Skip to content

Commit

Permalink
merge: shadow ui improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
chase-moskal committed Apr 23, 2024
2 parents 4ec7258 + 7f36b34 commit 2242137
Show file tree
Hide file tree
Showing 24 changed files with 530 additions and 262 deletions.
206 changes: 110 additions & 96 deletions package-lock.json

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@
},
"dependencies": {
"@benev/slate": "^0.1.1",
"@benev/toolbox": "^0.6.0-3",
"@benev/toolbox": "^0.6.0-4",
"@dimforge/rapier3d": "^0.12.0",
"@dimforge/rapier3d-compat": "^0.12.0",
"es-module-shims": "^1.9.0",
"lit": "^3.1.2",
"lit": "^3.1.3",
"shelljs": "^0.8.5",
"simplex-noise": "^4.0.1"
},
"peerDependencies": {
"@babylonjs/core": "^7.2.1",
"@babylonjs/loaders": "^7.2.1"
"@babylonjs/core": "^7.3.2",
"@babylonjs/loaders": "^7.3.2"
},
"devDependencies": {
"@benev/batchimage": "^0.0.1",
Expand All @@ -50,8 +50,8 @@
"mkdirp": "^3.0.1",
"npm-run-all": "^4.1.5",
"rimraf": "^5.0.5",
"rollup": "^4.14.2",
"terser": "^5.30.3",
"rollup": "^4.16.3",
"terser": "^5.30.4",
"typescript": "^5.4.5"
},
"keywords": [
Expand Down
15 changes: 4 additions & 11 deletions s/dom/elements/benev-humanoid/menus/effects.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@

import {clone, css, html} from "@benev/slate"
import {Bestorage} from "@benev/toolbox/x/ui/theater/views/effects-panel/parts/bestorage.js"
import {EffectsPanel, EffectsPanelData, defaultEffectsData} from "@benev/toolbox"
import {css, html} from "@benev/slate"
import {EffectsPanel, EffectsPanelData} from "@benev/toolbox"

import {Game} from "../../../../types.js"
import {nexus} from "../../../../nexus.js"
Expand All @@ -16,15 +15,9 @@ export const EffectsMenu = nexus.shadow_view(use => (game: Game) => {
use.name("effects-menu")
use.styles(css``)

const bestorage = use.once(() => new Bestorage<HuBestorageData>({
...defaultEffectsData(),
resolution: game.stage.porthole.resolution * 100,
shadows: clone(game.ui.shadows),
}))

return EffectsPanel(
[game.stage, bestorage],
{content: html`${ShadowsPanel([game, bestorage])}`},
[game.stage, game.bestorage],
{content: html`${ShadowsPanel([game, game.bestorage])}`},
)
})

217 changes: 171 additions & 46 deletions s/dom/elements/benev-humanoid/menus/panels/shadows.ts
Original file line number Diff line number Diff line change
@@ -1,73 +1,198 @@

import {clone, css, html, reactor} from "@benev/slate"
import {NuiCheckbox, NuiRange, Bestorage} from "@benev/toolbox"
import {NuiCheckbox, NuiRange, Bestorage, NuiSelect} from "@benev/toolbox"
import {ShadowGenerator} from "@babylonjs/core/Lights/Shadows/shadowGenerator.js"

import {Game} from "../../../../../types.js"
import {nexus} from "../../../../../nexus.js"
import {HuBestorageData} from "../effects.js"
import {Ui} from "../../../../../models/ui/ui.js"
import {Granularity} from "../utils/granularity.js"

const shadowBooleans: (keyof ShadowGenerator)[] = [
"usePoissonSampling",
"useExponentialShadowMap",
"useBlurExponentialShadowMap",
"useContactHardeningShadow",
"enableSoftTransparentShadow",
"useCloseExponentialShadowMap",
"useKernelBlur",
]

const shadowNumber: [keyof ShadowGenerator, Granularity][] = [
["mapSize", Granularity.square],
["blurScale", Granularity.medium],
["blurKernel", Granularity.medium],
["blurBoxOffset", Granularity.medium],
["bias", Granularity.ultrafine],
["darkness", Granularity.fine],
["depthScale", Granularity.coarse],
]
type Primitive = number | boolean

type InputGroup<G extends Record<string, Primitive>> = {
[K in keyof G]: (
G[K] extends number ? [typeof Number, Granularity] :
G[K] extends boolean ? [typeof Boolean] :
never
)
}

const lightInputs: InputGroup<Ui["shadows"]["light"]> = {
intensity: [Number, Granularity.coarse],
autoUpdateExtends: [Boolean],
autoCalcShadowZBounds: [Boolean],
shadowMinZ: [Number, Granularity.bigly],
shadowMaxZ: [Number, Granularity.bigly],
shadowOrthoScale: [Number, Granularity.fine],
shadowFrustumSize: [Number, Granularity.fine],
}

const generatorInputs: InputGroup<Ui["shadows"]["generator"]> = {
enableSoftTransparentShadow: [Boolean],
useKernelBlur: [Boolean],
forceBackFacesOnly: [Boolean],
mapSize: [Number, Granularity.square],
blurScale: [Number, Granularity.medium],
blurKernel: [Number, Granularity.medium],
blurBoxOffset: [Number, Granularity.medium],
bias: [Number, Granularity.ultrafine],
darkness: [Number, Granularity.fine],
depthScale: [Number, Granularity.coarse],
frustumEdgeFalloff: [Number, Granularity.fine],
}

const cascadedInputs: InputGroup<Ui["shadows"]["cascaded"]> = {
enabled: [Boolean],
debug: [Boolean],
stabilizeCascades: [Boolean],
freezeShadowCastersBoundingInfo: [Boolean],
autoCalcDepthBounds: [Boolean],
numCascades: [Number, new Granularity(0, 10, 1)],
lambda: [Number, Granularity.fine],
cascadeBlendPercentage: [Number, Granularity.fine],
penumbraDarkness: [Number, Granularity.fine],
shadowMinZ: [Number, Granularity.bigly],
shadowMaxZ: [Number, Granularity.bigly],
}

function renderInputGroup<Data extends Record<string, Primitive>>(data: Data, group: InputGroup<Data>) {
return Object.entries(group).map(([key, spec]) => {
const [kind] = spec
const value = data[key] as any
const set = (x: any) => (data as any)[key] = x
if (kind === Boolean) {
return NuiCheckbox([{
label: key,
checked: value,
set: x => (data as any)[key] = x,
}])
}
else if (kind === Number) {
const granularity = spec[1]!
return NuiRange([{
...granularity,
label: key,
value,
set,
}])
}
else throw new Error("unknown group kind")
})
}

class Flags<N extends number, S extends string> {
strings: Map<N, S>
numbers: Map<S, N>
constructor(entries: [N, S][]) {
this.strings = new Map(entries)
this.numbers = new Map(entries.map(([number, string]) => [string, number]))
}
toString(number: N) { return this.strings.get(number)! }
toNumber(string: S) { return this.numbers.get(string)! }
}

type FQNumber = 0 | 1 | 2
type FQString = "low" | "medium" | "high"
const filteringQualityFlags = new Flags<FQNumber, FQString>([
[ShadowGenerator.QUALITY_LOW, "low"],
[ShadowGenerator.QUALITY_MEDIUM, "medium"],
[ShadowGenerator.QUALITY_HIGH, "high"],
])

type FNumber = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
type FString = "none" | "exponential" | "poisson" | "blurExponential" | "closeExponential" | "blurCloseExponential" | "pcf" | "pcss"
const filterFlags = new Flags<FNumber, FString>([
[ShadowGenerator.FILTER_NONE, "none"],
[ShadowGenerator.FILTER_EXPONENTIALSHADOWMAP, "exponential"],
[ShadowGenerator.FILTER_POISSONSAMPLING, "poisson"],
[ShadowGenerator.FILTER_BLUREXPONENTIALSHADOWMAP, "blurExponential"],
[ShadowGenerator.FILTER_CLOSEEXPONENTIALSHADOWMAP, "closeExponential"],
[ShadowGenerator.FILTER_BLURCLOSEEXPONENTIALSHADOWMAP, "blurCloseExponential"],
[ShadowGenerator.FILTER_PCF, "pcf"],
[ShadowGenerator.FILTER_PCSS, "pcss"],
])

export const ShadowsPanel = nexus.shadow_view(use => (game: Game, bestorage: Bestorage<HuBestorageData>) => {
use.name("shadows-panel")
use.styles(css``)
use.styles(css`
.panel {
> * + * { margin-top: 1em; }
> section {
padding: 1em;
background: #0002;
> * + * { display: block; margin-top: 0.6em; }
}
}
h2 { color: white; text-align: center; }
h3 { color: #89ff91; }
`)

const {shadows} = game.ui

use.mount(() => reactor.reaction(
() => clone(game.ui.shadows),
shadows => bestorage.data.shadows = shadows,
))

use.mount(() => bestorage.onJson(({shadows}) => {
game.ui.shadows.sunDistance = shadows.sunDistance
Object.assign(game.ui.shadows.generator, shadows.generator)
use.mount(() => bestorage.onJson(({shadows: shadowsJson}) => {
Object.assign(shadows.basics, shadowsJson.basics)
Object.assign(shadows.light, shadowsJson.light)
Object.assign(shadows.generator, shadowsJson.generator)
Object.assign(shadows.cascaded, shadowsJson.cascaded)
}))

const get = (key: any) => (game.ui.shadows.generator as any)[key]
const set = (key: any, value: any) => (game.ui.shadows.generator as any)[key] = value

return html`
<section>
<h3>shadow settings</h3>
<section class=panel>
<h2>shadows</h2>
${NuiRange([{
...Granularity.bigly,
label: "sunDistance",
value: game.ui.shadows.sunDistance,
set: x => game.ui.shadows.sunDistance = x,
}])}
<section>
<h3>basics</h3>
${NuiSelect([{
label: "filter",
options: [...filterFlags.strings.values()],
selected: filterFlags.toString(shadows.basics.filter as FNumber),
set: x => shadows.basics.filter = filterFlags.toNumber(x as FString),
}])}
${NuiSelect([{
label: "filteringQuality",
options: [...filteringQualityFlags.strings.values()],
selected: filteringQualityFlags.toString(shadows.basics.filteringQuality as FQNumber),
set: x => shadows.basics.filteringQuality = filteringQualityFlags.toNumber(x as FQString),
}])}
${NuiRange([{
...Granularity.bigly,
label: "sunDistance",
value: shadows.basics.sunDistance,
set: x => shadows.basics.sunDistance = x,
}])}
${NuiCheckbox([{
label: "grass_receives_shadows",
checked: shadows.basics.grass_receives_shadows,
set: x => shadows.basics.grass_receives_shadows = x,
}])}
${NuiCheckbox([{
label: "grass_casts_shadows",
checked: shadows.basics.grass_casts_shadows,
set: x => shadows.basics.grass_casts_shadows = x,
}])}
</section>
${shadowBooleans.map(key => NuiCheckbox([{
label: key,
checked: get(key),
set: x => set(key, x),
}]))}
<section>
<h3>light</h3>
${renderInputGroup(shadows.light, lightInputs)}
</section>
${shadowNumber.map(([key, granularity]) => NuiRange([{
...granularity,
label: key,
value: get(key),
set: x => set(key, x),
}]))}
<section>
<h3>generator</h3>
${renderInputGroup(shadows.generator, generatorInputs)}
</section>
<section>
<h3>cascaded</h3>
${renderInputGroup(shadows.cascaded, cascadedInputs)}
</section>
</section>
`
})
Expand Down
3 changes: 2 additions & 1 deletion s/dom/elements/benev-humanoid/menus/utils/granularity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ export class Granularity {
public max: number,
public step: number,
) {}
static ultrafine = new this(0, (1/1000), (1/1_000_000))
static ultrafine = new this(0, (1/1_000), (1/1_000_000))
static quitefine = new this(0, (1/10), (1/1_000_000))
static fine = new this(0, 1, (1/1_000))
static medium = new this(0, 10, (1/100))
static coarse = new this(0, 100, (1/10))
Expand Down
4 changes: 2 additions & 2 deletions s/ecs/components/hybrids/character/character.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@

import {Prop, babyloid, nametag} from "@benev/toolbox"

import {ReferenceWeapon, Weaponry} from "./types.js"
import {HybridComponent} from "../../../hub.js"
import {ReferenceWeapon, Weaponry} from "./types.js"
import {make_tracer_ensembles} from "../../../../models/tracing/ensembles.js"
import {ContainerInstance} from "../../../../models/glb/container_instance.js"
import {establish_anim_coordination} from "./choreography/establish_anim_coordination.js"
import {ContainerInstance} from "../../../../models/glb_post_processing/container_instance.js"
import {prepare_character_component_parts} from "./choreography/prepare_character_component_parts.js"

export class Character extends HybridComponent<{height: number}> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {HuRealm} from "../../../../../models/realm/realm.js"
import {setup_character_anims} from "./setup_character_anims.js"
import {AdjustmentAnims} from "../../../../../models/choreographer/types.js"
import {adjustment_anim_for_direction} from "./adjustment_anim_for_direction.js"
import {ContainerInstance} from "../../../../../models/glb_post_processing/container_instance.js"
import {ContainerInstance} from "../../../../../models/glb/container_instance.js"
import {calculate_adjustment_weight} from "../../../../../models/choreographer/utils/calculate_adjustment_weight.js"

export function establish_anim_coordination(realm: HuRealm, character: ContainerInstance, onMissingAnim: (name: string) => void) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import {Scene} from "@babylonjs/core/scene.js"
import {babyloid, label, quat, vec3} from "@benev/toolbox"
import {TransformNode} from "@babylonjs/core/Meshes/transformNode.js"
import {ContainerInstance} from "../../../../../models/glb_post_processing/container_instance.js"
import {ContainerInstance} from "../../../../../models/glb/container_instance.js"

export function prepare_character_component_parts(
scene: Scene,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@

import {BasedAnim} from "../../../../../models/choreographer/anims/based.js"
import {ManualAnim} from "../../../../../models/choreographer/anims/manual.js"
import {ContainerInstance} from "../../../../../models/glb/container_instance.js"
import {manifest_anims} from "../../../../../models/choreographer/utils/manifest_anims.js"
import {ManualAdditiveAnim} from "../../../../../models/choreographer/anims/manual_additive.js"
import {ContainerInstance} from "../../../../../models/glb_post_processing/container_instance.js"

export type CharacterAnims = ReturnType<typeof setup_character_anims>

Expand Down
13 changes: 0 additions & 13 deletions s/ecs/components/hybrids/level.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ export class Level extends HybridComponent<{level: HuLevel}> {
#spawn_level(promise: Promise<AssetContainer>, physics: boolean) {
return promise
.then(instance_level)
.then(setup_quality_optimizations(this.realm))
.then(setup_thin_instances)
.then(setup_level_accoutrements(this.realm, physics))
.then(this.#make_level_disposer)
Expand Down Expand Up @@ -138,18 +137,6 @@ async function instance_level(asset: AssetContainer) {

export type LevelStuff = ReturnType<ReturnType<typeof setup_level_accoutrements>>

function setup_quality_optimizations(realm: HuRealm) {
return (params: LevelInstance) => {
const {level} = params
if (realm.gameplan.quality === "potato") {
level.meshes
.filter(m => m.name.includes("grass"))
.forEach(m => m.dispose())
}
return params
}
}

function trace_paternity(meshes: Meshoid[]) {
const paternity = new Map<Mesh, InstancedMesh[]>()
for (const mesh of meshes) {
Expand Down
Loading

0 comments on commit 2242137

Please sign in to comment.