3d-spinner 0.9.4 → 0.9.6
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/animations/charged-orb.js +4 -2
- package/dist/animations/ghost-train.d.ts +1 -1
- package/dist/animations/ghost-train.js +3 -1
- package/dist/animations/grid-assembly.d.ts +1 -1
- package/dist/animations/spin.d.ts +3 -1
- package/dist/animations/spin.js +6 -1
- package/dist/cjs/animations/charged-orb.cjs +177 -30
- package/dist/cjs/animations/grid-assembly.cjs +171 -28
- package/dist/cjs/animations/object-motion.cjs +163 -26
- package/dist/cjs/animations/particles.cjs +181 -30
- package/dist/cjs/animations/spin.cjs +176 -29
- package/dist/cjs/engines/little-3d-engine/little-3d-engine.cjs +200 -47
- package/dist/cjs/engines/little-3d-engine/loaders/obj.cjs +51 -13
- package/dist/cjs/engines/little-3d-engine/renderers/canvas2d-textured.cjs +56 -6
- package/dist/cjs/engines/little-3d-engine/renderers/webgl-textured.cjs +69 -10
- package/dist/cjs/engines/little-3d-engine/renderers/webgpu-textured.cjs +64 -11
- package/dist/cjs/prefabs/prefabs.cjs +200 -44
- package/dist/engines/little-3d-engine/core/geometry.d.ts +15 -2
- package/dist/engines/little-3d-engine/core/geometry.js +25 -3
- package/dist/engines/little-3d-engine/core/light.d.ts +28 -4
- package/dist/engines/little-3d-engine/core/light.js +48 -7
- package/dist/engines/little-3d-engine/core/mesh.d.ts +33 -0
- package/dist/engines/little-3d-engine/core/mesh.js +12 -0
- package/dist/engines/little-3d-engine/little-3d-engine.d.ts +2 -2
- package/dist/engines/little-3d-engine/little-3d-engine.js +1 -1
- package/dist/engines/little-3d-engine/loaders/obj.d.ts +8 -7
- package/dist/engines/little-3d-engine/loaders/obj.js +74 -20
- package/dist/engines/little-3d-engine/renderers/canvas2d.js +23 -1
- package/dist/engines/little-3d-engine/renderers/webgl-textured.js +8 -3
- package/dist/engines/little-3d-engine/renderers/webgl.js +41 -7
- package/dist/engines/little-3d-engine/renderers/webgpu.js +43 -10
- package/dist/engines/little-3d-engine/shapes/complex/plane.d.ts +8 -3
- package/dist/engines/little-3d-engine/shapes/complex/plane.js +10 -4
- package/dist/engines/little-3d-engine/shapes/primitives/cube.d.ts +3 -2
- package/dist/engines/little-3d-engine/shapes/primitives/cube.js +4 -2
- package/dist/engines/little-3d-engine/shapes/primitives/octahedron.d.ts +3 -2
- package/dist/engines/little-3d-engine/shapes/primitives/octahedron.js +4 -2
- package/dist/engines/little-3d-engine/shapes/primitives/pyramid.d.ts +3 -2
- package/dist/engines/little-3d-engine/shapes/primitives/pyramid.js +4 -2
- package/dist/engines/little-3d-engine/shapes/primitives/quad.d.ts +3 -2
- package/dist/engines/little-3d-engine/shapes/primitives/quad.js +4 -2
- package/dist/engines/little-3d-engine/shapes/primitives/spheres/cube-sphere.d.ts +3 -2
- package/dist/engines/little-3d-engine/shapes/primitives/spheres/cube-sphere.js +4 -2
- package/dist/engines/little-3d-engine/shapes/primitives/spheres/icosphere.d.ts +3 -2
- package/dist/engines/little-3d-engine/shapes/primitives/spheres/icosphere.js +4 -2
- package/dist/engines/little-3d-engine/shapes/primitives/spheres/octa-sphere.d.ts +3 -2
- package/dist/engines/little-3d-engine/shapes/primitives/spheres/octa-sphere.js +4 -2
- package/dist/engines/little-3d-engine/shapes/primitives/spheres/uv-sphere.d.ts +3 -2
- package/dist/engines/little-3d-engine/shapes/primitives/spheres/uv-sphere.js +4 -2
- package/dist/engines/little-3d-engine/shapes/primitives/tetrahedron.d.ts +3 -2
- package/dist/engines/little-3d-engine/shapes/primitives/tetrahedron.js +4 -2
- package/dist/umd/spinner.global.js +271 -67
- package/dist/umd/spinner.global.min.js +58 -17
- package/package.json +1 -1
|
@@ -136,7 +136,10 @@ function expandToTriangles(mesh) {
|
|
|
136
136
|
const positions = new Float32Array(triangles * 9);
|
|
137
137
|
const normals = new Float32Array(triangles * 9);
|
|
138
138
|
const colors = new Float32Array(triangles * 9);
|
|
139
|
+
const emissives = new Float32Array(triangles * 9);
|
|
140
|
+
const speculars = new Float32Array(triangles * 12);
|
|
139
141
|
let o = 0;
|
|
142
|
+
let so = 0;
|
|
140
143
|
for (const face of mesh.faces) {
|
|
141
144
|
const v0 = mesh.vertices[face.indices[0]];
|
|
142
145
|
const v1 = mesh.vertices[face.indices[1]];
|
|
@@ -146,6 +149,15 @@ function expandToTriangles(mesh) {
|
|
|
146
149
|
const cr = r / 255;
|
|
147
150
|
const cg = g / 255;
|
|
148
151
|
const cb = b / 255;
|
|
152
|
+
const emissive = face.material?.emissive;
|
|
153
|
+
const er = emissive ? emissive[0] : 0;
|
|
154
|
+
const eg = emissive ? emissive[1] : 0;
|
|
155
|
+
const eb = emissive ? emissive[2] : 0;
|
|
156
|
+
const specular = face.material?.specular;
|
|
157
|
+
const sr = specular ? specular[0] : 0;
|
|
158
|
+
const sg = specular ? specular[1] : 0;
|
|
159
|
+
const sb = specular ? specular[2] : 0;
|
|
160
|
+
const sn = specular ? face.material?.shininess ?? 32 : 1;
|
|
149
161
|
for (let k = 1; k < face.indices.length - 1; k++) {
|
|
150
162
|
const tri = [face.indices[0], face.indices[k], face.indices[k + 1]];
|
|
151
163
|
for (const index of tri) {
|
|
@@ -159,11 +171,19 @@ function expandToTriangles(mesh) {
|
|
|
159
171
|
colors[o] = cr;
|
|
160
172
|
colors[o + 1] = cg;
|
|
161
173
|
colors[o + 2] = cb;
|
|
174
|
+
emissives[o] = er;
|
|
175
|
+
emissives[o + 1] = eg;
|
|
176
|
+
emissives[o + 2] = eb;
|
|
177
|
+
speculars[so] = sr;
|
|
178
|
+
speculars[so + 1] = sg;
|
|
179
|
+
speculars[so + 2] = sb;
|
|
180
|
+
speculars[so + 3] = sn;
|
|
162
181
|
o += 3;
|
|
182
|
+
so += 4;
|
|
163
183
|
}
|
|
164
184
|
}
|
|
165
185
|
}
|
|
166
|
-
return { positions, normals, colors, count: positions.length / 3 };
|
|
186
|
+
return { positions, normals, colors, emissives, speculars, count: positions.length / 3 };
|
|
167
187
|
}
|
|
168
188
|
var init_geometry = __esm({
|
|
169
189
|
"src/engines/little-3d-engine/core/geometry.ts"() {
|
|
@@ -176,13 +196,42 @@ var init_geometry = __esm({
|
|
|
176
196
|
function clamp01(value) {
|
|
177
197
|
return Math.min(1, Math.max(0, value));
|
|
178
198
|
}
|
|
179
|
-
function
|
|
199
|
+
function clamp255(value) {
|
|
200
|
+
return Math.round(Math.min(255, Math.max(0, value)));
|
|
201
|
+
}
|
|
202
|
+
function shade(normal, color, light, surface) {
|
|
180
203
|
const lambert = Math.max(0, dot(normal, light.toLight));
|
|
181
204
|
const brightness = clamp01(light.ambient + light.intensity * lambert);
|
|
182
|
-
const [
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
205
|
+
const [baseR, baseG, baseB] = parseColor(color);
|
|
206
|
+
let r = baseR * brightness;
|
|
207
|
+
let g = baseG * brightness;
|
|
208
|
+
let b = baseB * brightness;
|
|
209
|
+
const material = surface?.material;
|
|
210
|
+
const specular = material?.specular;
|
|
211
|
+
const viewDir = surface?.viewDir;
|
|
212
|
+
if (specular && viewDir && lambert > 0) {
|
|
213
|
+
const half = normalize({
|
|
214
|
+
x: light.toLight.x + viewDir.x,
|
|
215
|
+
y: light.toLight.y + viewDir.y,
|
|
216
|
+
z: light.toLight.z + viewDir.z
|
|
217
|
+
});
|
|
218
|
+
const shininess = material?.shininess ?? 32;
|
|
219
|
+
const highlight = Math.pow(Math.max(0, dot(normal, half)), shininess) * light.intensity * 255;
|
|
220
|
+
r += highlight * specular[0];
|
|
221
|
+
g += highlight * specular[1];
|
|
222
|
+
b += highlight * specular[2];
|
|
223
|
+
}
|
|
224
|
+
const emissive = material?.emissive;
|
|
225
|
+
if (emissive) {
|
|
226
|
+
r += emissive[0] * 255;
|
|
227
|
+
g += emissive[1] * 255;
|
|
228
|
+
b += emissive[2] * 255;
|
|
229
|
+
}
|
|
230
|
+
return [clamp255(r), clamp255(g), clamp255(b)];
|
|
231
|
+
}
|
|
232
|
+
function shadeColor(normal, color, light, surface) {
|
|
233
|
+
const [r, g, b] = shade(normal, color, light, surface);
|
|
234
|
+
return `rgb(${r}, ${g}, ${b})`;
|
|
186
235
|
}
|
|
187
236
|
var DEFAULTS2, Light;
|
|
188
237
|
var init_light = __esm({
|
|
@@ -205,8 +254,8 @@ var init_light = __esm({
|
|
|
205
254
|
};
|
|
206
255
|
}
|
|
207
256
|
/** Convenience wrapper around {@link shadeColor} using this light. */
|
|
208
|
-
shade(normal, color) {
|
|
209
|
-
return shadeColor(normal, color, this.params);
|
|
257
|
+
shade(normal, color, surface) {
|
|
258
|
+
return shadeColor(normal, color, this.params, surface);
|
|
210
259
|
}
|
|
211
260
|
};
|
|
212
261
|
}
|
|
@@ -246,28 +295,51 @@ var init_webgl = __esm({
|
|
|
246
295
|
in vec3 aPos;
|
|
247
296
|
in vec3 aNormal;
|
|
248
297
|
in vec3 aColor;
|
|
298
|
+
in vec3 aEmissive;
|
|
299
|
+
in vec4 aSpecular;
|
|
249
300
|
uniform mat4 uViewProj;
|
|
250
301
|
uniform mat4 uModel;
|
|
251
302
|
out vec3 vNormal;
|
|
252
303
|
out vec3 vColor;
|
|
304
|
+
out vec3 vEmissive;
|
|
305
|
+
out vec4 vSpecular;
|
|
306
|
+
out vec3 vWorldPos;
|
|
253
307
|
void main() {
|
|
254
308
|
vNormal = mat3(uModel) * aNormal;
|
|
255
309
|
vColor = aColor;
|
|
256
|
-
|
|
310
|
+
vEmissive = aEmissive;
|
|
311
|
+
vSpecular = aSpecular;
|
|
312
|
+
vec4 world = uModel * vec4(aPos, 1.0);
|
|
313
|
+
vWorldPos = world.xyz;
|
|
314
|
+
gl_Position = uViewProj * world;
|
|
257
315
|
}`;
|
|
258
316
|
FRAGMENT_SHADER = `#version 300 es
|
|
259
317
|
precision mediump float;
|
|
260
318
|
in vec3 vNormal;
|
|
261
319
|
in vec3 vColor;
|
|
320
|
+
in vec3 vEmissive;
|
|
321
|
+
in vec4 vSpecular;
|
|
322
|
+
in vec3 vWorldPos;
|
|
262
323
|
uniform vec3 uToLight;
|
|
324
|
+
uniform vec3 uEye;
|
|
263
325
|
uniform float uIntensity;
|
|
264
326
|
uniform float uAmbient;
|
|
265
327
|
uniform float uOpacity;
|
|
266
328
|
out vec4 fragColor;
|
|
267
329
|
void main() {
|
|
268
|
-
|
|
330
|
+
vec3 normal = normalize(vNormal);
|
|
331
|
+
vec3 toLight = normalize(uToLight);
|
|
332
|
+
float lambert = max(dot(normal, toLight), 0.0);
|
|
269
333
|
float brightness = clamp(uAmbient + uIntensity * lambert, 0.0, 1.0);
|
|
270
|
-
|
|
334
|
+
vec3 lit = vColor * brightness;
|
|
335
|
+
if (lambert > 0.0) {
|
|
336
|
+
vec3 viewDir = normalize(uEye - vWorldPos);
|
|
337
|
+
vec3 halfVec = normalize(toLight + viewDir);
|
|
338
|
+
float highlight = pow(max(dot(normal, halfVec), 0.0), vSpecular.w) * uIntensity;
|
|
339
|
+
lit += highlight * vSpecular.xyz;
|
|
340
|
+
}
|
|
341
|
+
lit += vEmissive;
|
|
342
|
+
fragColor = vec4(lit, uOpacity);
|
|
271
343
|
}`;
|
|
272
344
|
WebGLRenderer = class {
|
|
273
345
|
constructor(options = {}) {
|
|
@@ -288,9 +360,12 @@ void main() {
|
|
|
288
360
|
aPos: gl.getAttribLocation(this.program, "aPos"),
|
|
289
361
|
aNormal: gl.getAttribLocation(this.program, "aNormal"),
|
|
290
362
|
aColor: gl.getAttribLocation(this.program, "aColor"),
|
|
363
|
+
aEmissive: gl.getAttribLocation(this.program, "aEmissive"),
|
|
364
|
+
aSpecular: gl.getAttribLocation(this.program, "aSpecular"),
|
|
291
365
|
uViewProj: gl.getUniformLocation(this.program, "uViewProj"),
|
|
292
366
|
uModel: gl.getUniformLocation(this.program, "uModel"),
|
|
293
367
|
uToLight: gl.getUniformLocation(this.program, "uToLight"),
|
|
368
|
+
uEye: gl.getUniformLocation(this.program, "uEye"),
|
|
294
369
|
uIntensity: gl.getUniformLocation(this.program, "uIntensity"),
|
|
295
370
|
uAmbient: gl.getUniformLocation(this.program, "uAmbient"),
|
|
296
371
|
uOpacity: gl.getUniformLocation(this.program, "uOpacity")
|
|
@@ -314,19 +389,23 @@ void main() {
|
|
|
314
389
|
const data = expandToTriangles(mesh);
|
|
315
390
|
const vao = gl.createVertexArray();
|
|
316
391
|
gl.bindVertexArray(vao);
|
|
317
|
-
const
|
|
392
|
+
const buffers = [];
|
|
393
|
+
const attribute = (location, array, size = 3) => {
|
|
318
394
|
if (location < 0) return;
|
|
319
395
|
const buffer = gl.createBuffer();
|
|
396
|
+
buffers.push(buffer);
|
|
320
397
|
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
321
398
|
gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW);
|
|
322
399
|
gl.enableVertexAttribArray(location);
|
|
323
|
-
gl.vertexAttribPointer(location,
|
|
400
|
+
gl.vertexAttribPointer(location, size, gl.FLOAT, false, 0, 0);
|
|
324
401
|
};
|
|
325
402
|
attribute(loc.aPos, data.positions);
|
|
326
403
|
attribute(loc.aNormal, data.normals);
|
|
327
404
|
attribute(loc.aColor, data.colors);
|
|
405
|
+
attribute(loc.aEmissive, data.emissives);
|
|
406
|
+
attribute(loc.aSpecular, data.speculars, 4);
|
|
328
407
|
gl.bindVertexArray(null);
|
|
329
|
-
const result = { vao, count: data.count };
|
|
408
|
+
const result = { vao, buffers, count: data.count };
|
|
330
409
|
this.cache.set(mesh, result);
|
|
331
410
|
return result;
|
|
332
411
|
}
|
|
@@ -339,6 +418,7 @@ void main() {
|
|
|
339
418
|
gl.useProgram(this.program);
|
|
340
419
|
gl.uniformMatrix4fv(loc.uViewProj, false, new Float32Array(frame.viewProjection));
|
|
341
420
|
gl.uniform3f(loc.uToLight, frame.light.toLight.x, frame.light.toLight.y, frame.light.toLight.z);
|
|
421
|
+
gl.uniform3f(loc.uEye, frame.eye.x, frame.eye.y, frame.eye.z);
|
|
342
422
|
gl.uniform1f(loc.uIntensity, frame.light.intensity);
|
|
343
423
|
gl.uniform1f(loc.uAmbient, frame.light.ambient);
|
|
344
424
|
gl.disable(gl.BLEND);
|
|
@@ -383,7 +463,10 @@ void main() {
|
|
|
383
463
|
destroy() {
|
|
384
464
|
const gl = this.gl;
|
|
385
465
|
if (gl) {
|
|
386
|
-
for (const mesh of this.cache.values())
|
|
466
|
+
for (const mesh of this.cache.values()) {
|
|
467
|
+
gl.deleteVertexArray(mesh.vao);
|
|
468
|
+
for (const buffer of mesh.buffers) gl.deleteBuffer(buffer);
|
|
469
|
+
}
|
|
387
470
|
if (this.program) gl.deleteProgram(this.program);
|
|
388
471
|
}
|
|
389
472
|
this.cache.clear();
|
|
@@ -413,6 +496,7 @@ struct Uniforms {
|
|
|
413
496
|
model: mat4x4<f32>,
|
|
414
497
|
toLight: vec4<f32>,
|
|
415
498
|
params: vec4<f32>,
|
|
499
|
+
eye: vec4<f32>,
|
|
416
500
|
};
|
|
417
501
|
@group(0) @binding(0) var<uniform> u: Uniforms;
|
|
418
502
|
|
|
@@ -420,23 +504,40 @@ struct VSOut {
|
|
|
420
504
|
@builtin(position) position: vec4<f32>,
|
|
421
505
|
@location(0) normal: vec3<f32>,
|
|
422
506
|
@location(1) color: vec3<f32>,
|
|
507
|
+
@location(2) emissive: vec3<f32>,
|
|
508
|
+
@location(3) specular: vec4<f32>,
|
|
509
|
+
@location(4) worldPos: vec3<f32>,
|
|
423
510
|
};
|
|
424
511
|
|
|
425
512
|
@vertex
|
|
426
|
-
fn vs(@location(0) pos: vec3<f32>, @location(1) normal: vec3<f32>, @location(2) color: vec3<f32>) -> VSOut {
|
|
513
|
+
fn vs(@location(0) pos: vec3<f32>, @location(1) normal: vec3<f32>, @location(2) color: vec3<f32>, @location(3) emissive: vec3<f32>, @location(4) specular: vec4<f32>) -> VSOut {
|
|
427
514
|
var out: VSOut;
|
|
428
515
|
let m = mat3x3<f32>(u.model[0].xyz, u.model[1].xyz, u.model[2].xyz);
|
|
429
516
|
out.normal = m * normal;
|
|
430
517
|
out.color = color;
|
|
431
|
-
out.
|
|
518
|
+
out.emissive = emissive;
|
|
519
|
+
out.specular = specular;
|
|
520
|
+
let world = u.model * vec4<f32>(pos, 1.0);
|
|
521
|
+
out.worldPos = world.xyz;
|
|
522
|
+
out.position = u.viewProj * world;
|
|
432
523
|
return out;
|
|
433
524
|
}
|
|
434
525
|
|
|
435
526
|
@fragment
|
|
436
527
|
fn fs(in: VSOut) -> @location(0) vec4<f32> {
|
|
437
|
-
let
|
|
528
|
+
let normal = normalize(in.normal);
|
|
529
|
+
let toLight = normalize(u.toLight.xyz);
|
|
530
|
+
let lambert = max(dot(normal, toLight), 0.0);
|
|
438
531
|
let brightness = clamp(u.params.y + u.params.x * lambert, 0.0, 1.0);
|
|
439
|
-
|
|
532
|
+
var lit = in.color * brightness;
|
|
533
|
+
if (lambert > 0.0) {
|
|
534
|
+
let viewDir = normalize(u.eye.xyz - in.worldPos);
|
|
535
|
+
let halfVec = normalize(toLight + viewDir);
|
|
536
|
+
let highlight = pow(max(dot(normal, halfVec), 0.0), in.specular.w) * u.params.x;
|
|
537
|
+
lit = lit + highlight * in.specular.xyz;
|
|
538
|
+
}
|
|
539
|
+
lit = lit + in.emissive;
|
|
540
|
+
return vec4<f32>(lit, u.params.z);
|
|
440
541
|
}
|
|
441
542
|
`;
|
|
442
543
|
CLIP_Z_FIX = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 1];
|
|
@@ -477,13 +578,15 @@ fn fs(in: VSOut) -> @location(0) vec4<f32> {
|
|
|
477
578
|
{
|
|
478
579
|
binding: 0,
|
|
479
580
|
visibility: stage.VERTEX | stage.FRAGMENT,
|
|
480
|
-
buffer: { type: "uniform", hasDynamicOffset: true, minBindingSize:
|
|
581
|
+
buffer: { type: "uniform", hasDynamicOffset: true, minBindingSize: 176 }
|
|
481
582
|
}
|
|
482
583
|
]
|
|
483
584
|
});
|
|
484
|
-
const vertexBuffer = (location) => ({
|
|
485
|
-
arrayStride:
|
|
486
|
-
attributes: [
|
|
585
|
+
const vertexBuffer = (location, components = 3) => ({
|
|
586
|
+
arrayStride: components * 4,
|
|
587
|
+
attributes: [
|
|
588
|
+
{ shaderLocation: location, offset: 0, format: `float32x${components}` }
|
|
589
|
+
]
|
|
487
590
|
});
|
|
488
591
|
const pipelineLayout = device.createPipelineLayout({ bindGroupLayouts: [layout] });
|
|
489
592
|
const blend = {
|
|
@@ -499,7 +602,13 @@ fn fs(in: VSOut) -> @location(0) vec4<f32> {
|
|
|
499
602
|
vertex: {
|
|
500
603
|
module: module2,
|
|
501
604
|
entryPoint: "vs",
|
|
502
|
-
buffers: [
|
|
605
|
+
buffers: [
|
|
606
|
+
vertexBuffer(0),
|
|
607
|
+
vertexBuffer(1),
|
|
608
|
+
vertexBuffer(2),
|
|
609
|
+
vertexBuffer(3),
|
|
610
|
+
vertexBuffer(4, 4)
|
|
611
|
+
]
|
|
503
612
|
},
|
|
504
613
|
fragment: {
|
|
505
614
|
module: module2,
|
|
@@ -552,6 +661,8 @@ fn fs(in: VSOut) -> @location(0) vec4<f32> {
|
|
|
552
661
|
position: upload(data.positions),
|
|
553
662
|
normal: upload(data.normals),
|
|
554
663
|
color: upload(data.colors),
|
|
664
|
+
emissive: upload(data.emissives),
|
|
665
|
+
specular: upload(data.speculars),
|
|
555
666
|
count: data.count
|
|
556
667
|
};
|
|
557
668
|
this.cache.set(mesh, result);
|
|
@@ -603,7 +714,7 @@ fn fs(in: VSOut) -> @location(0) vec4<f32> {
|
|
|
603
714
|
const bindGroup = this.device.createBindGroup({
|
|
604
715
|
layout,
|
|
605
716
|
entries: [
|
|
606
|
-
{ binding: 0, resource: { buffer: this.uniformBuffer, offset: 0, size:
|
|
717
|
+
{ binding: 0, resource: { buffer: this.uniformBuffer, offset: 0, size: 176 } }
|
|
607
718
|
]
|
|
608
719
|
});
|
|
609
720
|
draws.forEach((draw, i) => {
|
|
@@ -612,6 +723,7 @@ fn fs(in: VSOut) -> @location(0) vec4<f32> {
|
|
|
612
723
|
data.set(draw.item.model, 16);
|
|
613
724
|
data.set([frame.light.toLight.x, frame.light.toLight.y, frame.light.toLight.z, 0], 32);
|
|
614
725
|
data.set([frame.light.intensity, frame.light.ambient, draw.opacity, 0], 36);
|
|
726
|
+
data.set([frame.eye.x, frame.eye.y, frame.eye.z, 0], 40);
|
|
615
727
|
this.device.queue.writeBuffer(this.uniformBuffer, i * UNIFORM_STRIDE, data);
|
|
616
728
|
});
|
|
617
729
|
const encoder = this.device.createCommandEncoder();
|
|
@@ -638,6 +750,8 @@ fn fs(in: VSOut) -> @location(0) vec4<f32> {
|
|
|
638
750
|
pass.setVertexBuffer(0, mesh.position);
|
|
639
751
|
pass.setVertexBuffer(1, mesh.normal);
|
|
640
752
|
pass.setVertexBuffer(2, mesh.color);
|
|
753
|
+
pass.setVertexBuffer(3, mesh.emissive);
|
|
754
|
+
pass.setVertexBuffer(4, mesh.specular);
|
|
641
755
|
pass.draw(mesh.count);
|
|
642
756
|
});
|
|
643
757
|
pass.end();
|
|
@@ -649,6 +763,8 @@ fn fs(in: VSOut) -> @location(0) vec4<f32> {
|
|
|
649
763
|
mesh.position.destroy?.();
|
|
650
764
|
mesh.normal.destroy?.();
|
|
651
765
|
mesh.color.destroy?.();
|
|
766
|
+
mesh.emissive.destroy?.();
|
|
767
|
+
mesh.specular.destroy?.();
|
|
652
768
|
}
|
|
653
769
|
this.cache.clear();
|
|
654
770
|
this.uniformBuffer?.destroy?.();
|
|
@@ -731,9 +847,30 @@ var init_canvas2d = __esm({
|
|
|
731
847
|
depth += dot(d, d);
|
|
732
848
|
}
|
|
733
849
|
depth /= face.indices.length;
|
|
850
|
+
let surface;
|
|
851
|
+
const material = face.material;
|
|
852
|
+
if (material) {
|
|
853
|
+
if (material.specular) {
|
|
854
|
+
let cx = 0;
|
|
855
|
+
let cy = 0;
|
|
856
|
+
let cz = 0;
|
|
857
|
+
for (const i of face.indices) {
|
|
858
|
+
cx += world[i].x;
|
|
859
|
+
cy += world[i].y;
|
|
860
|
+
cz += world[i].z;
|
|
861
|
+
}
|
|
862
|
+
const inv = 1 / face.indices.length;
|
|
863
|
+
const viewDir = normalize(
|
|
864
|
+
subtract(frame.eye, { x: cx * inv, y: cy * inv, z: cz * inv })
|
|
865
|
+
);
|
|
866
|
+
surface = { material, viewDir };
|
|
867
|
+
} else {
|
|
868
|
+
surface = { material };
|
|
869
|
+
}
|
|
870
|
+
}
|
|
734
871
|
polygons.push({
|
|
735
872
|
points,
|
|
736
|
-
color: shadeColor(normal, face.color, frame.light),
|
|
873
|
+
color: shadeColor(normal, face.color, frame.light, surface),
|
|
737
874
|
depth,
|
|
738
875
|
opacity: faceOpacity
|
|
739
876
|
});
|
|
@@ -1271,9 +1408,11 @@ void main() {
|
|
|
1271
1408
|
const data = expandToTriangles(mesh);
|
|
1272
1409
|
const vao = gl.createVertexArray();
|
|
1273
1410
|
gl.bindVertexArray(vao);
|
|
1411
|
+
const buffers = [];
|
|
1274
1412
|
const attribute = (location, array, size) => {
|
|
1275
1413
|
if (location < 0) return;
|
|
1276
1414
|
const buffer = gl.createBuffer();
|
|
1415
|
+
buffers.push(buffer);
|
|
1277
1416
|
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
1278
1417
|
gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW);
|
|
1279
1418
|
gl.enableVertexAttribArray(location);
|
|
@@ -1283,7 +1422,7 @@ void main() {
|
|
|
1283
1422
|
attribute(loc.aColor, data.colors, 3);
|
|
1284
1423
|
attribute(loc.aUV, planarUVs(mesh), 2);
|
|
1285
1424
|
gl.bindVertexArray(null);
|
|
1286
|
-
const result = { vao, count: data.count };
|
|
1425
|
+
const result = { vao, buffers, count: data.count };
|
|
1287
1426
|
this.buffers.set(mesh, result);
|
|
1288
1427
|
return result;
|
|
1289
1428
|
}
|
|
@@ -1321,7 +1460,10 @@ void main() {
|
|
|
1321
1460
|
const gl = this.gl;
|
|
1322
1461
|
if (gl) {
|
|
1323
1462
|
for (const texture of this.textures.values()) gl.deleteTexture(texture);
|
|
1324
|
-
for (const
|
|
1463
|
+
for (const cached of this.buffers.values()) {
|
|
1464
|
+
gl.deleteVertexArray(cached.vao);
|
|
1465
|
+
for (const buffer of cached.buffers) gl.deleteBuffer(buffer);
|
|
1466
|
+
}
|
|
1325
1467
|
if (this.program) gl.deleteProgram(this.program);
|
|
1326
1468
|
}
|
|
1327
1469
|
this.textures.clear();
|
|
@@ -1557,6 +1699,12 @@ init_light();
|
|
|
1557
1699
|
init_math();
|
|
1558
1700
|
|
|
1559
1701
|
// src/engines/little-3d-engine/core/mesh.ts
|
|
1702
|
+
function attachMaterial(mesh, material) {
|
|
1703
|
+
if (material) {
|
|
1704
|
+
for (const face of mesh.faces) face.material = material;
|
|
1705
|
+
}
|
|
1706
|
+
return mesh;
|
|
1707
|
+
}
|
|
1560
1708
|
function transform(init) {
|
|
1561
1709
|
return {
|
|
1562
1710
|
position: init?.position ?? { x: 0, y: 0, z: 0 },
|
|
@@ -1571,7 +1719,7 @@ init_light();
|
|
|
1571
1719
|
|
|
1572
1720
|
// src/engines/little-3d-engine/shapes/primitives/quad.ts
|
|
1573
1721
|
var DEFAULT_COLORS = ["#3b82f6"];
|
|
1574
|
-
function quad(size = 1, colors = DEFAULT_COLORS) {
|
|
1722
|
+
function quad(size = 1, colors = DEFAULT_COLORS, material) {
|
|
1575
1723
|
const s = size / 2;
|
|
1576
1724
|
const vertices = [
|
|
1577
1725
|
{ x: -s, y: -s, z: 0 },
|
|
@@ -1579,7 +1727,10 @@ function quad(size = 1, colors = DEFAULT_COLORS) {
|
|
|
1579
1727
|
{ x: s, y: s, z: 0 },
|
|
1580
1728
|
{ x: -s, y: s, z: 0 }
|
|
1581
1729
|
];
|
|
1582
|
-
return
|
|
1730
|
+
return attachMaterial(
|
|
1731
|
+
{ vertices, faces: [{ indices: [0, 1, 2, 3], color: colors[0] }] },
|
|
1732
|
+
material
|
|
1733
|
+
);
|
|
1583
1734
|
}
|
|
1584
1735
|
|
|
1585
1736
|
// src/engines/little-3d-engine/shapes/primitives/spheres/icosphere.ts
|