pelican-engine 0.0.0-stage → 0.3.1
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/AGENTS.md +147 -0
- package/LICENSE +22 -0
- package/README.md +129 -2
- package/distribution.json +197 -0
- package/docs/AI-WORKFLOW.md +517 -0
- package/docs/ARCHITECTURE.md +268 -0
- package/docs/CAPABILITIES.md +264 -0
- package/docs/DECISIONS.md +107 -0
- package/docs/M3-USAGE.md +192 -0
- package/docs/PELICAN-MIGRATION.md +38 -0
- package/docs/RENDER-BACKENDS.md +50 -0
- package/docs/ROADMAP.md +239 -0
- package/docs/THIRD-PARTY-NOTICES.md +151 -0
- package/docs/api/REFERENCE.md +1435 -0
- package/docs/api/index.json +1139 -0
- package/docs/npm/DISTRIBUTION.md +130 -0
- package/docs/npm/GAME-AUTHOR.md +147 -0
- package/engine.manifest.json +15 -0
- package/lib/assets/audio.js +67 -0
- package/lib/assets/errors.js +36 -0
- package/lib/assets/glb.js +277 -0
- package/lib/assets/index.js +53 -0
- package/lib/assets/jpeg.js +199 -0
- package/lib/assets/model.js +558 -0
- package/lib/assets/optimize.js +95 -0
- package/lib/assets/texture.js +187 -0
- package/lib/compiler/distribution.js +17 -0
- package/lib/compiler/extract.js +425 -0
- package/lib/compiler/graph.js +366 -0
- package/lib/compiler/index.js +574 -0
- package/lib/compiler/normalize.js +1194 -0
- package/lib/compiler/source-map.js +25 -0
- package/lib/compiler/types.js +2 -0
- package/lib/compiler/version.js +93 -0
- package/lib/experiments/simulation/index.js +2 -0
- package/lib/experiments/simulation/math.js +41 -0
- package/lib/experiments/simulation/probe.js +215 -0
- package/lib/experiments/simulation/scenes.js +192 -0
- package/lib/experiments/simulation/solver.js +346 -0
- package/lib/experiments/simulation/types.js +1 -0
- package/lib/experiments/world/adapters.js +30 -0
- package/lib/experiments/world/geometry.js +180 -0
- package/lib/experiments/world/index.js +2 -0
- package/lib/experiments/world/probe.js +288 -0
- package/lib/experiments/world/types.js +1 -0
- package/lib/experiments/world/world.js +599 -0
- package/lib/navigation/index.js +157 -0
- package/lib/physics/index.js +909 -0
- package/lib/protocol/index.js +92 -0
- package/lib/renderer/acceleration.js +609 -0
- package/lib/renderer/browser.js +2015 -0
- package/lib/renderer/bsdf.js +260 -0
- package/lib/renderer/checkpoint.js +88 -0
- package/lib/renderer/compute-executor.js +1034 -0
- package/lib/renderer/compute-texture-assets.js +49 -0
- package/lib/renderer/compute-view-contract.js +1 -0
- package/lib/renderer/denoiser.js +361 -0
- package/lib/renderer/dielectric.js +360 -0
- package/lib/renderer/embedded-image-pixels.js +368 -0
- package/lib/renderer/emissive-lights.js +67 -0
- package/lib/renderer/environment-importance.js +55 -0
- package/lib/renderer/environment.js +346 -0
- package/lib/renderer/gameplay.js +464 -0
- package/lib/renderer/geometry.js +103 -0
- package/lib/renderer/graph-expressions.js +485 -0
- package/lib/renderer/graph-tsl.js +141 -0
- package/lib/renderer/graph.js +214 -0
- package/lib/renderer/managed-texture-sampling.js +29 -0
- package/lib/renderer/material-graphs.js +297 -0
- package/lib/renderer/medium.js +348 -0
- package/lib/renderer/models.js +1053 -0
- package/lib/renderer/motion-shader.js +40 -0
- package/lib/renderer/path-shader.js +196 -0
- package/lib/renderer/pathtrace.js +324 -0
- package/lib/renderer/postprocess-contract.js +1 -0
- package/lib/renderer/postprocess.js +494 -0
- package/lib/renderer/render-buffers.js +132 -0
- package/lib/renderer/render-textures.js +155 -0
- package/lib/renderer/startup.js +50 -0
- package/lib/renderer/surface-capture.js +199 -0
- package/lib/renderer/surface-gpu.js +270 -0
- package/lib/renderer/surface-motion.js +84 -0
- package/lib/renderer/surface-ray-shader.js +91 -0
- package/lib/renderer/surface-shader.js +88 -0
- package/lib/renderer/surface-tracer.js +1720 -0
- package/lib/renderer/surface.js +1425 -0
- package/lib/renderer/temporal-filter.js +512 -0
- package/lib/renderer/texture-pixels.js +207 -0
- package/lib/renderer/traversal-nodes.js +54 -0
- package/lib/renderer/ui.js +446 -0
- package/lib/renderer/vertex-bounds.js +127 -0
- package/lib/renderer/vertex-contract.js +1 -0
- package/lib/renderer/vertex-graphs.js +197 -0
- package/lib/renderer/volume-shader.js +50 -0
- package/lib/runtime/compute-contract.js +1 -0
- package/lib/runtime/compute-service.js +674 -0
- package/lib/runtime/contracts.js +1 -0
- package/lib/runtime/error.js +37 -0
- package/lib/runtime/events.js +189 -0
- package/lib/runtime/game-services.js +772 -0
- package/lib/runtime/host.js +839 -0
- package/lib/runtime/material-parameters.js +145 -0
- package/lib/runtime/plugins.js +1 -0
- package/lib/runtime/postprocess-contract.js +1 -0
- package/lib/runtime/postprocess.js +189 -0
- package/lib/runtime/prefabs.js +13 -0
- package/lib/runtime/random.js +88 -0
- package/lib/runtime/render-buffer-contract.js +1 -0
- package/lib/runtime/render-buffers.js +243 -0
- package/lib/runtime/render-capabilities.js +17 -0
- package/lib/runtime/render-settings.js +249 -0
- package/lib/runtime/render-texture-contract.js +1 -0
- package/lib/runtime/render-textures.js +271 -0
- package/lib/runtime/resources.js +648 -0
- package/lib/runtime/scheduler.js +765 -0
- package/lib/runtime/storage.js +169 -0
- package/lib/runtime/world.js +594 -0
- package/lib/schema/index.js +24 -0
- package/lib/sdk/graph-values.js +16 -0
- package/lib/sdk/index.d.ts +800 -0
- package/lib/sdk/index.js +82 -0
- package/lib/tools/api-index.js +113 -0
- package/lib/tools/browser-session.js +89 -0
- package/lib/tools/cli.js +513 -0
- package/lib/tools/compress-dist.js +59 -0
- package/lib/tools/control-client.js +153 -0
- package/lib/tools/control-server.js +633 -0
- package/lib/tools/diagnostic-code.js +3 -0
- package/lib/tools/doctor.js +496 -0
- package/lib/tools/npm/browser-cli.js +6 -0
- package/lib/tools/npm/entry.js +40 -0
- package/lib/tools/npm/layout.js +195 -0
- package/lib/tools/setup.js +153 -0
- package/licenses/@dimforge/rapier2d-compat/LICENSE +201 -0
- package/licenses/@dimforge/rapier3d-compat/LICENSE +201 -0
- package/licenses/@gltf-transform/core/LICENSE.md +21 -0
- package/licenses/@gltf-transform/extensions/LICENSE.md +21 -0
- package/licenses/@gltf-transform/functions/LICENSE.md +21 -0
- package/licenses/@img/colour/LICENSE.md +82 -0
- package/licenses/@img/sharp-win32-x64/LICENSE +191 -0
- package/licenses/@oxc-project/types/LICENSE +22 -0
- package/licenses/@rolldown/pluginutils/LICENSE +21 -0
- package/licenses/@tweenjs/tween.js/LICENSE +23 -0
- package/licenses/@types/ndarray/LICENSE +21 -0
- package/licenses/@types/node/LICENSE +21 -0
- package/licenses/@types/stats.js/LICENSE +21 -0
- package/licenses/@types/three/@dimforge/rapier3d-compat/LICENSE +201 -0
- package/licenses/@types/three/LICENSE +21 -0
- package/licenses/@types/webxr/LICENSE +21 -0
- package/licenses/@webgpu/types/LICENSE +26 -0
- package/licenses/THIRD-PARTY-NOTICES.md +139 -0
- package/licenses/cwise-compiler/LICENSE +22 -0
- package/licenses/detect-libc/LICENSE +201 -0
- package/licenses/esbuild/LICENSE.md +21 -0
- package/licenses/fast-png/LICENSE +21 -0
- package/licenses/fdir/LICENSE +7 -0
- package/licenses/fflate/LICENSE +21 -0
- package/licenses/iobuffer/LICENSE +22 -0
- package/licenses/iota-array/LICENSE +22 -0
- package/licenses/is-buffer/LICENSE +21 -0
- package/licenses/ktx-parse/LICENSE +21 -0
- package/licenses/lightningcss/LICENSE +373 -0
- package/licenses/lightningcss-win32-x64-msvc/LICENSE +373 -0
- package/licenses/meshoptimizer/LICENSE.md +21 -0
- package/licenses/nanoid/LICENSE +20 -0
- package/licenses/ndarray/LICENSE +22 -0
- package/licenses/ndarray-lanczos/LICENSE +21 -0
- package/licenses/ndarray-ops/LICENSE +22 -0
- package/licenses/ndarray-pixels/LICENSE +21 -0
- package/licenses/ngraph.path/LICENSE +21 -0
- package/licenses/picocolors/LICENSE +15 -0
- package/licenses/picomatch/LICENSE +21 -0
- package/licenses/playwright/LICENSE +202 -0
- package/licenses/playwright/NOTICE +5 -0
- package/licenses/playwright-core/LICENSE +202 -0
- package/licenses/playwright-core/NOTICE +5 -0
- package/licenses/postcss/LICENSE +20 -0
- package/licenses/prettier/LICENSE +7 -0
- package/licenses/property-graph/LICENSE +21 -0
- package/licenses/rolldown/LICENSE +25 -0
- package/licenses/semver/LICENSE +15 -0
- package/licenses/sharp/LICENSE +191 -0
- package/licenses/source-map-js/LICENSE +28 -0
- package/licenses/three/LICENSE +21 -0
- package/licenses/tinyglobby/LICENSE +21 -0
- package/licenses/tsx/LICENSE +21 -0
- package/licenses/typescript/LICENSE.txt +55 -0
- package/licenses/undici-types/LICENSE +21 -0
- package/licenses/uniq/LICENSE +22 -0
- package/licenses/vite/LICENSE.md +2084 -0
- package/package.json +49 -4
- package/web/index.html +34 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
const MAX_FLOAT = 3.4028234663852886e38;
|
|
2
|
+
function fail(code, label) {
|
|
3
|
+
throw new Error("TC_SURFACE_MOTION_" +
|
|
4
|
+
code +
|
|
5
|
+
": " +
|
|
6
|
+
label +
|
|
7
|
+
"; re-extract unique version 1 surfaces and supply a complete current order");
|
|
8
|
+
}
|
|
9
|
+
function identity(t, label) {
|
|
10
|
+
if (!t ||
|
|
11
|
+
typeof t.objectUuid !== "string" ||
|
|
12
|
+
!t.objectUuid.length ||
|
|
13
|
+
typeof t.geometryUuid !== "string" ||
|
|
14
|
+
!t.geometryUuid.length ||
|
|
15
|
+
![t.instanceId, t.elementOffset].every((n) => Number.isSafeInteger(n) && n >= 0) ||
|
|
16
|
+
!Number.isSafeInteger(t.groupIndex) ||
|
|
17
|
+
t.groupIndex < -1 ||
|
|
18
|
+
!Array.isArray(t.vertexIndices) ||
|
|
19
|
+
t.vertexIndices.length !== 3 ||
|
|
20
|
+
!Array.from(t.vertexIndices).every((n) => Number.isSafeInteger(n) && n >= 0))
|
|
21
|
+
fail("INVALID_IDENTITY", label);
|
|
22
|
+
// Keep exactly the geometry identity used by acceleration.ts, not material UUID.
|
|
23
|
+
return JSON.stringify([
|
|
24
|
+
t.objectUuid,
|
|
25
|
+
t.geometryUuid,
|
|
26
|
+
t.instanceId,
|
|
27
|
+
t.groupIndex,
|
|
28
|
+
t.elementOffset,
|
|
29
|
+
t.vertexIndices,
|
|
30
|
+
]);
|
|
31
|
+
}
|
|
32
|
+
function index(scene, label, positions) {
|
|
33
|
+
if (!scene ||
|
|
34
|
+
scene.version !== 1 ||
|
|
35
|
+
!Array.isArray(scene.triangles) ||
|
|
36
|
+
!Array.isArray(scene.materials) ||
|
|
37
|
+
!Array.isArray(scene.textures) ||
|
|
38
|
+
!Array.isArray(scene.diagnostics))
|
|
39
|
+
fail("INVALID_SNAPSHOT", label);
|
|
40
|
+
const triangles = new Map();
|
|
41
|
+
for (const [i, t] of scene.triangles.entries()) {
|
|
42
|
+
const location = label + ".triangles[" + i + "]";
|
|
43
|
+
const key = identity(t, location);
|
|
44
|
+
if (triangles.has(key))
|
|
45
|
+
fail("DUPLICATE_IDENTITY", location);
|
|
46
|
+
if (positions) {
|
|
47
|
+
if (!Array.isArray(t.vertices) || t.vertices.length !== 3)
|
|
48
|
+
fail("INVALID_POSITION", location + ".vertices");
|
|
49
|
+
for (const [j, v] of t.vertices.entries()) {
|
|
50
|
+
const p = v?.position;
|
|
51
|
+
if (!Array.isArray(p) ||
|
|
52
|
+
p.length !== 3 ||
|
|
53
|
+
!Array.from(p).every((n) => typeof n === "number" &&
|
|
54
|
+
Number.isFinite(n) &&
|
|
55
|
+
Math.abs(n) <= MAX_FLOAT))
|
|
56
|
+
fail("INVALID_POSITION", location + ".vertices[" + j + "].position");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
triangles.set(key, t);
|
|
60
|
+
}
|
|
61
|
+
return triangles;
|
|
62
|
+
}
|
|
63
|
+
/** Previous world-space positions only; a match does not validate shading history. */
|
|
64
|
+
export function packPreviousSurfacePositions(previous, current, ordered = current?.triangles) {
|
|
65
|
+
const remaining = index(current, "current", false);
|
|
66
|
+
const history = previous === undefined ? undefined : index(previous, "previous", true);
|
|
67
|
+
if (!Array.isArray(ordered) || ordered.length !== remaining.size)
|
|
68
|
+
fail("INVALID_ORDER", "ordered must include every current triangle once");
|
|
69
|
+
const data = new Float32Array(ordered.length * 12);
|
|
70
|
+
let matched = 0;
|
|
71
|
+
for (const [i, t] of ordered.entries()) {
|
|
72
|
+
const key = identity(t, "ordered[" + i + "]");
|
|
73
|
+
if (!remaining.delete(key))
|
|
74
|
+
fail("INVALID_ORDER", "ordered[" + i + "] is unknown or repeated");
|
|
75
|
+
const old = history?.get(key);
|
|
76
|
+
if (!old)
|
|
77
|
+
continue;
|
|
78
|
+
for (let j = 0; j < 3; j++)
|
|
79
|
+
data.set(old.vertices[j].position, i * 12 + j * 4);
|
|
80
|
+
data[i * 12 + 3] = 1;
|
|
81
|
+
matched++;
|
|
82
|
+
}
|
|
83
|
+
return { data, matched, missing: ordered.length - matched };
|
|
84
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/** Surface storage bindings 0..3, dynamic acceleration nodes at 4. Caller normalizes ray direction. */
|
|
2
|
+
export const SURFACE_RAY_SHADER = /* wgsl */ String.raw `
|
|
3
|
+
override surfaceOrderedTraversal:bool=false;
|
|
4
|
+
struct SurfaceNode{lo:vec4f,hi:vec4f,}
|
|
5
|
+
struct SurfaceHit{distance:f32,index:i32,bary:vec3f,front:bool,}
|
|
6
|
+
struct SurfaceCursor{current:u32,previous:u32,}
|
|
7
|
+
@group(0) @binding(4) var<storage,read> surfaceAccelerationData:array<vec4f>;
|
|
8
|
+
fn surfaceLoadNode(index:u32)->SurfaceNode{return SurfaceNode(surfaceAccelerationData[index*2u],surfaceAccelerationData[index*2u+1u]);}
|
|
9
|
+
fn surfaceBox(origin:vec3f,direction:vec3f,node:SurfaceNode,maxDistance:f32)->bool{
|
|
10
|
+
var near=0.0;var far=maxDistance;
|
|
11
|
+
for(var axis=0u;axis<3u;axis++){
|
|
12
|
+
if(abs(direction[axis])<1e-20){if(origin[axis]<node.lo[axis]||origin[axis]>node.hi[axis]){return false;}}
|
|
13
|
+
else{let a=(node.lo[axis]-origin[axis])/direction[axis];let b=(node.hi[axis]-origin[axis])/direction[axis];near=max(near,min(a,b));far=min(far,max(a,b));if(near>far){return false;}}
|
|
14
|
+
}return far>=near;
|
|
15
|
+
}
|
|
16
|
+
fn surfaceEntry(origin:vec3f,direction:vec3f,inverse:vec3f,node:SurfaceNode,maxDistance:f32)->f32{
|
|
17
|
+
let parallel=abs(direction)<vec3f(1e-20);if(any(parallel&((origin<node.lo.xyz)|(origin>node.hi.xyz)))){return 1e30;}
|
|
18
|
+
let a=(node.lo.xyz-origin)*inverse;let b=(node.hi.xyz-origin)*inverse;let low=min(a,b);let high=max(a,b);let near=max(max(low.x,low.y),max(low.z,0.0));let far=min(min(high.x,high.y),min(high.z,maxDistance));return select(1e30,near,near<=far);
|
|
19
|
+
}
|
|
20
|
+
// Shared-edge predicates use the same sheared endpoint products in either winding.
|
|
21
|
+
fn surfaceBoundary(origin:vec3f,direction:vec3f,a:vec3f,b:vec3f,c:vec3f,maxDistance:f32)->vec4f{
|
|
22
|
+
var kz=0u;if(abs(direction.y)>abs(direction.x)){kz=1u;}if(abs(direction.z)>abs(direction[kz])){kz=2u;}
|
|
23
|
+
var kx=(kz+1u)%3u;var ky=(kx+1u)%3u;if(direction[kz]<0.0){let swap=kx;kx=ky;ky=swap;}
|
|
24
|
+
let relativeA=a-origin;let relativeB=b-origin;let relativeC=c-origin;
|
|
25
|
+
let sx=direction[kx]/direction[kz];let sy=direction[ky]/direction[kz];
|
|
26
|
+
let pa=vec2f(relativeA[kx]-sx*relativeA[kz],relativeA[ky]-sy*relativeA[kz]);
|
|
27
|
+
let pb=vec2f(relativeB[kx]-sx*relativeB[kz],relativeB[ky]-sy*relativeB[kz]);
|
|
28
|
+
let pc=vec2f(relativeC[kx]-sx*relativeC[kz],relativeC[ky]-sy*relativeC[kz]);
|
|
29
|
+
let edges=vec3f(pb.x*pc.y-pb.y*pc.x,pc.x*pa.y-pc.y*pa.x,pa.x*pb.y-pa.y*pb.x);
|
|
30
|
+
if(any(edges<vec3f(0))&&any(edges>vec3f(0))){return vec4f(0,0,0,-1);}
|
|
31
|
+
let determinant=edges.x+edges.y+edges.z;if(determinant==0.0){return vec4f(0,0,0,-1);}
|
|
32
|
+
let distance=dot(edges,vec3f(relativeA[kz],relativeB[kz],relativeC[kz]))/(determinant*direction[kz]);
|
|
33
|
+
if(distance<=0.0||distance>maxDistance){return vec4f(0,0,0,-1);}
|
|
34
|
+
return vec4f(edges/determinant,distance);
|
|
35
|
+
}
|
|
36
|
+
// Parent links permit near-first descent without a fixed per-ray traversal stack.
|
|
37
|
+
fn surfaceNextLeaf(origin:vec3f,direction:vec3f,inverse:vec3f,limit:f32,nodeCount:u32,triangleCount:u32,cursor:ptr<function,SurfaceCursor>)->u32{
|
|
38
|
+
loop{
|
|
39
|
+
let current=(*cursor).current;if(current>=nodeCount){return nodeCount;}
|
|
40
|
+
let node=surfaceLoadNode(current);
|
|
41
|
+
let links=surfaceAccelerationData[nodeCount*2u+triangleCount*3u+current];let parent=u32(links.x);
|
|
42
|
+
if(current==0u&&(*cursor).previous==nodeCount&&surfaceEntry(origin,direction,inverse,node,limit)==1e30){(*cursor).current=nodeCount;return nodeCount;}
|
|
43
|
+
if(node.hi.w>0.0){(*cursor).previous=current;(*cursor).current=parent;return current;}
|
|
44
|
+
let left=u32(links.y);let right=u32(links.z);
|
|
45
|
+
let leftEntry=surfaceEntry(origin,direction,inverse,surfaceLoadNode(left),1e30);
|
|
46
|
+
let rightEntry=surfaceEntry(origin,direction,inverse,surfaceLoadNode(right),1e30);
|
|
47
|
+
let first=select(left,right,rightEntry<leftEntry);let second=select(right,left,rightEntry<leftEntry);
|
|
48
|
+
let near= min(leftEntry,rightEntry);let far=max(leftEntry,rightEntry);
|
|
49
|
+
var next=parent;
|
|
50
|
+
if((*cursor).previous==parent&&near<1e30&&near<=limit){next=first;}
|
|
51
|
+
else if(((*cursor).previous==parent||(*cursor).previous==first)&&far<1e30&&far<=limit){next=second;}
|
|
52
|
+
(*cursor).previous=current;(*cursor).current=next;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
fn traceSurface(origin:vec3f,direction:vec3f,maxDistance:f32,nodeCount:u32,triangleCount:u32,coverageRandom:f32)->SurfaceHit{
|
|
56
|
+
var hit=SurfaceHit(maxDistance,-1,vec3f(0),true);if(nodeCount==0u||triangleCount==0u){return hit;}
|
|
57
|
+
let inverse=1.0/select(vec3f(1e-30),direction,abs(direction)>vec3f(1e-20));var current=0u;var cursor=SurfaceCursor(0u,nodeCount);
|
|
58
|
+
loop{if(surfaceOrderedTraversal){current=surfaceNextLeaf(origin,direction,inverse,hit.distance,nodeCount,triangleCount,&cursor);}if(current>=nodeCount){break;}let node=surfaceLoadNode(current);if(!surfaceOrderedTraversal&&surfaceEntry(origin,direction,inverse,node,hit.distance)==1e30){current=select(u32(node.lo.w),current+1u,node.hi.w>0.0);continue;}
|
|
59
|
+
if(node.hi.w>0.0){let start=u32(node.lo.w);let count=u32(node.hi.w);
|
|
60
|
+
for(var slot=0u;slot<count;slot++){
|
|
61
|
+
let index=start+slot;if(index>=triangleCount){continue;}let offset=nodeCount*2u+index*3u;let a=surfaceAccelerationData[offset];let packedB=surfaceAccelerationData[offset+1u];let b=packedB.xyz;let c=surfaceAccelerationData[offset+2u].xyz;let edge1=b-a.xyz;let edge2=c-a.xyz;let p=cross(direction,edge2);let determinant=dot(edge1,p);let material=surfaceMaterials[u32(a.w)];let epsilon=1e-7*length(edge1)*length(edge2);if(determinant==0.0||((!surfacePhysicalEnabled||material.physical.x==0.0)&&abs(determinant)<=epsilon)){continue;}
|
|
62
|
+
let front=(determinant>0.0)==(packedB.w>0.0);if((!surfacePhysicalEnabled||material.physical.x==0.0)&&((material.maps1.w==0.0&&!front)||(material.maps1.w==1.0&&front))){continue;}
|
|
63
|
+
var distance:f32;var bary:vec3f;if((surfacePhysicalEnabled&&material.physical.x>0.0)){let boundary=surfaceBoundary(origin,direction,a.xyz,b,c,hit.distance);if(boundary.w<0.0){continue;}distance=boundary.w;bary=boundary.xyz;}else{let inverse=1.0/determinant;let relative=origin-a.xyz;let u=dot(relative,p)*inverse;if(u<0.0||u>1.0){continue;}let q=cross(relative,edge1);let v=dot(direction,q)*inverse;if(v<0.0||u+v>1.0){continue;}distance=dot(edge2,q)*inverse;if(distance<=1e-5||distance>hit.distance){continue;}bary=vec3f(1.0-u-v,u,v);}
|
|
64
|
+
let coverage=surfaceCoverage(index,bary,front);
|
|
65
|
+
if(coverage.y>0.5||(material.normal.w==2.0&&surfaceCoverageRandom(coverageRandom,index)>coverage.x)){continue;}
|
|
66
|
+
if(distance==hit.distance&&hit.index>=0&&index>=u32(hit.index)){continue;}
|
|
67
|
+
hit=SurfaceHit(distance,i32(index),bary,front);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
current++;
|
|
71
|
+
}return hit;
|
|
72
|
+
}
|
|
73
|
+
fn occludedSurface(origin:vec3f,direction:vec3f,maxDistance:f32,nodeCount:u32,triangleCount:u32,coverageRandom:f32)->bool{
|
|
74
|
+
var hit=SurfaceHit(maxDistance,-1,vec3f(0),true);if(nodeCount==0u||triangleCount==0u){return false;}
|
|
75
|
+
let inverse=1.0/select(vec3f(1e-30),direction,abs(direction)>vec3f(1e-20));var current=0u;
|
|
76
|
+
loop{if(current>=nodeCount){break;}let node=surfaceLoadNode(current);if(surfaceEntry(origin,direction,inverse,node,hit.distance)==1e30){current=select(u32(node.lo.w),current+1u,node.hi.w>0.0);continue;}
|
|
77
|
+
if(node.hi.w>0.0){let start=u32(node.lo.w);let count=u32(node.hi.w);
|
|
78
|
+
for(var slot=0u;slot<count;slot++){
|
|
79
|
+
let index=start+slot;if(index>=triangleCount){continue;}let offset=nodeCount*2u+index*3u;let a=surfaceAccelerationData[offset];let packedB=surfaceAccelerationData[offset+1u];let b=packedB.xyz;let c=surfaceAccelerationData[offset+2u].xyz;let edge1=b-a.xyz;let edge2=c-a.xyz;let p=cross(direction,edge2);let determinant=dot(edge1,p);let material=surfaceMaterials[u32(a.w)];let epsilon=1e-7*length(edge1)*length(edge2);if(determinant==0.0||((!surfacePhysicalEnabled||material.physical.x==0.0)&&abs(determinant)<=epsilon)){continue;}
|
|
80
|
+
let front=(determinant>0.0)==(packedB.w>0.0);if((!surfacePhysicalEnabled||material.physical.x==0.0)&&((material.maps1.w==0.0&&!front)||(material.maps1.w==1.0&&front))){continue;}
|
|
81
|
+
var distance:f32;var bary:vec3f;if((surfacePhysicalEnabled&&material.physical.x>0.0)){let boundary=surfaceBoundary(origin,direction,a.xyz,b,c,hit.distance);if(boundary.w<0.0){continue;}distance=boundary.w;bary=boundary.xyz;}else{let inverse=1.0/determinant;let relative=origin-a.xyz;let u=dot(relative,p)*inverse;if(u<0.0||u>1.0){continue;}let q=cross(relative,edge1);let v=dot(direction,q)*inverse;if(v<0.0||u+v>1.0){continue;}distance=dot(edge2,q)*inverse;if(distance<=1e-5||distance>hit.distance){continue;}bary=vec3f(1.0-u-v,u,v);}
|
|
82
|
+
let coverage=surfaceCoverage(index,bary,front);
|
|
83
|
+
if(coverage.y>0.5||(material.normal.w==2.0&&surfaceCoverageRandom(coverageRandom,index)>coverage.x)){continue;}
|
|
84
|
+
if(distance==hit.distance&&hit.index>=0&&index>=u32(hit.index)){continue;}
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
current++;
|
|
89
|
+
}return false;
|
|
90
|
+
}
|
|
91
|
+
`;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/** Shared shader surface evaluator. Bindings 0..3 match surface-gpu ABI 1. */
|
|
2
|
+
import { DEFAULT_SURFACE_GRAPHS } from "./material-graphs.js";
|
|
3
|
+
export const SURFACE_SHADER = /* wgsl */ String.raw `
|
|
4
|
+
override surfacePhysicalEnabled:bool=true;
|
|
5
|
+
struct SurfaceTriangle {
|
|
6
|
+
a:vec4f,b:vec4f,c:vec4f,na:vec4f,nb:vec4f,nc:vec4f,
|
|
7
|
+
ua:vec4f,ub:vec4f,uc:vec4f,ca:vec4f,cb:vec4f,cc:vec4f,
|
|
8
|
+
ta:vec4f,tb:vec4f,tc:vec4f,nma:vec4f,nmb:vec4f,nmc:vec4f,
|
|
9
|
+
}
|
|
10
|
+
struct SurfaceMaterial {base:vec4f,factors:vec4f,emission:vec4f,maps0:vec4f,maps1:vec4f,normal:vec4f,physical:vec4f,attenuation:vec4f,}
|
|
11
|
+
struct SurfaceTexture {info:vec4u,modes:vec4u,m0:vec4f,m1:vec4f,m2:vec4f,options:vec4f,}
|
|
12
|
+
struct SurfaceValue {base:vec3f,alpha:f32,normal:vec3f,roughness:f32,emissive:vec3f,metalness:f32,ao:f32,discarded:u32,medium:vec4f,specular:vec4f,}
|
|
13
|
+
fn surfaceCoverageRandom(random:f32,index:u32)->f32{var value=bitcast<u32>(random)^(index*0x9e3779b9u+0x85ebca6bu);value=(value^(value>>16u))*0x7feb352du;value=(value^(value>>15u))*0x846ca68bu;value=value^(value>>16u);return min(f32(value)/4294967296.0,0.99999994);}
|
|
14
|
+
fn surfaceOriginalFront(triangle:SurfaceTriangle,geometricFront:bool)->bool{return geometricFront==(triangle.nma.w>0.0);}
|
|
15
|
+
fn surfaceNormalSign(material:SurfaceMaterial,front:bool)->f32{return select(1.0,-1.0,select(material.maps1.w==1.0||(material.maps1.w==2.0&&!front),!front,surfacePhysicalEnabled&&material.physical.x>0.0));}
|
|
16
|
+
fn surfaceGraphNormal(value:vec3f,fallback:vec3f)->vec3f{let scale=max(max(abs(value.x),abs(value.y)),abs(value.z));if(scale==0.0){return fallback;}return normalize(value/scale);}
|
|
17
|
+
@group(0) @binding(0) var<storage,read> surfaceGeometry:array<vec4f>;
|
|
18
|
+
fn surfaceTriangle(index:u32)->SurfaceTriangle{
|
|
19
|
+
let p=index*18u;return SurfaceTriangle(surfaceGeometry[p],surfaceGeometry[p+1u],surfaceGeometry[p+2u],surfaceGeometry[p+3u],surfaceGeometry[p+4u],surfaceGeometry[p+5u],surfaceGeometry[p+6u],surfaceGeometry[p+7u],surfaceGeometry[p+8u],surfaceGeometry[p+9u],surfaceGeometry[p+10u],surfaceGeometry[p+11u],surfaceGeometry[p+12u],surfaceGeometry[p+13u],surfaceGeometry[p+14u],surfaceGeometry[p+15u],surfaceGeometry[p+16u],surfaceGeometry[p+17u]);
|
|
20
|
+
}
|
|
21
|
+
@group(0) @binding(1) var<storage,read> surfaceMaterials:array<SurfaceMaterial>;
|
|
22
|
+
@group(0) @binding(2) var<storage,read> surfaceTextures:array<SurfaceTexture>;
|
|
23
|
+
@group(0) @binding(3) var<storage,read> surfaceTexels:array<u32>;
|
|
24
|
+
fn surfaceSrgb(value:vec3f)->vec3f {return select(pow((value+vec3f(0.055))/1.055,vec3f(2.4)),value/12.92,value<=vec3f(0.04045));}
|
|
25
|
+
fn surfaceIndex(value:i32,size:i32,mode:u32)->i32{
|
|
26
|
+
if(mode==0u){return clamp(value,0,size-1);}
|
|
27
|
+
if(mode==1u){return ((value%size)+size)%size;}
|
|
28
|
+
let period=size*2;let index=((value%period)+period)%period;return select(period-1-index,index,index<size);
|
|
29
|
+
}
|
|
30
|
+
fn surfaceRead(texture:SurfaceTexture,x:i32,y:i32)->vec4f{
|
|
31
|
+
let index=u32(surfaceIndex(y,i32(texture.info.z),texture.modes.y))*texture.info.y+u32(surfaceIndex(x,i32(texture.info.y),texture.modes.x));
|
|
32
|
+
var value:vec4f;
|
|
33
|
+
if((texture.modes.w&1u)!=0u){let offset=texture.info.x+index*4u;value=vec4f(bitcast<f32>(surfaceTexels[offset]),bitcast<f32>(surfaceTexels[offset+1u]),bitcast<f32>(surfaceTexels[offset+2u]),bitcast<f32>(surfaceTexels[offset+3u]));}
|
|
34
|
+
else{value=unpack4x8unorm(surfaceTexels[texture.info.x+index]);}
|
|
35
|
+
if((texture.modes.w&2u)!=0u){value=vec4f(surfaceSrgb(value.rgb),value.a);}return value;
|
|
36
|
+
}
|
|
37
|
+
fn surfaceUV(texture:SurfaceTexture,uvs:vec4f)->vec2f{
|
|
38
|
+
let uv=select(uvs.xy,uvs.zw,texture.info.w==1u);return (mat3x3f(texture.m0.xyz,texture.m1.xyz,texture.m2.xyz)*vec3f(uv,1)).xy;
|
|
39
|
+
}
|
|
40
|
+
fn surfaceWrap(value:f32,mode:u32)->f32{
|
|
41
|
+
if(mode==0u){return clamp(value,0.0,1.0);}if(mode==1u){return fract(value);}let p=value-floor(value/2.0)*2.0;return select(2.0-p,p,p<=1.0);
|
|
42
|
+
}
|
|
43
|
+
fn surfaceCoverage(index:u32,bary:vec3f,front:bool)->vec2f{
|
|
44
|
+
let material=surfaceMaterials[u32(surfaceTriangle(index).a.w)];
|
|
45
|
+
if((!surfacePhysicalEnabled||material.physical.x==0.0)&&((material.maps1.w==0.0&&!front)||(material.maps1.w==1.0&&front))){return vec2f(0,1);}
|
|
46
|
+
if(material.normal.w==0.0&&material.factors.z==0.0){return vec2f(1,0);}
|
|
47
|
+
let triangle=surfaceTriangle(index);
|
|
48
|
+
let uv=triangle.ua*bary.x+triangle.ub*bary.y+triangle.uc*bary.z;var alpha=material.base.a;
|
|
49
|
+
if(triangle.nb.w>0.5){alpha*=triangle.ca.a*bary.x+triangle.cb.a*bary.y+triangle.cc.a*bary.z;}
|
|
50
|
+
alpha*=surfaceMap(material.maps0.x,uv).a*surfaceMap(material.maps0.y,uv).g;
|
|
51
|
+
let custom=surfaceGraphOpacity(index,bary,front);if(custom.y>0.5){alpha*=custom.x;}
|
|
52
|
+
return vec2f(alpha,select(0.0,1.0,material.factors.z>0.0&&alpha<=material.factors.z));
|
|
53
|
+
}
|
|
54
|
+
fn surfaceMap(id:f32,uvs:vec4f)->vec4f{
|
|
55
|
+
if(id<0.0){return vec4f(1);}let texture=surfaceTextures[u32(id)];let uv=surfaceUV(texture,uvs);let coordinate=vec2f(surfaceWrap(uv.x,texture.modes.x),surfaceWrap(uv.y,texture.modes.y))*vec2f(texture.info.yz);
|
|
56
|
+
if(texture.modes.z==0u){let pixel=vec2i(floor(coordinate));return surfaceRead(texture,pixel.x,pixel.y);}
|
|
57
|
+
let at=coordinate-vec2f(0.5);let pixel=vec2i(floor(at));let blend=fract(at);return mix(mix(surfaceRead(texture,pixel.x,pixel.y),surfaceRead(texture,pixel.x+1,pixel.y),blend.x),mix(surfaceRead(texture,pixel.x,pixel.y+1),surfaceRead(texture,pixel.x+1,pixel.y+1),blend.x),blend.y);
|
|
58
|
+
}
|
|
59
|
+
fn evaluateSurface(index:u32,bary:vec3f,front:bool)->SurfaceValue{
|
|
60
|
+
return evaluateSurfaceView(index,bary,front,vec3f(0));
|
|
61
|
+
}
|
|
62
|
+
fn evaluateSurfaceView(index:u32,bary:vec3f,front:bool,view:vec3f)->SurfaceValue{
|
|
63
|
+
let triangle=surfaceTriangle(index);let material=surfaceMaterials[u32(triangle.a.w)];let uv=triangle.ua*bary.x+triangle.ub*bary.y+triangle.uc*bary.z;
|
|
64
|
+
let reverse=select(material.maps1.w==1.0||(material.maps1.w==2.0&&!front),!front,(surfacePhysicalEnabled&&material.physical.x>0.0));let sign=select(1.0,-1.0,reverse);
|
|
65
|
+
var normal=normalize(triangle.na.xyz*bary.x+triangle.nb.xyz*bary.y+triangle.nc.xyz*bary.z)*sign;
|
|
66
|
+
var color=material.base;if(triangle.nb.w>0.5){color*=triangle.ca*bary.x+triangle.cb*bary.y+triangle.cc*bary.z;}
|
|
67
|
+
color*=vec4f(triangle.b.w,triangle.c.w,triangle.na.w,1);color*=surfaceMap(material.maps0.x,uv);color.a*=surfaceMap(material.maps0.y,uv).g;
|
|
68
|
+
let roughness=material.factors.x*surfaceMap(material.maps0.w,uv).g;let metalness=material.factors.y*surfaceMap(material.maps1.x,uv).b;
|
|
69
|
+
let ao=1.0+(surfaceMap(material.maps1.y,uv).r-1.0)*material.factors.w;let emissive=material.emission.rgb*material.emission.w*surfaceMap(material.maps1.z,uv).rgb;
|
|
70
|
+
if(material.maps0.z>=0.0){
|
|
71
|
+
let texture=surfaceTextures[u32(material.maps0.z)];var sampled=surfaceMap(material.maps0.z,uv).xyz*2.0-vec3f(1);sampled=vec3f(sampled.xy*material.normal.xy,sampled.z);
|
|
72
|
+
if(material.normal.z>0.5){normal=normalize(mat3x3f(triangle.nma.xyz,triangle.nmb.xyz,triangle.nmc.xyz)*sampled*sign);}
|
|
73
|
+
else{
|
|
74
|
+
var tangent:vec3f;var handedness:f32;
|
|
75
|
+
if(triangle.nc.w>0.5){let t=triangle.ta*bary.x+triangle.tb*bary.y+triangle.tc*bary.z;tangent=normalize(t.xyz)*sign;handedness=select(-1.0,1.0,t.w>=0.0);}
|
|
76
|
+
else{let a=surfaceUV(texture,triangle.ua);let b=surfaceUV(texture,triangle.ub);let c=surfaceUV(texture,triangle.uc);let du1=b-a;let du2=c-a;let det=du1.x*du2.y-du2.x*du1.y;let edge1=triangle.b.xyz-triangle.a.xyz;let edge2=triangle.c.xyz-triangle.a.xyz;
|
|
77
|
+
let derivativeT=(edge1*du2.y-edge2*du1.y)/det;let derivativeB=(edge2*du1.x-edge1*du2.x)/det;tangent=normalize(derivativeT-normal*dot(derivativeT,normal))*sign;handedness=select(-1.0,1.0,dot(cross(normal,tangent),derivativeB)>=0.0);
|
|
78
|
+
}
|
|
79
|
+
let bitangent=normalize(cross(normal,tangent))*handedness*sign;normal=normalize(tangent*sampled.x+bitangent*sampled.y+normal*sampled.z);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
var medium=material.physical;var specular=vec4f(select(material.attenuation.rgb,vec3f(1),medium.x>0.0),1.0-medium.w);
|
|
83
|
+
if(medium.x==0.0){specular*=vec4f(surfaceMap(material.attenuation.w-1.0,uv).rgb,surfaceMap(medium.z-1.0,uv).a);medium.z=0.0;}
|
|
84
|
+
var result=surfaceGraphApply(index,bary,front,view,SurfaceValue(color.rgb,color.a,normal,roughness,emissive,metalness,ao,0u,medium,specular));
|
|
85
|
+
let discarded=((!surfacePhysicalEnabled||material.physical.x==0.0)&&((material.maps1.w==0.0&&!front)||(material.maps1.w==1.0&&front)))||(material.factors.z>0.0&&result.alpha<=material.factors.z);
|
|
86
|
+
result.discarded=select(0u,1u,discarded);return result;
|
|
87
|
+
}
|
|
88
|
+
` + DEFAULT_SURFACE_GRAPHS;
|