@ifc-lite/renderer 1.0.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/LICENSE +373 -0
- package/dist/camera.d.ts +178 -0
- package/dist/camera.d.ts.map +1 -0
- package/dist/camera.js +921 -0
- package/dist/camera.js.map +1 -0
- package/dist/device.d.ts +46 -0
- package/dist/device.d.ts.map +1 -0
- package/dist/device.js +135 -0
- package/dist/device.js.map +1 -0
- package/dist/index.d.ts +63 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +397 -0
- package/dist/index.js.map +1 -0
- package/dist/math.d.ts +23 -0
- package/dist/math.d.ts.map +1 -0
- package/dist/math.js +102 -0
- package/dist/math.js.map +1 -0
- package/dist/picker.d.ts +22 -0
- package/dist/picker.d.ts.map +1 -0
- package/dist/picker.js +215 -0
- package/dist/picker.js.map +1 -0
- package/dist/pipeline.d.ts +40 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +266 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/post-processor.d.ts +32 -0
- package/dist/post-processor.d.ts.map +1 -0
- package/dist/post-processor.js +42 -0
- package/dist/post-processor.js.map +1 -0
- package/dist/scene.d.ts +35 -0
- package/dist/scene.d.ts.map +1 -0
- package/dist/scene.js +46 -0
- package/dist/scene.js.map +1 -0
- package/dist/section-plane.d.ts +34 -0
- package/dist/section-plane.d.ts.map +1 -0
- package/dist/section-plane.js +232 -0
- package/dist/section-plane.js.map +1 -0
- package/dist/types.d.ts +58 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +47 -0
package/dist/picker.js
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
export class Picker {
|
|
5
|
+
device;
|
|
6
|
+
pipeline;
|
|
7
|
+
depthTexture;
|
|
8
|
+
colorTexture;
|
|
9
|
+
uniformBuffer;
|
|
10
|
+
expressIdBuffer;
|
|
11
|
+
bindGroup;
|
|
12
|
+
maxMeshes = 10000;
|
|
13
|
+
constructor(device, width = 1, height = 1) {
|
|
14
|
+
this.device = device.getDevice();
|
|
15
|
+
// Create textures for picking
|
|
16
|
+
this.colorTexture = this.device.createTexture({
|
|
17
|
+
size: { width, height },
|
|
18
|
+
format: 'r32uint',
|
|
19
|
+
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC,
|
|
20
|
+
});
|
|
21
|
+
this.depthTexture = this.device.createTexture({
|
|
22
|
+
size: { width, height },
|
|
23
|
+
format: 'depth24plus',
|
|
24
|
+
usage: GPUTextureUsage.RENDER_ATTACHMENT,
|
|
25
|
+
});
|
|
26
|
+
// Create uniform buffer for viewProj matrix only (16 floats = 64 bytes)
|
|
27
|
+
this.uniformBuffer = this.device.createBuffer({
|
|
28
|
+
size: 64,
|
|
29
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
30
|
+
});
|
|
31
|
+
// Create storage buffer for expressIds (one u32 per mesh, +1 encoding)
|
|
32
|
+
// We'll upload all expressIds at once, then use instance_index to look them up
|
|
33
|
+
this.expressIdBuffer = this.device.createBuffer({
|
|
34
|
+
size: this.maxMeshes * 4, // 4 bytes per u32
|
|
35
|
+
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
|
|
36
|
+
});
|
|
37
|
+
// Create picker shader that uses storage buffer for per-object expressId
|
|
38
|
+
const shaderModule = this.device.createShaderModule({
|
|
39
|
+
code: `
|
|
40
|
+
struct Uniforms {
|
|
41
|
+
viewProj: mat4x4<f32>,
|
|
42
|
+
}
|
|
43
|
+
@binding(0) @group(0) var<uniform> uniforms: Uniforms;
|
|
44
|
+
@binding(1) @group(0) var<storage, read> expressIds: array<u32>;
|
|
45
|
+
|
|
46
|
+
struct VertexInput {
|
|
47
|
+
@location(0) position: vec3<f32>,
|
|
48
|
+
@location(1) normal: vec3<f32>,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
struct VertexOutput {
|
|
52
|
+
@builtin(position) position: vec4<f32>,
|
|
53
|
+
@location(0) @interpolate(flat) objectId: u32,
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@vertex
|
|
57
|
+
fn vs_main(input: VertexInput, @builtin(instance_index) instanceIndex: u32) -> VertexOutput {
|
|
58
|
+
var output: VertexOutput;
|
|
59
|
+
// Identity transform - positions are already in world space
|
|
60
|
+
output.position = uniforms.viewProj * vec4<f32>(input.position, 1.0);
|
|
61
|
+
// Look up expressId from storage buffer using instance index
|
|
62
|
+
output.objectId = expressIds[instanceIndex];
|
|
63
|
+
return output;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@fragment
|
|
67
|
+
fn fs_main(input: VertexOutput) -> @location(0) u32 {
|
|
68
|
+
return input.objectId;
|
|
69
|
+
}
|
|
70
|
+
`,
|
|
71
|
+
});
|
|
72
|
+
this.pipeline = this.device.createRenderPipeline({
|
|
73
|
+
layout: 'auto',
|
|
74
|
+
vertex: {
|
|
75
|
+
module: shaderModule,
|
|
76
|
+
entryPoint: 'vs_main',
|
|
77
|
+
buffers: [
|
|
78
|
+
{
|
|
79
|
+
arrayStride: 24,
|
|
80
|
+
attributes: [
|
|
81
|
+
{ shaderLocation: 0, offset: 0, format: 'float32x3' },
|
|
82
|
+
{ shaderLocation: 1, offset: 12, format: 'float32x3' },
|
|
83
|
+
],
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
},
|
|
87
|
+
fragment: {
|
|
88
|
+
module: shaderModule,
|
|
89
|
+
entryPoint: 'fs_main',
|
|
90
|
+
targets: [{ format: 'r32uint' }],
|
|
91
|
+
},
|
|
92
|
+
primitive: {
|
|
93
|
+
topology: 'triangle-list',
|
|
94
|
+
cullMode: 'back',
|
|
95
|
+
},
|
|
96
|
+
depthStencil: {
|
|
97
|
+
format: 'depth24plus',
|
|
98
|
+
depthWriteEnabled: true,
|
|
99
|
+
depthCompare: 'less',
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
// Create bind group using the pipeline's auto-generated layout
|
|
103
|
+
// IMPORTANT: Must use getBindGroupLayout() when pipeline uses layout: 'auto'
|
|
104
|
+
this.bindGroup = this.device.createBindGroup({
|
|
105
|
+
layout: this.pipeline.getBindGroupLayout(0),
|
|
106
|
+
entries: [
|
|
107
|
+
{
|
|
108
|
+
binding: 0,
|
|
109
|
+
resource: { buffer: this.uniformBuffer },
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
binding: 1,
|
|
113
|
+
resource: { buffer: this.expressIdBuffer },
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Pick object at screen coordinates
|
|
120
|
+
*/
|
|
121
|
+
async pick(x, y, width, height, meshes, viewProj) {
|
|
122
|
+
// Resize textures if needed
|
|
123
|
+
if (this.colorTexture.width !== width || this.colorTexture.height !== height) {
|
|
124
|
+
this.colorTexture.destroy();
|
|
125
|
+
this.depthTexture.destroy();
|
|
126
|
+
this.colorTexture = this.device.createTexture({
|
|
127
|
+
size: { width, height },
|
|
128
|
+
format: 'r32uint',
|
|
129
|
+
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC,
|
|
130
|
+
});
|
|
131
|
+
this.depthTexture = this.device.createTexture({
|
|
132
|
+
size: { width, height },
|
|
133
|
+
format: 'depth24plus',
|
|
134
|
+
usage: GPUTextureUsage.RENDER_ATTACHMENT,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
// Recreate texture views each time to avoid reuse issues
|
|
138
|
+
// WebGPU texture views cannot be reused after being submitted
|
|
139
|
+
const colorView = this.colorTexture.createView();
|
|
140
|
+
const depthView = this.depthTexture.createView();
|
|
141
|
+
// Render picker pass
|
|
142
|
+
const encoder = this.device.createCommandEncoder();
|
|
143
|
+
const pass = encoder.beginRenderPass({
|
|
144
|
+
colorAttachments: [
|
|
145
|
+
{
|
|
146
|
+
view: colorView,
|
|
147
|
+
loadOp: 'clear',
|
|
148
|
+
clearValue: { r: 0, g: 0, b: 0, a: 0 },
|
|
149
|
+
storeOp: 'store',
|
|
150
|
+
},
|
|
151
|
+
],
|
|
152
|
+
depthStencilAttachment: {
|
|
153
|
+
view: depthView,
|
|
154
|
+
depthClearValue: 1.0,
|
|
155
|
+
depthLoadOp: 'clear',
|
|
156
|
+
depthStoreOp: 'store',
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
// Upload viewProj matrix to uniform buffer (once for all meshes)
|
|
160
|
+
this.device.queue.writeBuffer(this.uniformBuffer, 0, viewProj);
|
|
161
|
+
// Build expressId array for all meshes (expressId + 1, so 0 = no hit)
|
|
162
|
+
const expressIdArray = new Uint32Array(meshes.length);
|
|
163
|
+
for (let i = 0; i < meshes.length; i++) {
|
|
164
|
+
const mesh = meshes[i];
|
|
165
|
+
if (mesh) {
|
|
166
|
+
expressIdArray[i] = mesh.expressId + 1;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
this.device.queue.writeBuffer(this.expressIdBuffer, 0, expressIdArray);
|
|
170
|
+
pass.setPipeline(this.pipeline);
|
|
171
|
+
pass.setBindGroup(0, this.bindGroup);
|
|
172
|
+
// Draw each mesh with its index as the first instance
|
|
173
|
+
// The shader will use this instance_index to look up the expressId
|
|
174
|
+
for (let i = 0; i < meshes.length; i++) {
|
|
175
|
+
const mesh = meshes[i];
|
|
176
|
+
if (!mesh)
|
|
177
|
+
continue;
|
|
178
|
+
pass.setVertexBuffer(0, mesh.vertexBuffer);
|
|
179
|
+
pass.setIndexBuffer(mesh.indexBuffer, 'uint32');
|
|
180
|
+
// Draw 1 instance, starting at instance i (so instance_index = i in shader)
|
|
181
|
+
pass.drawIndexed(mesh.indexCount, 1, 0, 0, i);
|
|
182
|
+
}
|
|
183
|
+
pass.end();
|
|
184
|
+
// Read pixel at click position
|
|
185
|
+
// WebGPU requires bytesPerRow to be a multiple of 256
|
|
186
|
+
const BYTES_PER_ROW = 256;
|
|
187
|
+
const readBuffer = this.device.createBuffer({
|
|
188
|
+
size: BYTES_PER_ROW,
|
|
189
|
+
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,
|
|
190
|
+
});
|
|
191
|
+
encoder.copyTextureToBuffer({
|
|
192
|
+
texture: this.colorTexture,
|
|
193
|
+
origin: { x: Math.floor(x), y: Math.floor(y), z: 0 },
|
|
194
|
+
}, {
|
|
195
|
+
buffer: readBuffer,
|
|
196
|
+
bytesPerRow: BYTES_PER_ROW,
|
|
197
|
+
rowsPerImage: 1,
|
|
198
|
+
}, { width: 1, height: 1 });
|
|
199
|
+
this.device.queue.submit([encoder.finish()]);
|
|
200
|
+
// GPUMapMode.READ = 1 (WebGPU spec)
|
|
201
|
+
await readBuffer.mapAsync(1); // GPUMapMode.READ
|
|
202
|
+
const data = new Uint32Array(readBuffer.getMappedRange());
|
|
203
|
+
const objectId = data[0];
|
|
204
|
+
readBuffer.unmap();
|
|
205
|
+
readBuffer.destroy();
|
|
206
|
+
// objectId is expressId + 1 (so 0 = no hit)
|
|
207
|
+
// Return expressId directly
|
|
208
|
+
return objectId > 0 ? objectId - 1 : null;
|
|
209
|
+
}
|
|
210
|
+
updateUniforms(viewProj) {
|
|
211
|
+
// Update viewProj matrix only
|
|
212
|
+
this.device.queue.writeBuffer(this.uniformBuffer, 0, viewProj);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=picker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"picker.js","sourceRoot":"","sources":["../src/picker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebGPU render pipeline setup
|
|
3
|
+
*/
|
|
4
|
+
import { WebGPUDevice } from './device.js';
|
|
5
|
+
export declare class RenderPipeline {
|
|
6
|
+
private device;
|
|
7
|
+
private pipeline;
|
|
8
|
+
private depthTexture;
|
|
9
|
+
private depthTextureView;
|
|
10
|
+
private uniformBuffer;
|
|
11
|
+
private bindGroup;
|
|
12
|
+
private currentWidth;
|
|
13
|
+
private currentHeight;
|
|
14
|
+
constructor(device: WebGPUDevice, width?: number, height?: number);
|
|
15
|
+
/**
|
|
16
|
+
* Update uniform buffer with camera matrices, PBR material, section plane, and selection state
|
|
17
|
+
*/
|
|
18
|
+
updateUniforms(viewProj: Float32Array, model: Float32Array, color?: [number, number, number, number], material?: {
|
|
19
|
+
metallic?: number;
|
|
20
|
+
roughness?: number;
|
|
21
|
+
}, sectionPlane?: {
|
|
22
|
+
normal: [number, number, number];
|
|
23
|
+
distance: number;
|
|
24
|
+
enabled: boolean;
|
|
25
|
+
}, isSelected?: boolean): void;
|
|
26
|
+
/**
|
|
27
|
+
* Check if resize is needed
|
|
28
|
+
*/
|
|
29
|
+
needsResize(width: number, height: number): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Resize depth texture
|
|
32
|
+
*/
|
|
33
|
+
resize(width: number, height: number): void;
|
|
34
|
+
getPipeline(): GPURenderPipeline;
|
|
35
|
+
getDepthTextureView(): GPUTextureView;
|
|
36
|
+
getBindGroup(): GPUBindGroup;
|
|
37
|
+
getBindGroupLayout(): GPUBindGroupLayout;
|
|
38
|
+
getUniformBufferSize(): number;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=pipeline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAIA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,qBAAa,cAAc;IACvB,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,QAAQ,CAAoB;IACpC,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,gBAAgB,CAAiB;IACzC,OAAO,CAAC,aAAa,CAAY;IACjC,OAAO,CAAC,SAAS,CAAe;IAChC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,aAAa,CAAS;gBAElB,MAAM,EAAE,YAAY,EAAE,KAAK,GAAE,MAAU,EAAE,MAAM,GAAE,MAAU;IAmLvE;;OAEG;IACH,cAAc,CACV,QAAQ,EAAE,YAAY,EACtB,KAAK,EAAE,YAAY,EACnB,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACxC,QAAQ,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,EACpD,YAAY,CAAC,EAAE;QAAE,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,EACvF,UAAU,CAAC,EAAE,OAAO,GACrB,IAAI;IA+CP;;OAEG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO;IAInD;;OAEG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAe3C,WAAW,IAAI,iBAAiB;IAIhC,mBAAmB,IAAI,cAAc;IAIrC,YAAY,IAAI,YAAY;IAI5B,kBAAkB,IAAI,kBAAkB;IAIxC,oBAAoB,IAAI,MAAM;CAGjC"}
|
package/dist/pipeline.js
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
export class RenderPipeline {
|
|
5
|
+
device;
|
|
6
|
+
pipeline;
|
|
7
|
+
depthTexture;
|
|
8
|
+
depthTextureView;
|
|
9
|
+
uniformBuffer;
|
|
10
|
+
bindGroup;
|
|
11
|
+
currentWidth;
|
|
12
|
+
currentHeight;
|
|
13
|
+
constructor(device, width = 1, height = 1) {
|
|
14
|
+
this.currentWidth = width;
|
|
15
|
+
this.currentHeight = height;
|
|
16
|
+
this.device = device.getDevice();
|
|
17
|
+
const format = device.getFormat();
|
|
18
|
+
// Create depth texture
|
|
19
|
+
this.depthTexture = this.device.createTexture({
|
|
20
|
+
size: { width, height },
|
|
21
|
+
format: 'depth24plus',
|
|
22
|
+
usage: GPUTextureUsage.RENDER_ATTACHMENT,
|
|
23
|
+
});
|
|
24
|
+
this.depthTextureView = this.depthTexture.createView();
|
|
25
|
+
// Create uniform buffer for camera matrices, PBR material, and section plane
|
|
26
|
+
// Layout: viewProj (64 bytes) + model (64 bytes) + baseColor (16 bytes) + metallicRoughness (8 bytes) +
|
|
27
|
+
// sectionPlane (16 bytes: vec3 normal + float position) + flags (16 bytes: u32 isSelected + u32 sectionEnabled + padding) = 192 bytes
|
|
28
|
+
// WebGPU requires uniform buffers to be aligned to 16 bytes
|
|
29
|
+
this.uniformBuffer = this.device.createBuffer({
|
|
30
|
+
size: 192, // 12 * 16 bytes = properly aligned
|
|
31
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
32
|
+
});
|
|
33
|
+
// Create shader module with PBR lighting, section plane clipping, and selection outline
|
|
34
|
+
const shaderModule = this.device.createShaderModule({
|
|
35
|
+
code: `
|
|
36
|
+
struct Uniforms {
|
|
37
|
+
viewProj: mat4x4<f32>,
|
|
38
|
+
model: mat4x4<f32>,
|
|
39
|
+
baseColor: vec4<f32>,
|
|
40
|
+
metallicRoughness: vec2<f32>, // x = metallic, y = roughness
|
|
41
|
+
_padding1: vec2<f32>,
|
|
42
|
+
sectionPlane: vec4<f32>, // xyz = plane normal, w = plane distance
|
|
43
|
+
flags: vec4<u32>, // x = isSelected, y = sectionEnabled, z,w = reserved
|
|
44
|
+
}
|
|
45
|
+
@binding(0) @group(0) var<uniform> uniforms: Uniforms;
|
|
46
|
+
|
|
47
|
+
struct VertexInput {
|
|
48
|
+
@location(0) position: vec3<f32>,
|
|
49
|
+
@location(1) normal: vec3<f32>,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
struct VertexOutput {
|
|
53
|
+
@builtin(position) position: vec4<f32>,
|
|
54
|
+
@location(0) worldPos: vec3<f32>,
|
|
55
|
+
@location(1) normal: vec3<f32>,
|
|
56
|
+
@location(2) @interpolate(flat) objectId: u32,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@vertex
|
|
60
|
+
fn vs_main(input: VertexInput, @builtin(instance_index) instanceIndex: u32) -> VertexOutput {
|
|
61
|
+
var output: VertexOutput;
|
|
62
|
+
let worldPos = uniforms.model * vec4<f32>(input.position, 1.0);
|
|
63
|
+
output.position = uniforms.viewProj * worldPos;
|
|
64
|
+
output.worldPos = worldPos.xyz;
|
|
65
|
+
output.normal = normalize((uniforms.model * vec4<f32>(input.normal, 0.0)).xyz);
|
|
66
|
+
output.objectId = instanceIndex;
|
|
67
|
+
return output;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// PBR helper functions
|
|
71
|
+
fn fresnelSchlick(cosTheta: f32, F0: vec3<f32>) -> vec3<f32> {
|
|
72
|
+
return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
fn distributionGGX(NdotH: f32, roughness: f32) -> f32 {
|
|
76
|
+
let a = roughness * roughness;
|
|
77
|
+
let a2 = a * a;
|
|
78
|
+
let NdotH2 = NdotH * NdotH;
|
|
79
|
+
let num = a2;
|
|
80
|
+
let denomBase = (NdotH2 * (a2 - 1.0) + 1.0);
|
|
81
|
+
let denom = 3.14159265 * denomBase * denomBase;
|
|
82
|
+
return num / max(denom, 0.0000001);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
fn geometrySchlickGGX(NdotV: f32, roughness: f32) -> f32 {
|
|
86
|
+
let r = (roughness + 1.0);
|
|
87
|
+
let k = (r * r) / 8.0;
|
|
88
|
+
let num = NdotV;
|
|
89
|
+
let denom = NdotV * (1.0 - k) + k;
|
|
90
|
+
return num / max(denom, 0.0000001);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
fn geometrySmith(NdotV: f32, NdotL: f32, roughness: f32) -> f32 {
|
|
94
|
+
let ggx2 = geometrySchlickGGX(NdotV, roughness);
|
|
95
|
+
let ggx1 = geometrySchlickGGX(NdotL, roughness);
|
|
96
|
+
return ggx1 * ggx2;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
@fragment
|
|
100
|
+
fn fs_main(input: VertexOutput) -> @location(0) vec4<f32> {
|
|
101
|
+
// Section plane clipping
|
|
102
|
+
if (uniforms.flags.y == 1u) {
|
|
103
|
+
let planeNormal = uniforms.sectionPlane.xyz;
|
|
104
|
+
let planeDistance = uniforms.sectionPlane.w;
|
|
105
|
+
let distToPlane = dot(input.worldPos, planeNormal) - planeDistance;
|
|
106
|
+
if (distToPlane > 0.0) {
|
|
107
|
+
discard;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
let N = normalize(input.normal);
|
|
112
|
+
let L = normalize(vec3<f32>(0.5, 1.0, 0.3)); // Light direction
|
|
113
|
+
|
|
114
|
+
let NdotL = max(dot(N, L), 0.0);
|
|
115
|
+
|
|
116
|
+
var baseColor = uniforms.baseColor.rgb;
|
|
117
|
+
|
|
118
|
+
// Simple diffuse lighting with ambient
|
|
119
|
+
let ambient = 0.3;
|
|
120
|
+
let diffuse = NdotL * 0.7;
|
|
121
|
+
|
|
122
|
+
var color = baseColor * (ambient + diffuse);
|
|
123
|
+
|
|
124
|
+
// Selection highlight - add glow/fresnel effect
|
|
125
|
+
if (uniforms.flags.x == 1u) {
|
|
126
|
+
// Calculate view direction for fresnel effect
|
|
127
|
+
let V = normalize(-input.worldPos); // Assuming camera at origin (simplified)
|
|
128
|
+
let NdotV = max(dot(N, V), 0.0);
|
|
129
|
+
|
|
130
|
+
// Fresnel-like edge highlight for selection
|
|
131
|
+
let fresnel = pow(1.0 - NdotV, 2.0);
|
|
132
|
+
let highlightColor = vec3<f32>(0.3, 0.6, 1.0); // Blue highlight
|
|
133
|
+
color = mix(color, highlightColor, fresnel * 0.5 + 0.2);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Gamma correction (IFC colors are typically in sRGB)
|
|
137
|
+
color = pow(color, vec3<f32>(1.0 / 2.2));
|
|
138
|
+
|
|
139
|
+
return vec4<f32>(color, uniforms.baseColor.a);
|
|
140
|
+
}
|
|
141
|
+
`,
|
|
142
|
+
});
|
|
143
|
+
// Create render pipeline
|
|
144
|
+
this.pipeline = this.device.createRenderPipeline({
|
|
145
|
+
layout: 'auto',
|
|
146
|
+
vertex: {
|
|
147
|
+
module: shaderModule,
|
|
148
|
+
entryPoint: 'vs_main',
|
|
149
|
+
buffers: [
|
|
150
|
+
{
|
|
151
|
+
arrayStride: 24, // 6 floats * 4 bytes
|
|
152
|
+
attributes: [
|
|
153
|
+
{ shaderLocation: 0, offset: 0, format: 'float32x3' }, // position
|
|
154
|
+
{ shaderLocation: 1, offset: 12, format: 'float32x3' }, // normal
|
|
155
|
+
],
|
|
156
|
+
},
|
|
157
|
+
],
|
|
158
|
+
},
|
|
159
|
+
fragment: {
|
|
160
|
+
module: shaderModule,
|
|
161
|
+
entryPoint: 'fs_main',
|
|
162
|
+
targets: [{ format }],
|
|
163
|
+
},
|
|
164
|
+
primitive: {
|
|
165
|
+
topology: 'triangle-list',
|
|
166
|
+
cullMode: 'none', // Disable culling to debug - IFC winding order varies
|
|
167
|
+
},
|
|
168
|
+
depthStencil: {
|
|
169
|
+
format: 'depth24plus',
|
|
170
|
+
depthWriteEnabled: true,
|
|
171
|
+
depthCompare: 'less',
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
// Create bind group using the pipeline's auto-generated layout
|
|
175
|
+
// IMPORTANT: Must use getBindGroupLayout() when pipeline uses layout: 'auto'
|
|
176
|
+
this.bindGroup = this.device.createBindGroup({
|
|
177
|
+
layout: this.pipeline.getBindGroupLayout(0),
|
|
178
|
+
entries: [
|
|
179
|
+
{
|
|
180
|
+
binding: 0,
|
|
181
|
+
resource: { buffer: this.uniformBuffer },
|
|
182
|
+
},
|
|
183
|
+
],
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Update uniform buffer with camera matrices, PBR material, section plane, and selection state
|
|
188
|
+
*/
|
|
189
|
+
updateUniforms(viewProj, model, color, material, sectionPlane, isSelected) {
|
|
190
|
+
// Create buffer with proper alignment:
|
|
191
|
+
// viewProj (16 floats) + model (16 floats) + baseColor (4 floats) + metallicRoughness (2 floats) + padding (2 floats)
|
|
192
|
+
// + sectionPlane (4 floats) + flags (4 u32) = 48 floats = 192 bytes
|
|
193
|
+
const buffer = new Float32Array(48);
|
|
194
|
+
const flagBuffer = new Uint32Array(buffer.buffer, 176, 4); // flags at byte 176
|
|
195
|
+
// viewProj: mat4x4<f32> at offset 0 (16 floats)
|
|
196
|
+
buffer.set(viewProj, 0);
|
|
197
|
+
// model: mat4x4<f32> at offset 16 (16 floats)
|
|
198
|
+
buffer.set(model, 16);
|
|
199
|
+
// baseColor: vec4<f32> at offset 32 (4 floats)
|
|
200
|
+
if (color) {
|
|
201
|
+
buffer.set(color, 32);
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
// Default white color
|
|
205
|
+
buffer.set([1.0, 1.0, 1.0, 1.0], 32);
|
|
206
|
+
}
|
|
207
|
+
// metallicRoughness: vec2<f32> at offset 36 (2 floats)
|
|
208
|
+
const metallic = material?.metallic ?? 0.0;
|
|
209
|
+
const roughness = material?.roughness ?? 0.6;
|
|
210
|
+
buffer[36] = metallic;
|
|
211
|
+
buffer[37] = roughness;
|
|
212
|
+
// padding at offset 38-39 (2 floats)
|
|
213
|
+
// sectionPlane: vec4<f32> at offset 40 (4 floats - normal xyz + distance w)
|
|
214
|
+
if (sectionPlane) {
|
|
215
|
+
buffer[40] = sectionPlane.normal[0];
|
|
216
|
+
buffer[41] = sectionPlane.normal[1];
|
|
217
|
+
buffer[42] = sectionPlane.normal[2];
|
|
218
|
+
buffer[43] = sectionPlane.distance;
|
|
219
|
+
}
|
|
220
|
+
// flags: vec4<u32> at offset 44 (4 u32 - using flagBuffer view)
|
|
221
|
+
flagBuffer[0] = isSelected ? 1 : 0; // isSelected
|
|
222
|
+
flagBuffer[1] = sectionPlane?.enabled ? 1 : 0; // sectionEnabled
|
|
223
|
+
flagBuffer[2] = 0; // reserved
|
|
224
|
+
flagBuffer[3] = 0; // reserved
|
|
225
|
+
// Write the buffer
|
|
226
|
+
this.device.queue.writeBuffer(this.uniformBuffer, 0, buffer);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Check if resize is needed
|
|
230
|
+
*/
|
|
231
|
+
needsResize(width, height) {
|
|
232
|
+
return this.currentWidth !== width || this.currentHeight !== height;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Resize depth texture
|
|
236
|
+
*/
|
|
237
|
+
resize(width, height) {
|
|
238
|
+
if (width <= 0 || height <= 0)
|
|
239
|
+
return;
|
|
240
|
+
this.currentWidth = width;
|
|
241
|
+
this.currentHeight = height;
|
|
242
|
+
this.depthTexture.destroy();
|
|
243
|
+
this.depthTexture = this.device.createTexture({
|
|
244
|
+
size: { width, height },
|
|
245
|
+
format: 'depth24plus',
|
|
246
|
+
usage: GPUTextureUsage.RENDER_ATTACHMENT,
|
|
247
|
+
});
|
|
248
|
+
this.depthTextureView = this.depthTexture.createView();
|
|
249
|
+
}
|
|
250
|
+
getPipeline() {
|
|
251
|
+
return this.pipeline;
|
|
252
|
+
}
|
|
253
|
+
getDepthTextureView() {
|
|
254
|
+
return this.depthTextureView;
|
|
255
|
+
}
|
|
256
|
+
getBindGroup() {
|
|
257
|
+
return this.bindGroup;
|
|
258
|
+
}
|
|
259
|
+
getBindGroupLayout() {
|
|
260
|
+
return this.pipeline.getBindGroupLayout(0);
|
|
261
|
+
}
|
|
262
|
+
getUniformBufferSize() {
|
|
263
|
+
return 192; // 48 floats * 4 bytes
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=pipeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Post-processing effects for Blender-quality rendering
|
|
3
|
+
* Includes SSAO, tone mapping, and edge enhancement
|
|
4
|
+
*/
|
|
5
|
+
import { WebGPUDevice } from './device.js';
|
|
6
|
+
export interface PostProcessorOptions {
|
|
7
|
+
enableSSAO?: boolean;
|
|
8
|
+
enableEdgeEnhancement?: boolean;
|
|
9
|
+
ssaoRadius?: number;
|
|
10
|
+
ssaoIntensity?: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Post-processing pipeline
|
|
14
|
+
* Currently implements enhanced tone mapping in shader
|
|
15
|
+
* SSAO and edge enhancement can be added as separate passes
|
|
16
|
+
*/
|
|
17
|
+
export declare class PostProcessor {
|
|
18
|
+
private _device;
|
|
19
|
+
private options;
|
|
20
|
+
constructor(device: WebGPUDevice, options?: PostProcessorOptions);
|
|
21
|
+
/**
|
|
22
|
+
* Apply post-processing effects
|
|
23
|
+
* Currently tone mapping is handled in the main shader
|
|
24
|
+
* This class provides infrastructure for future SSAO and edge detection
|
|
25
|
+
*/
|
|
26
|
+
apply(_inputTexture: GPUTexture, _outputTexture: GPUTexture): void;
|
|
27
|
+
/**
|
|
28
|
+
* Update post-processing options
|
|
29
|
+
*/
|
|
30
|
+
updateOptions(options: Partial<PostProcessorOptions>): void;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=post-processor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"post-processor.d.ts","sourceRoot":"","sources":["../src/post-processor.ts"],"names":[],"mappings":"AAIA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,oBAAoB;IACjC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;GAIG;AACH,qBAAa,aAAa;IACtB,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,OAAO,CAAuB;gBAE1B,MAAM,EAAE,YAAY,EAAE,OAAO,GAAE,oBAAyB;IAWpE;;;;OAIG;IACH,KAAK,CAAC,aAAa,EAAE,UAAU,EAAE,cAAc,EAAE,UAAU,GAAG,IAAI;IASlE;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG,IAAI;CAG9D"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
/**
|
|
5
|
+
* Post-processing pipeline
|
|
6
|
+
* Currently implements enhanced tone mapping in shader
|
|
7
|
+
* SSAO and edge enhancement can be added as separate passes
|
|
8
|
+
*/
|
|
9
|
+
export class PostProcessor {
|
|
10
|
+
_device;
|
|
11
|
+
options;
|
|
12
|
+
constructor(device, options = {}) {
|
|
13
|
+
this._device = device;
|
|
14
|
+
this.options = {
|
|
15
|
+
enableSSAO: false,
|
|
16
|
+
enableEdgeEnhancement: false,
|
|
17
|
+
ssaoRadius: 0.5,
|
|
18
|
+
ssaoIntensity: 1.0,
|
|
19
|
+
...options,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Apply post-processing effects
|
|
24
|
+
* Currently tone mapping is handled in the main shader
|
|
25
|
+
* This class provides infrastructure for future SSAO and edge detection
|
|
26
|
+
*/
|
|
27
|
+
apply(_inputTexture, _outputTexture) {
|
|
28
|
+
// Tone mapping is already applied in the main PBR shader
|
|
29
|
+
// SSAO and edge enhancement would be implemented here as separate passes
|
|
30
|
+
// Reserved for future use
|
|
31
|
+
void this._device;
|
|
32
|
+
void _inputTexture;
|
|
33
|
+
void _outputTexture;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Update post-processing options
|
|
37
|
+
*/
|
|
38
|
+
updateOptions(options) {
|
|
39
|
+
this.options = { ...this.options, ...options };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=post-processor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"post-processor.js","sourceRoot":"","sources":["../src/post-processor.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAgB/D;;;;GAIG;AACH,MAAM,OAAO,aAAa;IACd,OAAO,CAAe;IACtB,OAAO,CAAuB;IAEtC,YAAY,MAAoB,EAAE,UAAgC,EAAE;QAChE,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,OAAO,GAAG;YACX,UAAU,EAAE,KAAK;YACjB,qBAAqB,EAAE,KAAK;YAC5B,UAAU,EAAE,GAAG;YACf,aAAa,EAAE,GAAG;YAClB,GAAG,OAAO;SACb,CAAC;IACN,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,aAAyB,EAAE,cAA0B;QACvD,yDAAyD;QACzD,yEAAyE;QACzE,0BAA0B;QAC1B,KAAK,IAAI,CAAC,OAAO,CAAC;QAClB,KAAK,aAAa,CAAC;QACnB,KAAK,cAAc,CAAC;IACxB,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,OAAsC;QAChD,IAAI,CAAC,OAAO,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC;IACnD,CAAC;CACJ"}
|
package/dist/scene.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scene graph and mesh management
|
|
3
|
+
*/
|
|
4
|
+
import type { Mesh } from './types.js';
|
|
5
|
+
export declare class Scene {
|
|
6
|
+
private meshes;
|
|
7
|
+
/**
|
|
8
|
+
* Add mesh to scene
|
|
9
|
+
*/
|
|
10
|
+
addMesh(mesh: Mesh): void;
|
|
11
|
+
/**
|
|
12
|
+
* Get all meshes
|
|
13
|
+
*/
|
|
14
|
+
getMeshes(): Mesh[];
|
|
15
|
+
/**
|
|
16
|
+
* Clear scene
|
|
17
|
+
*/
|
|
18
|
+
clear(): void;
|
|
19
|
+
/**
|
|
20
|
+
* Calculate bounding box
|
|
21
|
+
*/
|
|
22
|
+
getBounds(): {
|
|
23
|
+
min: {
|
|
24
|
+
x: number;
|
|
25
|
+
y: number;
|
|
26
|
+
z: number;
|
|
27
|
+
};
|
|
28
|
+
max: {
|
|
29
|
+
x: number;
|
|
30
|
+
y: number;
|
|
31
|
+
z: number;
|
|
32
|
+
};
|
|
33
|
+
} | null;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=scene.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scene.d.ts","sourceRoot":"","sources":["../src/scene.ts"],"names":[],"mappings":"AAIA;;GAEG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,qBAAa,KAAK;IAChB,OAAO,CAAC,MAAM,CAAc;IAE5B;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAIzB;;OAEG;IACH,SAAS,IAAI,IAAI,EAAE;IAInB;;OAEG;IACH,KAAK,IAAI,IAAI;IAYb;;OAEG;IACH,SAAS,IAAI;QAAE,GAAG,EAAE;YAAE,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAAC,GAAG,EAAE;YAAE,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,GAAG,IAAI;CAU3G"}
|