reze-engine 0.64.0 → 0.66.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/engine.d.ts +300 -94
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +1628 -787
- package/dist/graph/compile.d.ts.map +1 -1
- package/dist/graph/compile.js +5 -0
- package/dist/graph/presets/body.d.ts.map +1 -1
- package/dist/graph/presets/body.js +26 -24
- package/dist/graph/presets/cloth_rough.js +8 -8
- package/dist/graph/presets/cloth_smooth.js +8 -8
- package/dist/graph/presets/default.js +4 -4
- package/dist/graph/presets/eye.js +10 -10
- package/dist/graph/presets/face.d.ts.map +1 -1
- package/dist/graph/presets/face.js +28 -26
- package/dist/graph/presets/hair.js +6 -6
- package/dist/graph/presets/metal.js +8 -8
- package/dist/graph/presets/stockings.d.ts.map +1 -1
- package/dist/graph/presets/stockings.js +4 -11
- package/dist/graph/presets/unlit.d.ts.map +1 -1
- package/dist/graph/presets/unlit.js +9 -13
- package/dist/graph/registry.d.ts.map +1 -1
- package/dist/graph/registry.js +128 -157
- package/dist/graph/render-class.d.ts +5 -2
- package/dist/graph/render-class.d.ts.map +1 -1
- package/dist/graph/slots.d.ts.map +1 -1
- package/dist/graph/slots.js +12 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/model.d.ts +23 -1
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +41 -1
- package/dist/outline-normals.d.ts +12 -0
- package/dist/outline-normals.d.ts.map +1 -0
- package/dist/outline-normals.js +100 -0
- package/dist/pmx-loader.d.ts +7 -0
- package/dist/pmx-loader.d.ts.map +1 -1
- package/dist/pmx-loader.js +17 -3
- package/dist/shaders/anchor-table.d.ts +11 -0
- package/dist/shaders/anchor-table.d.ts.map +1 -1
- package/dist/shaders/anchor-table.js +9 -3
- package/dist/shaders/directives.d.ts +42 -5
- package/dist/shaders/directives.d.ts.map +1 -1
- package/dist/shaders/directives.js +51 -4
- package/dist/shaders/lights.d.ts +11 -7
- package/dist/shaders/lights.d.ts.map +1 -1
- package/dist/shaders/lights.js +315 -271
- package/dist/shaders/materials/common.d.ts.map +1 -1
- package/dist/shaders/materials/common.js +30 -5
- package/dist/shaders/materials/nodes.d.ts +1 -1
- package/dist/shaders/materials/nodes.d.ts.map +1 -1
- package/dist/shaders/materials/nodes.js +191 -271
- package/dist/shaders/passes/bloom.d.ts +4 -3
- package/dist/shaders/passes/bloom.d.ts.map +1 -1
- package/dist/shaders/passes/bloom.js +58 -87
- package/dist/shaders/passes/composite.d.ts +1 -1
- package/dist/shaders/passes/composite.d.ts.map +1 -1
- package/dist/shaders/passes/composite.js +121 -77
- package/dist/shaders/passes/ground.js +1 -1
- package/dist/shaders/passes/mirror.d.ts +18 -12
- package/dist/shaders/passes/mirror.d.ts.map +1 -1
- package/dist/shaders/passes/mirror.js +59 -13
- package/dist/shaders/passes/outline.d.ts.map +1 -1
- package/dist/shaders/passes/outline.js +71 -14
- package/dist/shaders/passes/particles.d.ts.map +1 -1
- package/dist/shaders/passes/particles.js +9 -3
- package/dist/shaders/passes/probe.d.ts +45 -0
- package/dist/shaders/passes/probe.d.ts.map +1 -0
- package/dist/shaders/passes/probe.js +230 -0
- package/dist/shaders/passes/scene-contract.d.ts +13 -0
- package/dist/shaders/passes/scene-contract.d.ts.map +1 -1
- package/dist/shaders/passes/scene-contract.js +4 -0
- package/dist/shaders/scene-light-api.d.ts.map +1 -1
- package/dist/shaders/scene-light-api.js +1 -0
- package/dist/unity/globals.d.ts +7 -0
- package/dist/unity/globals.d.ts.map +1 -1
- package/dist/unity/globals.js +4 -3
- package/dist/unity/host.d.ts +18 -0
- package/dist/unity/host.d.ts.map +1 -1
- package/dist/unity/host.js +144 -70
- package/dist/unity/looks.d.ts +47 -0
- package/dist/unity/looks.d.ts.map +1 -1
- package/dist/unity/looks.js +150 -6
- package/dist/unity/skin.d.ts.map +1 -1
- package/dist/unity/skin.js +5 -2
- package/dist/unity/stage.d.ts +24 -0
- package/dist/unity/stage.d.ts.map +1 -1
- package/dist/unity/stage.js +59 -7
- package/package.json +1 -1
- package/src/engine.ts +2010 -1033
- package/src/graph/compile.ts +4 -0
- package/src/graph/presets/body.ts +26 -24
- package/src/graph/presets/cloth_rough.ts +8 -8
- package/src/graph/presets/cloth_smooth.ts +8 -8
- package/src/graph/presets/default.ts +4 -4
- package/src/graph/presets/eye.ts +10 -10
- package/src/graph/presets/face.ts +28 -26
- package/src/graph/presets/hair.ts +6 -6
- package/src/graph/presets/metal.ts +8 -8
- package/src/graph/presets/stockings.ts +4 -11
- package/src/graph/presets/unlit.ts +9 -13
- package/src/graph/registry.ts +133 -158
- package/src/graph/render-class.ts +5 -2
- package/src/graph/slots.ts +12 -2
- package/src/index.ts +1 -0
- package/src/model.ts +50 -1
- package/src/outline-normals.ts +110 -0
- package/src/pmx-loader.ts +18 -3
- package/src/shaders/anchor-table.ts +15 -3
- package/src/shaders/directives.ts +88 -6
- package/src/shaders/lights.ts +464 -415
- package/src/shaders/materials/common.ts +30 -5
- package/src/shaders/materials/nodes.ts +191 -271
- package/src/shaders/passes/bloom.ts +59 -87
- package/src/shaders/passes/composite.ts +121 -77
- package/src/shaders/passes/ground.ts +1 -1
- package/src/shaders/passes/mirror.ts +60 -13
- package/src/shaders/passes/outline.ts +71 -14
- package/src/shaders/passes/particles.ts +9 -3
- package/src/shaders/passes/probe.ts +240 -0
- package/src/shaders/passes/scene-contract.ts +17 -0
- package/src/shaders/scene-light-api.ts +1 -0
- package/src/unity/globals.ts +7 -3
- package/src/unity/host.ts +93 -20
- package/src/unity/looks.ts +182 -9
- package/src/unity/skin.ts +5 -2
- package/src/unity/stage.ts +66 -7
- package/dist/physics-debug.d.ts +0 -30
- package/dist/physics-debug.d.ts.map +0 -1
- package/dist/physics-debug.js +0 -526
- package/dist/shaders/agx-lut.d.ts +0 -11
- package/dist/shaders/agx-lut.d.ts.map +0 -1
- package/dist/shaders/agx-lut.js +0 -29
- package/dist/shaders/dfg_lut.d.ts +0 -3
- package/dist/shaders/dfg_lut.d.ts.map +0 -1
- package/dist/shaders/dfg_lut.js +0 -129
- package/dist/shaders/ltc_mag_lut.d.ts +0 -3
- package/dist/shaders/ltc_mag_lut.d.ts.map +0 -1
- package/dist/shaders/ltc_mag_lut.js +0 -1033
- package/dist/shaders/materials/body.d.ts +0 -2
- package/dist/shaders/materials/body.d.ts.map +0 -1
- package/dist/shaders/materials/body.js +0 -95
- package/dist/shaders/materials/cloth_rough.d.ts +0 -2
- package/dist/shaders/materials/cloth_rough.d.ts.map +0 -1
- package/dist/shaders/materials/cloth_rough.js +0 -69
- package/dist/shaders/materials/cloth_smooth.d.ts +0 -2
- package/dist/shaders/materials/cloth_smooth.d.ts.map +0 -1
- package/dist/shaders/materials/cloth_smooth.js +0 -61
- package/dist/shaders/materials/default.d.ts +0 -2
- package/dist/shaders/materials/default.d.ts.map +0 -1
- package/dist/shaders/materials/default.js +0 -43
- package/dist/shaders/materials/eye.d.ts +0 -2
- package/dist/shaders/materials/eye.d.ts.map +0 -1
- package/dist/shaders/materials/eye.js +0 -60
- package/dist/shaders/materials/face.d.ts +0 -2
- package/dist/shaders/materials/face.d.ts.map +0 -1
- package/dist/shaders/materials/face.js +0 -95
- package/dist/shaders/materials/hair.d.ts +0 -2
- package/dist/shaders/materials/hair.d.ts.map +0 -1
- package/dist/shaders/materials/hair.js +0 -90
- package/dist/shaders/materials/metal.d.ts +0 -2
- package/dist/shaders/materials/metal.d.ts.map +0 -1
- package/dist/shaders/materials/metal.js +0 -77
- package/dist/shaders/materials/mmd_classic.d.ts +0 -2
- package/dist/shaders/materials/mmd_classic.d.ts.map +0 -1
- package/dist/shaders/materials/mmd_classic.js +0 -66
- package/dist/shaders/materials/stockings.d.ts +0 -2
- package/dist/shaders/materials/stockings.d.ts.map +0 -1
- package/dist/shaders/materials/stockings.js +0 -122
- package/dist/shaders/passes/physics-debug.d.ts +0 -2
- package/dist/shaders/passes/physics-debug.d.ts.map +0 -1
- package/dist/shaders/passes/physics-debug.js +0 -69
- package/src/shaders/agx-lut.ts +0 -30
- package/src/shaders/dfg_lut.ts +0 -131
- package/src/shaders/ltc_mag_lut.ts +0 -1035
package/src/unity/looks.ts
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
// and the transparent queue in the engine's transparent phase. Shadows are the
|
|
16
16
|
// engine's: a native material still casts through its pass.
|
|
17
17
|
|
|
18
|
-
import { NativeHost, type NativeShader, type NativeStream, type NativeValue, type ValueSource } from "./host"
|
|
18
|
+
import { NativeHost, sameValue, type NativeShader, type NativeStream, type NativeValue, type ValueSource } from "./host"
|
|
19
19
|
import type { PassState } from "./state"
|
|
20
20
|
import { UNITY_SKIN_WGSL, tangentsFor } from "./skin"
|
|
21
21
|
import { characterBlock, type CharacterRig } from "./character"
|
|
@@ -28,6 +28,19 @@ export type NativeTexture = {
|
|
|
28
28
|
data: Uint8Array
|
|
29
29
|
/** Colour (sRGB) or data (linear) — how the shader expects to read it. */
|
|
30
30
|
srgb: boolean
|
|
31
|
+
/** Unity's wrap mode as the game imported it (Repeat, Clamp, Mirror,
|
|
32
|
+
* MirrorOnce); repeating when absent. A clamped mask sampled past its edge
|
|
33
|
+
* reads its border, not the far side. */
|
|
34
|
+
wrap?: string
|
|
35
|
+
/** Unity's filter mode (Point, Bilinear, Trilinear); bilinear when absent. */
|
|
36
|
+
filter?: string
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const WRAP: Record<string, GPUAddressMode> = {
|
|
40
|
+
Repeat: "repeat",
|
|
41
|
+
Clamp: "clamp-to-edge",
|
|
42
|
+
Mirror: "mirror-repeat",
|
|
43
|
+
MirrorOnce: "mirror-repeat",
|
|
31
44
|
}
|
|
32
45
|
|
|
33
46
|
export type NativeMaterialSpec = {
|
|
@@ -48,6 +61,12 @@ export type NativeLook = {
|
|
|
48
61
|
textures: Record<string, NativeTexture>
|
|
49
62
|
materials: NativeMaterialSpec[]
|
|
50
63
|
rig?: CharacterRig
|
|
64
|
+
/** The game vertex streams the model's PMX carries, by semantic: the
|
|
65
|
+
* additional UV channel (1–4) that holds each, four floats a vertex, keyed
|
|
66
|
+
* over time by that channel's UV morphs (PMX types 4–7) — a particle's
|
|
67
|
+
* colour over its life on a mesh's own vertex colours. A stream named here
|
|
68
|
+
* reads that channel; any other reads as Unity binds a missing one. */
|
|
69
|
+
streams?: Record<string, number>
|
|
51
70
|
}
|
|
52
71
|
|
|
53
72
|
/** What the engine lends for one model. */
|
|
@@ -72,12 +91,30 @@ export type NativeModel = {
|
|
|
72
91
|
headRest: [number, number, number]
|
|
73
92
|
/** Its rendering-layer bits, for a look without a rig. */
|
|
74
93
|
layers: number
|
|
94
|
+
/** A PMX additional UV channel (1–4), four floats a vertex, or null. */
|
|
95
|
+
additionalUv: (channel: number) => Float32Array | null
|
|
96
|
+
/** Its morphs, in the order of morphWeights. */
|
|
97
|
+
morphs: readonly { type: number; uvOffsets?: { vertexIndex: number; offset: [number, number, number, number] }[] }[]
|
|
98
|
+
/** The current effective (group-resolved, clamped) morph weights. */
|
|
99
|
+
morphWeights: () => Float32Array
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** A vertex stream out of an additional UV channel: its rest values, the
|
|
103
|
+
* channel's morphs, and the weights it was last built at. */
|
|
104
|
+
type CarriedStream = {
|
|
105
|
+
buffer: GPUBuffer
|
|
106
|
+
base: Float32Array
|
|
107
|
+
data: Float32Array
|
|
108
|
+
morphs: { index: number; offsets: { vertexIndex: number; offset: [number, number, number, number] }[] }[]
|
|
109
|
+
weights: Float32Array
|
|
75
110
|
}
|
|
76
111
|
|
|
77
112
|
type Install = {
|
|
78
113
|
model: NativeModel
|
|
79
114
|
look: NativeLook
|
|
80
115
|
views: Map<string, GPUTextureView>
|
|
116
|
+
/** Per look texture: its sampler, as the game imported the texture. */
|
|
117
|
+
samplers: Map<string, GPUSampler>
|
|
81
118
|
textures: GPUTexture[]
|
|
82
119
|
pos: GPUBuffer
|
|
83
120
|
nrm: GPUBuffer
|
|
@@ -85,9 +122,12 @@ type Install = {
|
|
|
85
122
|
restTan: GPUBuffer
|
|
86
123
|
params: GPUBuffer
|
|
87
124
|
skinBind: GPUBindGroup
|
|
88
|
-
/** Per draw of the model: the spec that dresses it,
|
|
89
|
-
|
|
125
|
+
/** Per draw of the model: the spec that dresses it, and the values set on
|
|
126
|
+
* that material since (setUniforms), over the spec's. */
|
|
127
|
+
dressed: { draw: NativeModel["draws"][number]; spec: NativeMaterialSpec; values: Record<string, NativeValue> }[]
|
|
90
128
|
block: Record<string, NativeValue>
|
|
129
|
+
/** The look's streams (NativeLook.streams), by semantic. */
|
|
130
|
+
carried: Map<string, CarriedStream>
|
|
91
131
|
}
|
|
92
132
|
|
|
93
133
|
const OPAQUE_MODES = ["ALWAYS", "FORWARDBASE"]
|
|
@@ -97,6 +137,8 @@ const OVERRIDE_MODES = ["OVERRIDE1", "OVERRIDE2", "OVERRIDE3"]
|
|
|
97
137
|
export class NativeLooks {
|
|
98
138
|
readonly host: NativeHost
|
|
99
139
|
private installs = new Map<string, Install>()
|
|
140
|
+
/** Per model: its passes' pipelines compiling (see install). */
|
|
141
|
+
private warming = new Map<string, Promise<void>>()
|
|
100
142
|
private skinPipeline: GPUComputePipeline
|
|
101
143
|
private zero: GPUBuffer
|
|
102
144
|
private white: GPUBuffer
|
|
@@ -139,10 +181,38 @@ export class NativeLooks {
|
|
|
139
181
|
return this.installs.size
|
|
140
182
|
}
|
|
141
183
|
|
|
184
|
+
private samplerCache = new Map<string, GPUSampler>()
|
|
185
|
+
|
|
186
|
+
/** A texture's sampler: its wrap and filter, shared by every texture alike. */
|
|
187
|
+
private sampler(t: NativeTexture): GPUSampler {
|
|
188
|
+
const wrap = WRAP[t.wrap ?? "Repeat"] ?? "repeat"
|
|
189
|
+
const filter: GPUFilterMode = t.filter === "Point" ? "nearest" : "linear"
|
|
190
|
+
const key = `${wrap}|${filter}`
|
|
191
|
+
let s = this.samplerCache.get(key)
|
|
192
|
+
if (!s) {
|
|
193
|
+
s = this.device.createSampler({
|
|
194
|
+
label: `native look sampler ${key}`,
|
|
195
|
+
addressModeU: wrap,
|
|
196
|
+
addressModeV: wrap,
|
|
197
|
+
magFilter: filter,
|
|
198
|
+
minFilter: filter,
|
|
199
|
+
mipmapFilter: filter,
|
|
200
|
+
})
|
|
201
|
+
this.samplerCache.set(key, s)
|
|
202
|
+
}
|
|
203
|
+
return s
|
|
204
|
+
}
|
|
205
|
+
|
|
142
206
|
has(model: string): boolean {
|
|
143
207
|
return this.installs.has(model)
|
|
144
208
|
}
|
|
145
209
|
|
|
210
|
+
/** Resolves once every pass of the model's look has its pipeline — until
|
|
211
|
+
* then those draws sit out (NativeHost never compiles at a draw). */
|
|
212
|
+
ready(model: string): Promise<void> {
|
|
213
|
+
return this.warming.get(model) ?? Promise.resolve()
|
|
214
|
+
}
|
|
215
|
+
|
|
146
216
|
/** Is this model's material drawn by its native look? */
|
|
147
217
|
dresses(model: string, material: string): boolean {
|
|
148
218
|
const i = this.installs.get(model)
|
|
@@ -154,8 +224,10 @@ export class NativeLooks {
|
|
|
154
224
|
const d = this.device
|
|
155
225
|
for (const s of look.shaders) this.host.register(s)
|
|
156
226
|
const views = new Map<string, GPUTextureView>()
|
|
227
|
+
const samplers = new Map<string, GPUSampler>()
|
|
157
228
|
const textures: GPUTexture[] = []
|
|
158
229
|
for (const [key, t] of Object.entries(look.textures)) {
|
|
230
|
+
if (t.wrap || t.filter) samplers.set(key, this.sampler(t))
|
|
159
231
|
const tex = d.createTexture({
|
|
160
232
|
label: `${model.name}: ${key}`,
|
|
161
233
|
size: [t.width, t.height],
|
|
@@ -203,12 +275,27 @@ export class NativeLooks {
|
|
|
203
275
|
const dressed: Install["dressed"] = []
|
|
204
276
|
for (const draw of model.draws) {
|
|
205
277
|
const spec = look.materials.find((m) => m.materials.includes(draw.materialName))
|
|
206
|
-
if (spec) dressed.push({ draw, spec })
|
|
278
|
+
if (spec) dressed.push({ draw, spec, values: {} })
|
|
207
279
|
}
|
|
208
|
-
|
|
280
|
+
const carried = new Map<string, CarriedStream>()
|
|
281
|
+
for (const [semantic, channel] of Object.entries(look.streams ?? {})) {
|
|
282
|
+
const base = model.additionalUv(channel)
|
|
283
|
+
if (!base || base.length < n * 4) continue
|
|
284
|
+
const morphs = model.morphs
|
|
285
|
+
.map((m, index) => ({ index, type: m.type, offsets: m.uvOffsets ?? [] }))
|
|
286
|
+
.filter((m) => m.type === 3 + channel && m.offsets.length)
|
|
287
|
+
.map(({ index, offsets }) => ({ index, offsets }))
|
|
288
|
+
const buffer = buf(`stream ${semantic}`, n * 4, GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST)
|
|
289
|
+
const data = new Float32Array(base.subarray(0, n * 4))
|
|
290
|
+
d.queue.writeBuffer(buffer, 0, data)
|
|
291
|
+
// NaN: the first prepare builds the stream whatever the weights are
|
|
292
|
+
carried.set(semantic, { buffer, base: data.slice(), data, morphs, weights: new Float32Array(morphs.length).fill(NaN) })
|
|
293
|
+
}
|
|
294
|
+
const install: Install = {
|
|
209
295
|
model,
|
|
210
296
|
look,
|
|
211
297
|
views,
|
|
298
|
+
samplers,
|
|
212
299
|
textures,
|
|
213
300
|
pos,
|
|
214
301
|
nrm,
|
|
@@ -218,7 +305,19 @@ export class NativeLooks {
|
|
|
218
305
|
skinBind,
|
|
219
306
|
dressed,
|
|
220
307
|
block: {},
|
|
221
|
-
|
|
308
|
+
carried,
|
|
309
|
+
}
|
|
310
|
+
this.installs.set(model.name, install)
|
|
311
|
+
// Every pass this look will draw, compiled now and side by side — the
|
|
312
|
+
// shader, its state and the streams are all known here.
|
|
313
|
+
const drawn = [...OPAQUE_MODES, ...CHARACTER_MODES, ...OVERRIDE_MODES]
|
|
314
|
+
const jobs: Promise<void>[] = []
|
|
315
|
+
for (const d of dressed)
|
|
316
|
+
for (const p of d.spec.passes) if (drawn.includes(p.lightMode)) jobs.push(this.host.warm(p.shader, p.state, this.streams(install, p.shader)))
|
|
317
|
+
this.warming.set(
|
|
318
|
+
model.name,
|
|
319
|
+
Promise.all(jobs).then(() => {}),
|
|
320
|
+
)
|
|
222
321
|
}
|
|
223
322
|
|
|
224
323
|
remove(name: string): void {
|
|
@@ -226,7 +325,7 @@ export class NativeLooks {
|
|
|
226
325
|
if (!i) return
|
|
227
326
|
this.installs.delete(name)
|
|
228
327
|
this.host.release(`${name}|`)
|
|
229
|
-
const bufs = [i.pos, i.nrm, i.tan, i.restTan, i.params]
|
|
328
|
+
const bufs = [i.pos, i.nrm, i.tan, i.restTan, i.params, ...[...i.carried.values()].map((c) => c.buffer)]
|
|
230
329
|
const texs = i.textures
|
|
231
330
|
// Freed once the GPU is done with the frames that may still name them.
|
|
232
331
|
void this.device.queue.onSubmittedWorkDone().then(() => {
|
|
@@ -259,12 +358,81 @@ export class NativeLooks {
|
|
|
259
358
|
: {
|
|
260
359
|
unity_RenderingLayer: new Uint32Array([i.model.layers >>> 0, 0, 0, 0]),
|
|
261
360
|
}
|
|
361
|
+
if (i.carried.size) this.keyStreams(i)
|
|
262
362
|
}
|
|
263
363
|
pass.end()
|
|
264
364
|
}
|
|
265
365
|
|
|
366
|
+
/** Each carried stream at the model's current morph weights: its rest values
|
|
367
|
+
* plus every one of its channel's morphs at its weight, rebuilt and uploaded
|
|
368
|
+
* only when one of those weights moved. */
|
|
369
|
+
private keyStreams(i: Install): void {
|
|
370
|
+
const weights = i.model.morphWeights()
|
|
371
|
+
for (const c of i.carried.values()) {
|
|
372
|
+
if (!c.morphs.length) continue
|
|
373
|
+
let moved = false
|
|
374
|
+
for (let k = 0; k < c.morphs.length; k++) {
|
|
375
|
+
const w = weights[c.morphs[k].index] ?? 0
|
|
376
|
+
if (w !== c.weights[k]) {
|
|
377
|
+
c.weights[k] = w
|
|
378
|
+
moved = true
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
if (!moved) continue
|
|
382
|
+
c.data.set(c.base)
|
|
383
|
+
for (let k = 0; k < c.morphs.length; k++) {
|
|
384
|
+
const w = c.weights[k]
|
|
385
|
+
if (!w) continue
|
|
386
|
+
for (const o of c.morphs[k].offsets) {
|
|
387
|
+
const at = o.vertexIndex * 4
|
|
388
|
+
if (at + 3 >= c.data.length) continue
|
|
389
|
+
c.data[at] += o.offset[0] * w
|
|
390
|
+
c.data[at + 1] += o.offset[1] * w
|
|
391
|
+
c.data[at + 2] += o.offset[2] * w
|
|
392
|
+
c.data[at + 3] += o.offset[3] * w
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
this.device.queue.writeBuffer(c.buffer, 0, c.data as Float32Array<ArrayBuffer>)
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Set some of one dressed material's values (its Unity material properties,
|
|
401
|
+
* as the look's `values` hold them) — what a game animates on a material
|
|
402
|
+
* over a take. Each value stands until set again; the look's own stand
|
|
403
|
+
* under it. Only names the material's spec carries are taken: they are the
|
|
404
|
+
* ones its draws' uniform blocks read per draw. A value equal to the one
|
|
405
|
+
* already set keeps that one's object, so the host, which refills a
|
|
406
|
+
* uniform member only when its value object changes, writes nothing for
|
|
407
|
+
* it. Returns whether the model wears a look that dresses this material.
|
|
408
|
+
*/
|
|
409
|
+
setUniforms(model: string, material: string, values: Record<string, NativeValue>): boolean {
|
|
410
|
+
const i = this.installs.get(model)
|
|
411
|
+
if (!i) return false
|
|
412
|
+
let found = false
|
|
413
|
+
for (const d of i.dressed) {
|
|
414
|
+
if (d.draw.materialName !== material) continue
|
|
415
|
+
found = true
|
|
416
|
+
for (const name in values) {
|
|
417
|
+
const v = values[name]
|
|
418
|
+
if (v === undefined || v === null || !(name in d.spec.values)) continue
|
|
419
|
+
const was = d.values[name]
|
|
420
|
+
if (was === undefined || !sameValue(was, v)) d.values[name] = v
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
return found
|
|
424
|
+
}
|
|
425
|
+
|
|
266
426
|
private streams(i: Install, shader: string): NativeStream[] {
|
|
267
427
|
return this.host.inputs(shader).map(({ semantic }) => {
|
|
428
|
+
const carried = i.carried.get(semantic)
|
|
429
|
+
if (carried)
|
|
430
|
+
return {
|
|
431
|
+
buffer: carried.buffer,
|
|
432
|
+
offset: 0,
|
|
433
|
+
stride: 16,
|
|
434
|
+
format: "float32x4" as const,
|
|
435
|
+
}
|
|
268
436
|
if (semantic === "POSITION")
|
|
269
437
|
return {
|
|
270
438
|
buffer: i.pos,
|
|
@@ -329,7 +497,11 @@ export class NativeLooks {
|
|
|
329
497
|
const textures: Record<string, GPUTextureView | undefined> = {
|
|
330
498
|
...this.frameTextures,
|
|
331
499
|
}
|
|
332
|
-
|
|
500
|
+
const samplers: Record<string, GPUSampler | undefined> = {}
|
|
501
|
+
for (const [slot, key] of Object.entries(d.spec.textures)) {
|
|
502
|
+
textures[slot] = key === "@diffuse" ? d.draw.diffuse : i.views.get(key)
|
|
503
|
+
samplers[slot] = i.samplers.get(key)
|
|
504
|
+
}
|
|
333
505
|
this.host.draw(pass, {
|
|
334
506
|
shader: p.shader,
|
|
335
507
|
state: p.state,
|
|
@@ -340,8 +512,9 @@ export class NativeLooks {
|
|
|
340
512
|
offset: d.draw.firstIndex * 4,
|
|
341
513
|
count: d.draw.count,
|
|
342
514
|
},
|
|
343
|
-
sources: [perDraw, i.block, d.spec.values, this.globals],
|
|
515
|
+
sources: [perDraw, i.block, d.values, d.spec.values, this.globals],
|
|
344
516
|
textures,
|
|
517
|
+
samplers,
|
|
345
518
|
key: `${i.model.name}|${d.draw.materialName}|${p.lightMode}|${p.shader}`,
|
|
346
519
|
pass: "main",
|
|
347
520
|
})
|
package/src/unity/skin.ts
CHANGED
|
@@ -78,10 +78,13 @@ export function tangentsFor(verts: Float32Array, indices: Uint32Array | Uint16Ar
|
|
|
78
78
|
const p = (v: number, k: number) => verts[v * 8 + k]
|
|
79
79
|
const e1 = [p(b, 0) - p(a, 0), p(b, 1) - p(a, 1), p(b, 2) - p(a, 2)]
|
|
80
80
|
const e2 = [p(c, 0) - p(a, 0), p(c, 1) - p(a, 1), p(c, 2) - p(a, 2)]
|
|
81
|
+
// v measured upward, as Unity builds tangent space: a PMX uv runs v down,
|
|
82
|
+
// and taken as it is the bitangent — the handedness in w — comes out
|
|
83
|
+
// reversed, which a game normal map reads as its green channel inverted.
|
|
81
84
|
const du1 = p(b, 6) - p(a, 6),
|
|
82
|
-
dv1 = p(
|
|
85
|
+
dv1 = p(a, 7) - p(b, 7)
|
|
83
86
|
const du2 = p(c, 6) - p(a, 6),
|
|
84
|
-
dv2 = p(
|
|
87
|
+
dv2 = p(a, 7) - p(c, 7)
|
|
85
88
|
const det = du1 * dv2 - du2 * dv1
|
|
86
89
|
if (Math.abs(det) < 1e-12) continue
|
|
87
90
|
const r = 1 / det
|
package/src/unity/stage.ts
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
import { NativeHost, type NativeShader, type NativeStream, type NativeValue, type ValueSource } from "./host"
|
|
22
22
|
import type { PassState } from "./state"
|
|
23
23
|
import { gameToEngine, invert4, mul4, scale4, flipY } from "./globals"
|
|
24
|
+
import { SHADOW_CASCADES } from "../shadow-cascades"
|
|
24
25
|
|
|
25
26
|
export type NativeStageMesh = {
|
|
26
27
|
id: string
|
|
@@ -78,6 +79,12 @@ export type NativeStageLights = {
|
|
|
78
79
|
direction: [number, number, number]
|
|
79
80
|
color: [number, number, number]
|
|
80
81
|
shadow: number
|
|
82
|
+
/** As the game's pipeline packed it, recorded: _MainLightColor and
|
|
83
|
+
* SimMainLightColor (linear, intensity in w), SimMainLightColorNoInt. */
|
|
84
|
+
unity?: { color: number[]; simColor: number[]; simColorNoInt: number[] }
|
|
85
|
+
/** The Light's shadowBias and shadowNormalBias, in shadow-map texels. */
|
|
86
|
+
shadowBias?: number
|
|
87
|
+
shadowNormalBias?: number
|
|
81
88
|
}
|
|
82
89
|
additional: {
|
|
83
90
|
position: [number, number, number]
|
|
@@ -147,6 +154,15 @@ export class NativeStage {
|
|
|
147
154
|
min: [number, number, number]
|
|
148
155
|
max: [number, number, number]
|
|
149
156
|
}
|
|
157
|
+
/**
|
|
158
|
+
* How far the stage reaches from the origin, in engine units: every
|
|
159
|
+
* renderer's box, casters or not. A game's sky is a dome in the stage
|
|
160
|
+
* (X317's reaches 1900 units out), and the camera's far plane has to reach it.
|
|
161
|
+
*/
|
|
162
|
+
get extent(): number {
|
|
163
|
+
return this.reach
|
|
164
|
+
}
|
|
165
|
+
private reach = 0
|
|
150
166
|
private buffers: GPUBuffer[] = []
|
|
151
167
|
private textures: GPUTexture[] = []
|
|
152
168
|
private opaque: Item[] = []
|
|
@@ -242,6 +258,10 @@ export class NativeStage {
|
|
|
242
258
|
}),
|
|
243
259
|
)
|
|
244
260
|
|
|
261
|
+
// Loaded means drawable: every pass's pipeline is compiled before this
|
|
262
|
+
// resolves, rather than one at a time in the frames after it.
|
|
263
|
+
const warming = st.warm(hosts, meshes)
|
|
264
|
+
|
|
245
265
|
const textures = new Map<string, Tex>()
|
|
246
266
|
await Promise.all(
|
|
247
267
|
pkg.textures.map(async (t) => {
|
|
@@ -255,6 +275,7 @@ export class NativeStage {
|
|
|
255
275
|
)
|
|
256
276
|
|
|
257
277
|
st.build(meshes, textures, tools.fallback)
|
|
278
|
+
await warming
|
|
258
279
|
return st
|
|
259
280
|
}
|
|
260
281
|
|
|
@@ -384,6 +405,7 @@ export class NativeStage {
|
|
|
384
405
|
ey = b.size[1] / 2,
|
|
385
406
|
ez = b.size[2] / 2
|
|
386
407
|
const half = [0, 1, 2].map((i) => (Math.abs(m[i]) * ex + Math.abs(m[4 + i]) * ey + Math.abs(m[8 + i]) * ez) * s)
|
|
408
|
+
this.reach = Math.max(this.reach, Math.hypot(center[0], center[1], center[2]) + Math.hypot(half[0], half[1], half[2]))
|
|
387
409
|
const world = Float32Array.from(m)
|
|
388
410
|
const det = m[0] * (m[5] * m[10] - m[9] * m[6]) - m[4] * (m[1] * m[10] - m[9] * m[2]) + m[8] * (m[1] * m[6] - m[5] * m[2])
|
|
389
411
|
const perDraw: ValueSource = {
|
|
@@ -429,8 +451,10 @@ export class NativeStage {
|
|
|
429
451
|
const samplers: Record<string, GPUSampler | undefined> = {
|
|
430
452
|
...globalSamplers,
|
|
431
453
|
}
|
|
432
|
-
// an empty slot reads what the shader declared it defaults to
|
|
433
|
-
|
|
454
|
+
// an empty slot reads what the shader declared it defaults to. A default
|
|
455
|
+
// with no name ("") is no picture at all — a cube's, usually — and is
|
|
456
|
+
// left to the host, which stands in by the binding's own kind.
|
|
457
|
+
for (const [slot, def] of Object.entries(mat.defaults ?? {})) if (def && fallback[def]) views[slot] = fallback[def]
|
|
434
458
|
for (const [slot, id] of [...Object.entries(mat.textures), ...Object.entries(r.textures)]) {
|
|
435
459
|
const t = textures.get(id)
|
|
436
460
|
if (!t) continue
|
|
@@ -459,6 +483,35 @@ export class NativeStage {
|
|
|
459
483
|
})
|
|
460
484
|
}
|
|
461
485
|
|
|
486
|
+
/**
|
|
487
|
+
* Every pass's pipeline, compiled before the stage reports loaded (see
|
|
488
|
+
* NativeHost.warm) — side by side, and never at the first draw. Needs only
|
|
489
|
+
* the meshes' stream layouts, so it runs while the pictures decode. The
|
|
490
|
+
* passes are the ones build() keeps: casters that cast, and the main modes.
|
|
491
|
+
*/
|
|
492
|
+
private warm(
|
|
493
|
+
hosts: { scene: NativeHost; shadow: NativeHost },
|
|
494
|
+
meshes: Map<string, { info: NativeStageMesh; buffer: GPUBuffer }>,
|
|
495
|
+
): Promise<void> {
|
|
496
|
+
const jobs: Promise<void>[] = []
|
|
497
|
+
const mats = new Map(this.pkg.materials.map((m) => [m.id, m]))
|
|
498
|
+
for (const r of this.pkg.renderers) {
|
|
499
|
+
const mesh = meshes.get(r.mesh)
|
|
500
|
+
if (!mesh) continue
|
|
501
|
+
r.materials.forEach((mid, sub) => {
|
|
502
|
+
const mat = mid ? mats.get(mid) : undefined
|
|
503
|
+
if (!mat || sub >= mesh.info.submeshes.length) return
|
|
504
|
+
for (const pass of mat.passes) {
|
|
505
|
+
const caster = pass.lightMode === "SHADOWCASTER"
|
|
506
|
+
if (caster ? !r.castShadows : !MAIN_MODES.includes(pass.lightMode)) continue
|
|
507
|
+
const host = caster ? hosts.shadow : hosts.scene
|
|
508
|
+
jobs.push(host.warm(pass.shader, pass.state, this.streams(host, { mesh, pass } as Item)))
|
|
509
|
+
}
|
|
510
|
+
})
|
|
511
|
+
}
|
|
512
|
+
return Promise.all(jobs).then(() => {})
|
|
513
|
+
}
|
|
514
|
+
|
|
462
515
|
private streams(host: NativeHost, it: Item): NativeStream[] {
|
|
463
516
|
const info = it.mesh.info
|
|
464
517
|
return host.inputs(it.pass.shader).map(({ semantic }) => {
|
|
@@ -514,18 +567,24 @@ export class NativeStage {
|
|
|
514
567
|
engineScale: number,
|
|
515
568
|
): void {
|
|
516
569
|
const vp = flipY(mul4(viewProj, gameToEngine(engineScale)))
|
|
517
|
-
// ShadowUtils.GetShadowBias as the game
|
|
518
|
-
//
|
|
519
|
-
// game units over its resolution
|
|
570
|
+
// ShadowUtils.GetShadowBias as the game sets it: (texel x the light's
|
|
571
|
+
// shadowBias, -texel x its shadowNormalBias), a texel being this tile's
|
|
572
|
+
// width in game units over its resolution. The stage's casters read it as
|
|
573
|
+
// _ShadowBias (Replica's CascadeShadowPass); the character's DrawShadowPass
|
|
574
|
+
// names it sim_ShadowBias. A package that predates the recorded biases
|
|
575
|
+
// takes half a texel of each.
|
|
520
576
|
const rowLen = Math.hypot(vp[0], vp[4], vp[8])
|
|
521
|
-
const texel = rowLen > 0 ? 2 / rowLen /
|
|
577
|
+
const texel = rowLen > 0 ? 2 / rowLen / SHADOW_CASCADES[cascade].mapSize : 0
|
|
578
|
+
const main = this.pkg.lights.main
|
|
579
|
+
const bias = [texel * (main.shadowBias ?? 0.5), -texel * (main.shadowNormalBias ?? 0.5), 0, 0]
|
|
522
580
|
const g: Record<string, NativeValue> = {
|
|
523
581
|
...globals,
|
|
524
582
|
unity_MatrixVP: vp,
|
|
525
583
|
unity_MatrixV: scale4(1),
|
|
526
584
|
unity_MatrixP: vp,
|
|
527
585
|
glstate_matrix_projection: vp,
|
|
528
|
-
|
|
586
|
+
_ShadowBias: bias,
|
|
587
|
+
sim_ShadowBias: bias,
|
|
529
588
|
}
|
|
530
589
|
for (const it of this.casters) this.draw(pass, host, it, g, {}, `|c${cascade}`)
|
|
531
590
|
}
|
package/dist/physics-debug.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import type { RezePhysics } from "./physics";
|
|
2
|
-
export declare class PhysicsDebugRenderer {
|
|
3
|
-
private device;
|
|
4
|
-
private bindGroup;
|
|
5
|
-
private wirePipelineSphere;
|
|
6
|
-
private wirePipelineBox;
|
|
7
|
-
private wirePipelineCapsule;
|
|
8
|
-
private wireSphereBuffer;
|
|
9
|
-
private wireBoxBuffer;
|
|
10
|
-
private wireCapsuleBuffer;
|
|
11
|
-
private wireSphereCount;
|
|
12
|
-
private wireBoxCount;
|
|
13
|
-
private wireCapsuleCount;
|
|
14
|
-
private solidPipelineSphere;
|
|
15
|
-
private solidPipelineBox;
|
|
16
|
-
private solidPipelineCapsule;
|
|
17
|
-
private solidSphereBuffer;
|
|
18
|
-
private solidBoxBuffer;
|
|
19
|
-
private solidCapsuleBuffer;
|
|
20
|
-
private solidSphereCount;
|
|
21
|
-
private solidBoxCount;
|
|
22
|
-
private solidCapsuleCount;
|
|
23
|
-
private instanceBuffer;
|
|
24
|
-
private instanceData;
|
|
25
|
-
private instanceCapacity;
|
|
26
|
-
constructor(device: GPUDevice, cameraUniformBuffer: GPUBuffer, presentationFormat: GPUTextureFormat);
|
|
27
|
-
render(pass: GPURenderPassEncoder, physics: RezePhysics): void;
|
|
28
|
-
destroy(): void;
|
|
29
|
-
}
|
|
30
|
-
//# sourceMappingURL=physics-debug.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"physics-debug.d.ts","sourceRoot":"","sources":["../src/physics-debug.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAmB5C,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,SAAS,CAAc;IAG/B,OAAO,CAAC,kBAAkB,CAAmB;IAC7C,OAAO,CAAC,eAAe,CAAmB;IAC1C,OAAO,CAAC,mBAAmB,CAAmB;IAC9C,OAAO,CAAC,gBAAgB,CAAW;IACnC,OAAO,CAAC,aAAa,CAAW;IAChC,OAAO,CAAC,iBAAiB,CAAW;IACpC,OAAO,CAAC,eAAe,CAAQ;IAC/B,OAAO,CAAC,YAAY,CAAQ;IAC5B,OAAO,CAAC,gBAAgB,CAAQ;IAIhC,OAAO,CAAC,mBAAmB,CAAmB;IAC9C,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,oBAAoB,CAAmB;IAC/C,OAAO,CAAC,iBAAiB,CAAW;IACpC,OAAO,CAAC,cAAc,CAAW;IACjC,OAAO,CAAC,kBAAkB,CAAW;IACrC,OAAO,CAAC,gBAAgB,CAAQ;IAChC,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,iBAAiB,CAAQ;IAEjC,OAAO,CAAC,cAAc,CAAW;IACjC,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,gBAAgB,CAAQ;gBAG9B,MAAM,EAAE,SAAS,EACjB,mBAAmB,EAAE,SAAS,EAC9B,kBAAkB,EAAE,gBAAgB;IA2HtC,MAAM,CAAC,IAAI,EAAE,oBAAoB,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI;IAmI9D,OAAO,IAAI,IAAI;CAShB"}
|