3d-spinner 0.9.4 → 0.9.5
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.js +3 -1
- package/dist/animations/spin.d.ts +3 -1
- package/dist/animations/spin.js +6 -1
- package/dist/cjs/animations/charged-orb.cjs +170 -28
- package/dist/cjs/animations/grid-assembly.cjs +164 -26
- package/dist/cjs/animations/object-motion.cjs +156 -24
- package/dist/cjs/animations/particles.cjs +167 -26
- package/dist/cjs/animations/spin.cjs +169 -27
- package/dist/cjs/engines/little-3d-engine/little-3d-engine.cjs +193 -45
- 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 +55 -6
- package/dist/cjs/engines/little-3d-engine/renderers/webgpu-textured.cjs +64 -11
- package/dist/cjs/prefabs/prefabs.cjs +186 -40
- 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.js +34 -5
- 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 +255 -63
- 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,17 +389,19 @@ void main() {
|
|
|
314
389
|
const data = expandToTriangles(mesh);
|
|
315
390
|
const vao = gl.createVertexArray();
|
|
316
391
|
gl.bindVertexArray(vao);
|
|
317
|
-
const attribute = (location, array) => {
|
|
392
|
+
const attribute = (location, array, size = 3) => {
|
|
318
393
|
if (location < 0) return;
|
|
319
394
|
const buffer = gl.createBuffer();
|
|
320
395
|
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
321
396
|
gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW);
|
|
322
397
|
gl.enableVertexAttribArray(location);
|
|
323
|
-
gl.vertexAttribPointer(location,
|
|
398
|
+
gl.vertexAttribPointer(location, size, gl.FLOAT, false, 0, 0);
|
|
324
399
|
};
|
|
325
400
|
attribute(loc.aPos, data.positions);
|
|
326
401
|
attribute(loc.aNormal, data.normals);
|
|
327
402
|
attribute(loc.aColor, data.colors);
|
|
403
|
+
attribute(loc.aEmissive, data.emissives);
|
|
404
|
+
attribute(loc.aSpecular, data.speculars, 4);
|
|
328
405
|
gl.bindVertexArray(null);
|
|
329
406
|
const result = { vao, count: data.count };
|
|
330
407
|
this.cache.set(mesh, result);
|
|
@@ -339,6 +416,7 @@ void main() {
|
|
|
339
416
|
gl.useProgram(this.program);
|
|
340
417
|
gl.uniformMatrix4fv(loc.uViewProj, false, new Float32Array(frame.viewProjection));
|
|
341
418
|
gl.uniform3f(loc.uToLight, frame.light.toLight.x, frame.light.toLight.y, frame.light.toLight.z);
|
|
419
|
+
gl.uniform3f(loc.uEye, frame.eye.x, frame.eye.y, frame.eye.z);
|
|
342
420
|
gl.uniform1f(loc.uIntensity, frame.light.intensity);
|
|
343
421
|
gl.uniform1f(loc.uAmbient, frame.light.ambient);
|
|
344
422
|
gl.disable(gl.BLEND);
|
|
@@ -413,6 +491,7 @@ struct Uniforms {
|
|
|
413
491
|
model: mat4x4<f32>,
|
|
414
492
|
toLight: vec4<f32>,
|
|
415
493
|
params: vec4<f32>,
|
|
494
|
+
eye: vec4<f32>,
|
|
416
495
|
};
|
|
417
496
|
@group(0) @binding(0) var<uniform> u: Uniforms;
|
|
418
497
|
|
|
@@ -420,23 +499,40 @@ struct VSOut {
|
|
|
420
499
|
@builtin(position) position: vec4<f32>,
|
|
421
500
|
@location(0) normal: vec3<f32>,
|
|
422
501
|
@location(1) color: vec3<f32>,
|
|
502
|
+
@location(2) emissive: vec3<f32>,
|
|
503
|
+
@location(3) specular: vec4<f32>,
|
|
504
|
+
@location(4) worldPos: vec3<f32>,
|
|
423
505
|
};
|
|
424
506
|
|
|
425
507
|
@vertex
|
|
426
|
-
fn vs(@location(0) pos: vec3<f32>, @location(1) normal: vec3<f32>, @location(2) color: vec3<f32>) -> VSOut {
|
|
508
|
+
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
509
|
var out: VSOut;
|
|
428
510
|
let m = mat3x3<f32>(u.model[0].xyz, u.model[1].xyz, u.model[2].xyz);
|
|
429
511
|
out.normal = m * normal;
|
|
430
512
|
out.color = color;
|
|
431
|
-
out.
|
|
513
|
+
out.emissive = emissive;
|
|
514
|
+
out.specular = specular;
|
|
515
|
+
let world = u.model * vec4<f32>(pos, 1.0);
|
|
516
|
+
out.worldPos = world.xyz;
|
|
517
|
+
out.position = u.viewProj * world;
|
|
432
518
|
return out;
|
|
433
519
|
}
|
|
434
520
|
|
|
435
521
|
@fragment
|
|
436
522
|
fn fs(in: VSOut) -> @location(0) vec4<f32> {
|
|
437
|
-
let
|
|
523
|
+
let normal = normalize(in.normal);
|
|
524
|
+
let toLight = normalize(u.toLight.xyz);
|
|
525
|
+
let lambert = max(dot(normal, toLight), 0.0);
|
|
438
526
|
let brightness = clamp(u.params.y + u.params.x * lambert, 0.0, 1.0);
|
|
439
|
-
|
|
527
|
+
var lit = in.color * brightness;
|
|
528
|
+
if (lambert > 0.0) {
|
|
529
|
+
let viewDir = normalize(u.eye.xyz - in.worldPos);
|
|
530
|
+
let halfVec = normalize(toLight + viewDir);
|
|
531
|
+
let highlight = pow(max(dot(normal, halfVec), 0.0), in.specular.w) * u.params.x;
|
|
532
|
+
lit = lit + highlight * in.specular.xyz;
|
|
533
|
+
}
|
|
534
|
+
lit = lit + in.emissive;
|
|
535
|
+
return vec4<f32>(lit, u.params.z);
|
|
440
536
|
}
|
|
441
537
|
`;
|
|
442
538
|
CLIP_Z_FIX = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 1];
|
|
@@ -477,13 +573,15 @@ fn fs(in: VSOut) -> @location(0) vec4<f32> {
|
|
|
477
573
|
{
|
|
478
574
|
binding: 0,
|
|
479
575
|
visibility: stage.VERTEX | stage.FRAGMENT,
|
|
480
|
-
buffer: { type: "uniform", hasDynamicOffset: true, minBindingSize:
|
|
576
|
+
buffer: { type: "uniform", hasDynamicOffset: true, minBindingSize: 176 }
|
|
481
577
|
}
|
|
482
578
|
]
|
|
483
579
|
});
|
|
484
|
-
const vertexBuffer = (location) => ({
|
|
485
|
-
arrayStride:
|
|
486
|
-
attributes: [
|
|
580
|
+
const vertexBuffer = (location, components = 3) => ({
|
|
581
|
+
arrayStride: components * 4,
|
|
582
|
+
attributes: [
|
|
583
|
+
{ shaderLocation: location, offset: 0, format: `float32x${components}` }
|
|
584
|
+
]
|
|
487
585
|
});
|
|
488
586
|
const pipelineLayout = device.createPipelineLayout({ bindGroupLayouts: [layout] });
|
|
489
587
|
const blend = {
|
|
@@ -499,7 +597,13 @@ fn fs(in: VSOut) -> @location(0) vec4<f32> {
|
|
|
499
597
|
vertex: {
|
|
500
598
|
module: module2,
|
|
501
599
|
entryPoint: "vs",
|
|
502
|
-
buffers: [
|
|
600
|
+
buffers: [
|
|
601
|
+
vertexBuffer(0),
|
|
602
|
+
vertexBuffer(1),
|
|
603
|
+
vertexBuffer(2),
|
|
604
|
+
vertexBuffer(3),
|
|
605
|
+
vertexBuffer(4, 4)
|
|
606
|
+
]
|
|
503
607
|
},
|
|
504
608
|
fragment: {
|
|
505
609
|
module: module2,
|
|
@@ -552,6 +656,8 @@ fn fs(in: VSOut) -> @location(0) vec4<f32> {
|
|
|
552
656
|
position: upload(data.positions),
|
|
553
657
|
normal: upload(data.normals),
|
|
554
658
|
color: upload(data.colors),
|
|
659
|
+
emissive: upload(data.emissives),
|
|
660
|
+
specular: upload(data.speculars),
|
|
555
661
|
count: data.count
|
|
556
662
|
};
|
|
557
663
|
this.cache.set(mesh, result);
|
|
@@ -603,7 +709,7 @@ fn fs(in: VSOut) -> @location(0) vec4<f32> {
|
|
|
603
709
|
const bindGroup = this.device.createBindGroup({
|
|
604
710
|
layout,
|
|
605
711
|
entries: [
|
|
606
|
-
{ binding: 0, resource: { buffer: this.uniformBuffer, offset: 0, size:
|
|
712
|
+
{ binding: 0, resource: { buffer: this.uniformBuffer, offset: 0, size: 176 } }
|
|
607
713
|
]
|
|
608
714
|
});
|
|
609
715
|
draws.forEach((draw, i) => {
|
|
@@ -612,6 +718,7 @@ fn fs(in: VSOut) -> @location(0) vec4<f32> {
|
|
|
612
718
|
data.set(draw.item.model, 16);
|
|
613
719
|
data.set([frame.light.toLight.x, frame.light.toLight.y, frame.light.toLight.z, 0], 32);
|
|
614
720
|
data.set([frame.light.intensity, frame.light.ambient, draw.opacity, 0], 36);
|
|
721
|
+
data.set([frame.eye.x, frame.eye.y, frame.eye.z, 0], 40);
|
|
615
722
|
this.device.queue.writeBuffer(this.uniformBuffer, i * UNIFORM_STRIDE, data);
|
|
616
723
|
});
|
|
617
724
|
const encoder = this.device.createCommandEncoder();
|
|
@@ -638,6 +745,8 @@ fn fs(in: VSOut) -> @location(0) vec4<f32> {
|
|
|
638
745
|
pass.setVertexBuffer(0, mesh.position);
|
|
639
746
|
pass.setVertexBuffer(1, mesh.normal);
|
|
640
747
|
pass.setVertexBuffer(2, mesh.color);
|
|
748
|
+
pass.setVertexBuffer(3, mesh.emissive);
|
|
749
|
+
pass.setVertexBuffer(4, mesh.specular);
|
|
641
750
|
pass.draw(mesh.count);
|
|
642
751
|
});
|
|
643
752
|
pass.end();
|
|
@@ -649,6 +758,8 @@ fn fs(in: VSOut) -> @location(0) vec4<f32> {
|
|
|
649
758
|
mesh.position.destroy?.();
|
|
650
759
|
mesh.normal.destroy?.();
|
|
651
760
|
mesh.color.destroy?.();
|
|
761
|
+
mesh.emissive.destroy?.();
|
|
762
|
+
mesh.specular.destroy?.();
|
|
652
763
|
}
|
|
653
764
|
this.cache.clear();
|
|
654
765
|
this.uniformBuffer?.destroy?.();
|
|
@@ -731,9 +842,30 @@ var init_canvas2d = __esm({
|
|
|
731
842
|
depth += dot(d, d);
|
|
732
843
|
}
|
|
733
844
|
depth /= face.indices.length;
|
|
845
|
+
let surface;
|
|
846
|
+
const material = face.material;
|
|
847
|
+
if (material) {
|
|
848
|
+
if (material.specular) {
|
|
849
|
+
let cx = 0;
|
|
850
|
+
let cy = 0;
|
|
851
|
+
let cz = 0;
|
|
852
|
+
for (const i of face.indices) {
|
|
853
|
+
cx += world[i].x;
|
|
854
|
+
cy += world[i].y;
|
|
855
|
+
cz += world[i].z;
|
|
856
|
+
}
|
|
857
|
+
const inv = 1 / face.indices.length;
|
|
858
|
+
const viewDir = normalize(
|
|
859
|
+
subtract(frame.eye, { x: cx * inv, y: cy * inv, z: cz * inv })
|
|
860
|
+
);
|
|
861
|
+
surface = { material, viewDir };
|
|
862
|
+
} else {
|
|
863
|
+
surface = { material };
|
|
864
|
+
}
|
|
865
|
+
}
|
|
734
866
|
polygons.push({
|
|
735
867
|
points,
|
|
736
|
-
color: shadeColor(normal, face.color, frame.light),
|
|
868
|
+
color: shadeColor(normal, face.color, frame.light, surface),
|
|
737
869
|
depth,
|
|
738
870
|
opacity: faceOpacity
|
|
739
871
|
});
|
|
@@ -1557,6 +1689,12 @@ init_light();
|
|
|
1557
1689
|
init_math();
|
|
1558
1690
|
|
|
1559
1691
|
// src/engines/little-3d-engine/core/mesh.ts
|
|
1692
|
+
function attachMaterial(mesh, material) {
|
|
1693
|
+
if (material) {
|
|
1694
|
+
for (const face of mesh.faces) face.material = material;
|
|
1695
|
+
}
|
|
1696
|
+
return mesh;
|
|
1697
|
+
}
|
|
1560
1698
|
function transform(init) {
|
|
1561
1699
|
return {
|
|
1562
1700
|
position: init?.position ?? { x: 0, y: 0, z: 0 },
|
|
@@ -1571,7 +1709,7 @@ init_light();
|
|
|
1571
1709
|
|
|
1572
1710
|
// src/engines/little-3d-engine/shapes/primitives/quad.ts
|
|
1573
1711
|
var DEFAULT_COLORS = ["#3b82f6"];
|
|
1574
|
-
function quad(size = 1, colors = DEFAULT_COLORS) {
|
|
1712
|
+
function quad(size = 1, colors = DEFAULT_COLORS, material) {
|
|
1575
1713
|
const s = size / 2;
|
|
1576
1714
|
const vertices = [
|
|
1577
1715
|
{ x: -s, y: -s, z: 0 },
|
|
@@ -1579,7 +1717,10 @@ function quad(size = 1, colors = DEFAULT_COLORS) {
|
|
|
1579
1717
|
{ x: s, y: s, z: 0 },
|
|
1580
1718
|
{ x: -s, y: s, z: 0 }
|
|
1581
1719
|
];
|
|
1582
|
-
return
|
|
1720
|
+
return attachMaterial(
|
|
1721
|
+
{ vertices, faces: [{ indices: [0, 1, 2, 3], color: colors[0] }] },
|
|
1722
|
+
material
|
|
1723
|
+
);
|
|
1583
1724
|
}
|
|
1584
1725
|
|
|
1585
1726
|
// src/engines/little-3d-engine/shapes/primitives/spheres/icosphere.ts
|