matrix-engine-wgpu 1.3.19 → 1.4.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/examples/camera-texture.js +2 -0
- package/examples/load-obj-file.js +9 -13
- package/examples/load-objs-sequence.js +8 -0
- package/examples/video-texture.js +13 -7
- package/package.json +4 -2
- package/public/examples.js +707 -543
- package/readme.md +19 -8
- package/src/engine/engine.js +1 -1
- package/src/engine/lights.js +174 -87
- package/src/engine/materials.js +129 -68
- package/src/engine/mesh-obj.js +96 -176
- package/src/physics/matrix-ammo.js +0 -42
- package/src/shaders/fragment.video.wgsl.js +3 -2
- package/src/shaders/fragment.wgsl.js +113 -51
- package/src/shaders/shaders.js +0 -1
- package/src/shaders/vertex.wgsl.js +6 -20
- package/src/world.js +207 -127
package/public/examples.js
CHANGED
|
@@ -95,6 +95,7 @@ var loadCameraTexture = function () {
|
|
|
95
95
|
a: 1
|
|
96
96
|
}
|
|
97
97
|
}, () => {
|
|
98
|
+
cameraTexture.addLight();
|
|
98
99
|
addEventListener('AmmoReady', () => {
|
|
99
100
|
(0, _loaderObj.downloadMeshes)({
|
|
100
101
|
welcomeText: "./res/meshes/blender/piramyd.obj",
|
|
@@ -158,8 +159,9 @@ exports.loadObjFile = void 0;
|
|
|
158
159
|
var _world = _interopRequireDefault(require("../src/world.js"));
|
|
159
160
|
var _loaderObj = require("../src/engine/loader-obj.js");
|
|
160
161
|
var _utils = require("../src/engine/utils.js");
|
|
161
|
-
var _raycast = require("../src/engine/raycast.js");
|
|
162
162
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
163
|
+
// import {addRaycastsAABBListener} from "../src/engine/raycast.js";
|
|
164
|
+
|
|
163
165
|
var loadObjFile = function () {
|
|
164
166
|
let loadObjFile = new _world.default({
|
|
165
167
|
useSingleRenderPass: true,
|
|
@@ -175,8 +177,6 @@ var loadObjFile = function () {
|
|
|
175
177
|
a: 1
|
|
176
178
|
}
|
|
177
179
|
}, () => {
|
|
178
|
-
// loadObjFile.addLight()
|
|
179
|
-
|
|
180
180
|
addEventListener('AmmoReady', () => {
|
|
181
181
|
(0, _loaderObj.downloadMeshes)({
|
|
182
182
|
ball: "./res/meshes/blender/sphere.obj",
|
|
@@ -187,7 +187,7 @@ var loadObjFile = function () {
|
|
|
187
187
|
(0, _loaderObj.downloadMeshes)({
|
|
188
188
|
cube: "./res/meshes/blender/cube.obj"
|
|
189
189
|
}, onGround, {
|
|
190
|
-
scale: [
|
|
190
|
+
scale: [20, 1, 20]
|
|
191
191
|
});
|
|
192
192
|
|
|
193
193
|
// loadObjFile.addLight();
|
|
@@ -223,13 +223,13 @@ var loadObjFile = function () {
|
|
|
223
223
|
function onLoadObj(m) {
|
|
224
224
|
loadObjFile.myLoadedMeshes = m;
|
|
225
225
|
for (var key in m) {
|
|
226
|
-
console.log(`%c Loaded objs: ${key} `,
|
|
226
|
+
// console.log(`%c Loaded objs: ${key} `, LOG_MATRIX);
|
|
227
227
|
}
|
|
228
228
|
loadObjFile.addMeshObj({
|
|
229
229
|
position: {
|
|
230
230
|
x: 0,
|
|
231
231
|
y: 2,
|
|
232
|
-
z: -
|
|
232
|
+
z: -20
|
|
233
233
|
},
|
|
234
234
|
rotation: {
|
|
235
235
|
x: 0,
|
|
@@ -245,16 +245,16 @@ var loadObjFile = function () {
|
|
|
245
245
|
name: 'cube1',
|
|
246
246
|
mesh: m.cube,
|
|
247
247
|
physics: {
|
|
248
|
-
enabled:
|
|
248
|
+
enabled: false,
|
|
249
249
|
geometry: "Cube"
|
|
250
250
|
}
|
|
251
251
|
// raycast: { enabled: true , radius: 2 }
|
|
252
252
|
});
|
|
253
253
|
loadObjFile.addMeshObj({
|
|
254
254
|
position: {
|
|
255
|
-
x:
|
|
256
|
-
y:
|
|
257
|
-
z: -
|
|
255
|
+
x: 0,
|
|
256
|
+
y: -1,
|
|
257
|
+
z: -20
|
|
258
258
|
},
|
|
259
259
|
rotation: {
|
|
260
260
|
x: 0,
|
|
@@ -270,7 +270,7 @@ var loadObjFile = function () {
|
|
|
270
270
|
name: 'ball1',
|
|
271
271
|
mesh: m.ball,
|
|
272
272
|
physics: {
|
|
273
|
-
enabled:
|
|
273
|
+
enabled: false,
|
|
274
274
|
geometry: "Sphere"
|
|
275
275
|
}
|
|
276
276
|
// raycast: { enabled: true , radius: 2 }
|
|
@@ -278,6 +278,7 @@ var loadObjFile = function () {
|
|
|
278
278
|
var TEST = loadObjFile.getSceneObjectByName('cube2');
|
|
279
279
|
console.log(`%c Test access scene ${TEST} object.`, _utils.LOG_MATRIX);
|
|
280
280
|
loadObjFile.addLight();
|
|
281
|
+
// loadObjFile.addLight();
|
|
281
282
|
}
|
|
282
283
|
});
|
|
283
284
|
// just for dev
|
|
@@ -285,7 +286,7 @@ var loadObjFile = function () {
|
|
|
285
286
|
};
|
|
286
287
|
exports.loadObjFile = loadObjFile;
|
|
287
288
|
|
|
288
|
-
},{"../src/engine/loader-obj.js":12,"../src/engine/
|
|
289
|
+
},{"../src/engine/loader-obj.js":12,"../src/engine/utils.js":17,"../src/world.js":26}],4:[function(require,module,exports){
|
|
289
290
|
"use strict";
|
|
290
291
|
|
|
291
292
|
Object.defineProperty(exports, "__esModule", {
|
|
@@ -306,6 +307,12 @@ var loadObjsSequence = function () {
|
|
|
306
307
|
}
|
|
307
308
|
}, () => {
|
|
308
309
|
addEventListener('AmmoReady', () => {
|
|
310
|
+
// requied now
|
|
311
|
+
loadObjFile.addLight();
|
|
312
|
+
|
|
313
|
+
// adapt
|
|
314
|
+
app.lightContainer[0].position[2] = -5;
|
|
315
|
+
app.lightContainer[0].position[1] = 22;
|
|
309
316
|
(0, _loaderObj.downloadMeshes)((0, _loaderObj.makeObjSeqArg)({
|
|
310
317
|
id: "swat-walk-pistol",
|
|
311
318
|
path: "res/meshes/objs-sequence/swat-walk-pistol",
|
|
@@ -442,6 +449,7 @@ var _loaderObj = require("../src/engine/loader-obj.js");
|
|
|
442
449
|
var _utils = require("../src/engine/utils.js");
|
|
443
450
|
var _raycast = require("../src/engine/raycast.js");
|
|
444
451
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
452
|
+
// @group(0) @binding(5) var<uniform> postFXMode: u32;
|
|
445
453
|
var loadVideoTexture = function () {
|
|
446
454
|
let videoTexture = new _world.default({
|
|
447
455
|
useSingleRenderPass: true,
|
|
@@ -457,6 +465,10 @@ var loadVideoTexture = function () {
|
|
|
457
465
|
a: 1
|
|
458
466
|
}
|
|
459
467
|
}, () => {
|
|
468
|
+
// For now one light perscene must be added.
|
|
469
|
+
// if you dont wanna light just use intesity = 0
|
|
470
|
+
// videoTexture is app main instance
|
|
471
|
+
videoTexture.addLight();
|
|
460
472
|
addEventListener('AmmoReady', () => {
|
|
461
473
|
(0, _loaderObj.downloadMeshes)({
|
|
462
474
|
welcomeText: "./res/meshes/blender/piramyd.obj",
|
|
@@ -498,13 +510,11 @@ var loadVideoTexture = function () {
|
|
|
498
510
|
// raycast: { enabled: true , radius: 2 }
|
|
499
511
|
});
|
|
500
512
|
var TEST = videoTexture.getSceneObjectByName('MyVideoTex');
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
});
|
|
507
|
-
}, 4000);
|
|
513
|
+
console.log(`%c Test video-texture...`, _utils.LOG_MATRIX);
|
|
514
|
+
TEST.loadVideoTexture({
|
|
515
|
+
type: 'video',
|
|
516
|
+
src: 'res/videos/tunel.mp4'
|
|
517
|
+
});
|
|
508
518
|
}
|
|
509
519
|
});
|
|
510
520
|
window.app = videoTexture;
|
|
@@ -6733,7 +6743,7 @@ class CameraBase {
|
|
|
6733
6743
|
set matrix(mat) {
|
|
6734
6744
|
_wgpuMatrix.mat4.copy(mat, this.matrix_);
|
|
6735
6745
|
}
|
|
6736
|
-
setProjection(fov = 2 * Math.PI / 5, aspect = 1, near =
|
|
6746
|
+
setProjection(fov = 2 * Math.PI / 5, aspect = 1, near = 0.5, far = 1000) {
|
|
6737
6747
|
this.projectionMatrix = _wgpuMatrix.mat4.perspective(fov, aspect, near, far);
|
|
6738
6748
|
}
|
|
6739
6749
|
|
|
@@ -7119,12 +7129,16 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
7119
7129
|
});
|
|
7120
7130
|
exports.SpotLight = void 0;
|
|
7121
7131
|
var _wgpuMatrix = require("wgpu-matrix");
|
|
7132
|
+
var _vertexShadow = require("../shaders/vertexShadow.wgsl");
|
|
7133
|
+
/**
|
|
7134
|
+
* @description
|
|
7135
|
+
* Spot light with shodow cast.
|
|
7136
|
+
* @author Nikola Lukic
|
|
7137
|
+
* @email zlatnaspirala@gmail.com
|
|
7138
|
+
*/
|
|
7122
7139
|
class SpotLight {
|
|
7123
|
-
// injected
|
|
7124
7140
|
camera;
|
|
7125
7141
|
inputHandler;
|
|
7126
|
-
|
|
7127
|
-
// Light
|
|
7128
7142
|
position;
|
|
7129
7143
|
target;
|
|
7130
7144
|
up;
|
|
@@ -7139,15 +7153,29 @@ class SpotLight {
|
|
|
7139
7153
|
innerCutoff;
|
|
7140
7154
|
outerCutoff;
|
|
7141
7155
|
spotlightUniformBuffer;
|
|
7142
|
-
constructor(camera, inputHandler, position = _wgpuMatrix.vec3.create(0,
|
|
7156
|
+
constructor(camera, inputHandler, device, position = _wgpuMatrix.vec3.create(0, 10, -20), target = _wgpuMatrix.vec3.create(0, 0, -20), fov = 45, aspect = 1.0, near = 0.1, far = 200) {
|
|
7157
|
+
this.fov = fov;
|
|
7158
|
+
this.aspect = aspect;
|
|
7159
|
+
this.near = near;
|
|
7160
|
+
this.far = far;
|
|
7143
7161
|
this.camera = camera;
|
|
7144
7162
|
this.inputHandler = inputHandler;
|
|
7145
7163
|
this.position = position;
|
|
7146
7164
|
this.target = target;
|
|
7147
|
-
this.up = _wgpuMatrix.vec3.create(0,
|
|
7165
|
+
this.up = _wgpuMatrix.vec3.create(0, 0, -1);
|
|
7148
7166
|
this.direction = _wgpuMatrix.vec3.normalize(_wgpuMatrix.vec3.subtract(target, position));
|
|
7167
|
+
this.intensity = 1.0;
|
|
7168
|
+
this.color = _wgpuMatrix.vec3.create(1.0, 1.0, 1.0); // white
|
|
7169
|
+
|
|
7149
7170
|
this.viewMatrix = _wgpuMatrix.mat4.lookAt(position, target, this.up);
|
|
7150
|
-
this.projectionMatrix = _wgpuMatrix.mat4.perspective(fov * Math.PI / 180, aspect, near, far);
|
|
7171
|
+
this.projectionMatrix = _wgpuMatrix.mat4.perspective(this.fov * Math.PI / 180, this.aspect, this.near, this.far);
|
|
7172
|
+
this.setProjection = function (fov = 45, aspect = 1.0, near = 0.1, far = 200) {
|
|
7173
|
+
this.projectionMatrix = _wgpuMatrix.mat4.perspective(fov, aspect, near, far);
|
|
7174
|
+
};
|
|
7175
|
+
this.updateProjection = function () {
|
|
7176
|
+
this.projectionMatrix = _wgpuMatrix.mat4.perspective(this.fov, this.aspect, this.near, this.far);
|
|
7177
|
+
};
|
|
7178
|
+
this.device = device;
|
|
7151
7179
|
this.viewProjMatrix = _wgpuMatrix.mat4.multiply(this.projectionMatrix, this.viewMatrix);
|
|
7152
7180
|
this.fov = fov;
|
|
7153
7181
|
this.aspect = aspect;
|
|
@@ -7155,77 +7183,145 @@ class SpotLight {
|
|
|
7155
7183
|
this.far = far;
|
|
7156
7184
|
this.innerCutoff = Math.cos(Math.PI / 180 * 12.5);
|
|
7157
7185
|
this.outerCutoff = Math.cos(Math.PI / 180 * 17.5);
|
|
7186
|
+
this.ambientFactor = 0.5;
|
|
7187
|
+
this.range = 20.0;
|
|
7188
|
+
this.shadowBias = 0.01;
|
|
7189
|
+
this.SHADOW_RES = 1024;
|
|
7190
|
+
this.primitive = {
|
|
7191
|
+
topology: 'triangle-list',
|
|
7192
|
+
cullMode: 'back',
|
|
7193
|
+
// for front interest border drawen shadows !
|
|
7194
|
+
frontFace: 'ccw'
|
|
7195
|
+
};
|
|
7196
|
+
this.shadowTexture = this.device.createTexture({
|
|
7197
|
+
label: 'shadowTexture[light]',
|
|
7198
|
+
size: [this.SHADOW_RES, this.SHADOW_RES, 1],
|
|
7199
|
+
format: "depth32float",
|
|
7200
|
+
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING
|
|
7201
|
+
});
|
|
7202
|
+
this.shadowSampler = device.createSampler({
|
|
7203
|
+
label: 'shadowSampler[light]',
|
|
7204
|
+
compare: 'less',
|
|
7205
|
+
magFilter: 'linear',
|
|
7206
|
+
minFilter: 'linear'
|
|
7207
|
+
});
|
|
7208
|
+
this.renderPassDescriptor = {
|
|
7209
|
+
label: "renderPassDescriptor shadowPass [per SpotLigth]",
|
|
7210
|
+
colorAttachments: [],
|
|
7211
|
+
depthStencilAttachment: {
|
|
7212
|
+
view: this.shadowTexture.createView(),
|
|
7213
|
+
depthClearValue: 1.0,
|
|
7214
|
+
depthLoadOp: "clear",
|
|
7215
|
+
depthStoreOp: "store"
|
|
7216
|
+
}
|
|
7217
|
+
};
|
|
7218
|
+
this.uniformBufferBindGroupLayout = this.device.createBindGroupLayout({
|
|
7219
|
+
label: 'modelBindGroup in light',
|
|
7220
|
+
entries: [{
|
|
7221
|
+
binding: 0,
|
|
7222
|
+
visibility: GPUShaderStage.VERTEX,
|
|
7223
|
+
buffer: {
|
|
7224
|
+
type: 'uniform'
|
|
7225
|
+
}
|
|
7226
|
+
}]
|
|
7227
|
+
});
|
|
7228
|
+
this.shadowBindGroupContainer = [];
|
|
7229
|
+
this.getShadowBindGroup = (mesh, index) => {
|
|
7230
|
+
if (this.shadowBindGroupContainer[index]) {
|
|
7231
|
+
return this.shadowBindGroupContainer[index];
|
|
7232
|
+
}
|
|
7233
|
+
this.shadowBindGroupContainer[index] = this.device.createBindGroup({
|
|
7234
|
+
label: 'sceneBindGroupForShadow in light',
|
|
7235
|
+
layout: this.uniformBufferBindGroupLayout,
|
|
7236
|
+
entries: [{
|
|
7237
|
+
binding: 0,
|
|
7238
|
+
resource: {
|
|
7239
|
+
buffer: mesh.sceneUniformBuffer
|
|
7240
|
+
}
|
|
7241
|
+
}]
|
|
7242
|
+
});
|
|
7243
|
+
return this.shadowBindGroupContainer[index];
|
|
7244
|
+
};
|
|
7245
|
+
this.modelBindGroupLayout = this.device.createBindGroupLayout({
|
|
7246
|
+
entries: [{
|
|
7247
|
+
binding: 0,
|
|
7248
|
+
visibility: GPUShaderStage.VERTEX,
|
|
7249
|
+
buffer: {
|
|
7250
|
+
type: 'uniform'
|
|
7251
|
+
}
|
|
7252
|
+
}]
|
|
7253
|
+
});
|
|
7254
|
+
this.shadowPipeline = this.device.createRenderPipeline({
|
|
7255
|
+
label: 'shadowPipeline per light',
|
|
7256
|
+
layout: this.device.createPipelineLayout({
|
|
7257
|
+
label: 'createPipelineLayout - uniformBufferBindGroupLayout',
|
|
7258
|
+
bindGroupLayouts: [this.uniformBufferBindGroupLayout, this.modelBindGroupLayout]
|
|
7259
|
+
}),
|
|
7260
|
+
vertex: {
|
|
7261
|
+
module: this.device.createShaderModule({
|
|
7262
|
+
code: _vertexShadow.vertexShadowWGSL
|
|
7263
|
+
}),
|
|
7264
|
+
buffers: [{
|
|
7265
|
+
arrayStride: 12,
|
|
7266
|
+
// 3 * 4 bytes (vec3f)
|
|
7267
|
+
attributes: [{
|
|
7268
|
+
shaderLocation: 0,
|
|
7269
|
+
// must match @location(0) in vertex shader
|
|
7270
|
+
offset: 0,
|
|
7271
|
+
format: "float32x3"
|
|
7272
|
+
}]
|
|
7273
|
+
}]
|
|
7274
|
+
},
|
|
7275
|
+
depthStencil: {
|
|
7276
|
+
depthWriteEnabled: true,
|
|
7277
|
+
depthCompare: 'less',
|
|
7278
|
+
format: 'depth32float'
|
|
7279
|
+
},
|
|
7280
|
+
primitive: this.primitive
|
|
7281
|
+
});
|
|
7282
|
+
this.getMainPassBindGroup = function (mesh) {
|
|
7283
|
+
// You can cache it per mesh to avoid recreating each frame
|
|
7284
|
+
if (!this.mainPassBindGroupContainer) this.mainPassBindGroupContainer = [];
|
|
7285
|
+
const index = mesh._lightBindGroupIndex || 0; // assign unique per mesh if needed
|
|
7286
|
+
if (this.mainPassBindGroupContainer[index]) {
|
|
7287
|
+
return this.mainPassBindGroupContainer[index];
|
|
7288
|
+
}
|
|
7289
|
+
this.mainPassBindGroupContainer[index] = this.device.createBindGroup({
|
|
7290
|
+
label: `mainPassBindGroup for mesh`,
|
|
7291
|
+
layout: mesh.mainPassBindGroupLayout,
|
|
7292
|
+
// this should match the pipeline
|
|
7293
|
+
entries: [{
|
|
7294
|
+
binding: 0,
|
|
7295
|
+
// must match @binding in shader for shadow texture
|
|
7296
|
+
resource: this.shadowTexture.createView()
|
|
7297
|
+
}, {
|
|
7298
|
+
binding: 1,
|
|
7299
|
+
// must match @binding in shader for shadow sampler
|
|
7300
|
+
resource: this.shadowSampler
|
|
7301
|
+
}]
|
|
7302
|
+
});
|
|
7303
|
+
return this.mainPassBindGroupContainer[index];
|
|
7304
|
+
};
|
|
7158
7305
|
}
|
|
7159
7306
|
update() {
|
|
7160
|
-
//
|
|
7161
|
-
|
|
7162
|
-
// this.viewProjMatrix = mat4.multiply(this.projectionMatrix, this.viewMatrix);
|
|
7163
|
-
// console.log('test light update this.target : ', this.target)
|
|
7164
|
-
// Use the existing direction
|
|
7307
|
+
// this.target = vec3.create(x, y, z); // new target
|
|
7308
|
+
this.direction = _wgpuMatrix.vec3.normalize(_wgpuMatrix.vec3.subtract(this.target, this.position));
|
|
7165
7309
|
const target = _wgpuMatrix.vec3.add(this.position, this.direction);
|
|
7166
7310
|
this.viewMatrix = _wgpuMatrix.mat4.lookAt(this.position, target, this.up);
|
|
7167
7311
|
this.viewProjMatrix = _wgpuMatrix.mat4.multiply(this.projectionMatrix, this.viewMatrix);
|
|
7168
7312
|
}
|
|
7169
|
-
updateSceneUniforms(mainRenderBundle) {
|
|
7170
|
-
const now = Date.now();
|
|
7171
|
-
// First frame safety
|
|
7172
|
-
let dt = (now - this.lastFrameMS) / 1000;
|
|
7173
|
-
if (!this.lastFrameMS) {
|
|
7174
|
-
dt = 16;
|
|
7175
|
-
}
|
|
7176
|
-
this.lastFrameMS = now;
|
|
7177
|
-
// engine, once per frame
|
|
7178
|
-
this.camera.update(dt, this.inputHandler());
|
|
7179
|
-
const camVP = _wgpuMatrix.mat4.multiply(this.camera.projectionMatrix, this.camera.view); // P * V
|
|
7180
|
-
|
|
7181
|
-
for (const mesh of mainRenderBundle) {
|
|
7182
|
-
// scene buffer layout = 0..63 lightVP, 64..127 camVP, 128..143 lightPos(+pad)
|
|
7183
|
-
this.device.queue.writeBuffer(mesh.sceneUniformBuffer, 64,
|
|
7184
|
-
// cameraViewProjMatrix offset
|
|
7185
|
-
camVP.buffer, camVP.byteOffset, camVP.byteLength);
|
|
7186
|
-
}
|
|
7187
|
-
// const camVP = mat4.multiply(camera.projectionMatrix, camera.view);
|
|
7188
|
-
// const sceneData = new Float32Array(36); // 16 + 16 + 4
|
|
7189
|
-
// sceneData.set(this.viewProjMatrix, 0);
|
|
7190
|
-
// sceneData.set(camVP, 16);
|
|
7191
|
-
// sceneData.set(this.position, 32);
|
|
7192
|
-
// if(!this.device) {
|
|
7193
|
-
// console.warn("Device not set for SpotLight");
|
|
7194
|
-
// return;
|
|
7195
|
-
// }
|
|
7196
|
-
// this.device.queue.writeBuffer(
|
|
7197
|
-
// sceneUniformBuffer,
|
|
7198
|
-
// // this.spotlightUniformBuffer,
|
|
7199
|
-
// 0,
|
|
7200
|
-
// sceneData.buffer,
|
|
7201
|
-
// sceneData.byteOffset,
|
|
7202
|
-
// sceneData.byteLength
|
|
7203
|
-
// );
|
|
7204
|
-
}
|
|
7205
|
-
prepareBuffer(device) {
|
|
7206
|
-
if (!this.device) this.device = device;
|
|
7207
|
-
this.spotlightUniformBuffer = this.device.createBuffer({
|
|
7208
|
-
size: 16 * 4,
|
|
7209
|
-
// 64 bytes
|
|
7210
|
-
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
7211
|
-
});
|
|
7212
|
-
const spotlightData = this.getLightDataBuffer();
|
|
7213
|
-
this.device.queue.writeBuffer(this.spotlightUniformBuffer, 0, spotlightData.buffer, spotlightData.byteOffset, spotlightData.byteLength);
|
|
7214
|
-
}
|
|
7215
|
-
updateLightBuffer() {
|
|
7216
|
-
if (!this.device || !this.spotlightUniformBuffer) {
|
|
7217
|
-
return;
|
|
7218
|
-
}
|
|
7219
|
-
const spotlightData = this.getLightDataBuffer();
|
|
7220
|
-
this.device.queue.writeBuffer(this.spotlightUniformBuffer, 0, spotlightData.buffer, spotlightData.byteOffset, spotlightData.byteLength);
|
|
7221
|
-
}
|
|
7222
7313
|
getLightDataBuffer() {
|
|
7223
|
-
|
|
7314
|
+
const m = this.viewProjMatrix;
|
|
7315
|
+
return new Float32Array([...this.position, 0.0, ...this.direction, 0.0, this.innerCutoff, this.outerCutoff, this.intensity, 0.0, ...this.color, 0.0, this.range, this.ambientFactor, this.shadowBias,
|
|
7316
|
+
// <<--- use shadowBias
|
|
7317
|
+
0.0,
|
|
7318
|
+
// keep padding
|
|
7319
|
+
...m]);
|
|
7224
7320
|
}
|
|
7225
7321
|
}
|
|
7226
7322
|
exports.SpotLight = SpotLight;
|
|
7227
7323
|
|
|
7228
|
-
},{"wgpu-matrix":7}],12:[function(require,module,exports){
|
|
7324
|
+
},{"../shaders/vertexShadow.wgsl":24,"wgpu-matrix":7}],12:[function(require,module,exports){
|
|
7229
7325
|
"use strict";
|
|
7230
7326
|
|
|
7231
7327
|
Object.defineProperty(exports, "__esModule", {
|
|
@@ -7712,8 +7808,17 @@ class Materials {
|
|
|
7712
7808
|
constructor(device) {
|
|
7713
7809
|
this.device = device;
|
|
7714
7810
|
this.isVideo = false;
|
|
7811
|
+
this.videoIsReady = 'NONE';
|
|
7812
|
+
// this.compareSampler = this.device.createSampler({compare: 'less'});
|
|
7715
7813
|
this.compareSampler = this.device.createSampler({
|
|
7716
|
-
compare: 'less'
|
|
7814
|
+
compare: 'less-equal',
|
|
7815
|
+
// safer for shadow comparison
|
|
7816
|
+
addressModeU: 'clamp-to-edge',
|
|
7817
|
+
// prevents UV leaking outside
|
|
7818
|
+
addressModeV: 'clamp-to-edge',
|
|
7819
|
+
magFilter: 'linear',
|
|
7820
|
+
// smooth PCF
|
|
7821
|
+
minFilter: 'linear'
|
|
7717
7822
|
});
|
|
7718
7823
|
// For image textures (standard sampler)
|
|
7719
7824
|
this.imageSampler = this.device.createSampler({
|
|
@@ -7735,7 +7840,7 @@ class Materials {
|
|
|
7735
7840
|
|
|
7736
7841
|
// Dymmy buffer
|
|
7737
7842
|
this.dummySpotlightUniformBuffer = this.device.createBuffer({
|
|
7738
|
-
size:
|
|
7843
|
+
size: 80,
|
|
7739
7844
|
// Must match size in shader
|
|
7740
7845
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
7741
7846
|
});
|
|
@@ -7768,7 +7873,8 @@ class Materials {
|
|
|
7768
7873
|
});
|
|
7769
7874
|
}
|
|
7770
7875
|
async loadVideoTexture(arg) {
|
|
7771
|
-
this.isVideo = true;
|
|
7876
|
+
// this.isVideo = true;
|
|
7877
|
+
this.videoIsReady = 'MAYBE';
|
|
7772
7878
|
if (arg.type === 'video') {
|
|
7773
7879
|
this.video = document.createElement('video');
|
|
7774
7880
|
this.video.src = arg.src || 'res/videos/tunel.mp4';
|
|
@@ -7777,7 +7883,11 @@ class Materials {
|
|
|
7777
7883
|
this.video.loop = true;
|
|
7778
7884
|
document.body.append(this.video);
|
|
7779
7885
|
this.video.style.display = 'none';
|
|
7886
|
+
this.video.style.position = 'absolute';
|
|
7887
|
+
this.video.style.top = '50px';
|
|
7888
|
+
this.video.style.left = '50px';
|
|
7780
7889
|
await this.video.play();
|
|
7890
|
+
this.isVideo = true;
|
|
7781
7891
|
} else if (arg.type === 'videoElement') {
|
|
7782
7892
|
this.video = arg.el;
|
|
7783
7893
|
await this.video.play();
|
|
@@ -7802,6 +7912,7 @@ class Materials {
|
|
|
7802
7912
|
});
|
|
7803
7913
|
this.video.srcObject = stream;
|
|
7804
7914
|
await this.video.play();
|
|
7915
|
+
this.isVideo = true;
|
|
7805
7916
|
} catch (err) {
|
|
7806
7917
|
console.error("❌ Failed to access camera:", err);
|
|
7807
7918
|
return;
|
|
@@ -7821,6 +7932,7 @@ class Materials {
|
|
|
7821
7932
|
}
|
|
7822
7933
|
this.video.srcObject = stream;
|
|
7823
7934
|
await this.video.play();
|
|
7935
|
+
this.isVideo = true;
|
|
7824
7936
|
} else if (arg.type === 'canvas2d-inline') {
|
|
7825
7937
|
// Miniature inline-drawn canvas created dynamically
|
|
7826
7938
|
const canvas = document.createElement('canvas');
|
|
@@ -7841,6 +7953,7 @@ class Materials {
|
|
|
7841
7953
|
this.video.playsInline = true;
|
|
7842
7954
|
this.video.style.display = 'none';
|
|
7843
7955
|
document.body.append(this.video);
|
|
7956
|
+
this.isVideo = true;
|
|
7844
7957
|
const stream = canvas.captureStream?.() || canvas.mozCaptureStream?.();
|
|
7845
7958
|
if (!stream) {
|
|
7846
7959
|
console.error('❌ Cannot capture stream from inline canvas');
|
|
@@ -7854,27 +7967,37 @@ class Materials {
|
|
|
7854
7967
|
minFilter: 'linear'
|
|
7855
7968
|
});
|
|
7856
7969
|
|
|
7857
|
-
// ✅ Now
|
|
7970
|
+
// ✅ Now - maybe noT
|
|
7858
7971
|
this.createLayoutForRender();
|
|
7859
|
-
this.setupPipeline();
|
|
7860
|
-
setTimeout(() => this.createBindGroupForRender(), 1500);
|
|
7861
7972
|
}
|
|
7862
7973
|
updateVideoTexture() {
|
|
7863
7974
|
if (!this.video || this.video.readyState < 2) return;
|
|
7864
|
-
this.externalTexture
|
|
7865
|
-
|
|
7866
|
-
|
|
7867
|
-
|
|
7975
|
+
if (!this.externalTexture) {
|
|
7976
|
+
// create it once
|
|
7977
|
+
this.externalTexture = this.device.importExternalTexture({
|
|
7978
|
+
source: this.video
|
|
7979
|
+
});
|
|
7980
|
+
this.createBindGroupForRender();
|
|
7981
|
+
this.videoIsReady = 'YES';
|
|
7982
|
+
console.log("✅ video bind group created [createBindGroupForRender()]");
|
|
7983
|
+
} else {
|
|
7984
|
+
this.externalTexture = this.device.importExternalTexture({
|
|
7985
|
+
source: this.video
|
|
7986
|
+
});
|
|
7987
|
+
this.createBindGroupForRender();
|
|
7988
|
+
}
|
|
7868
7989
|
}
|
|
7869
7990
|
createBindGroupForRender() {
|
|
7870
|
-
const textureResource = this.isVideo ? this.externalTexture
|
|
7871
|
-
|
|
7872
|
-
|
|
7873
|
-
console.warn("❗Missing res
|
|
7991
|
+
const textureResource = this.isVideo ? this.externalTexture : this.texture0.createView();
|
|
7992
|
+
if (!textureResource || !this.sceneUniformBuffer || !this.shadowDepthTextureView) {
|
|
7993
|
+
if (!textureResource) console.warn("❗Missing res texture: ", textureResource);
|
|
7994
|
+
if (!this.sceneUniformBuffer) console.warn("❗Missing res: this.sceneUniformBuffer: ", this.sceneUniformBuffer);
|
|
7995
|
+
if (!this.shadowDepthTextureView) console.warn("❗Missing res: this.shadowDepthTextureView: ", this.shadowDepthTextureView);
|
|
7996
|
+
if (typeof textureResource === 'undefined') this.updateVideoTexture();
|
|
7874
7997
|
return;
|
|
7875
|
-
}
|
|
7876
|
-
// console.log('what is this.lightContainer.length ', this.lightContainer.length)
|
|
7998
|
+
} else {}
|
|
7877
7999
|
if (this.isVideo == true) {
|
|
8000
|
+
console.info("✅ video sceneBindGroupForRender ");
|
|
7878
8001
|
this.sceneBindGroupForRender = this.device.createBindGroup({
|
|
7879
8002
|
layout: this.bglForRender,
|
|
7880
8003
|
entries: [{
|
|
@@ -7901,6 +8024,10 @@ class Materials {
|
|
|
7901
8024
|
}
|
|
7902
8025
|
}]
|
|
7903
8026
|
});
|
|
8027
|
+
|
|
8028
|
+
// special case for video meybe better solution exist
|
|
8029
|
+
// this.setupPipeline();
|
|
8030
|
+
this.video.play();
|
|
7904
8031
|
} else {
|
|
7905
8032
|
this.sceneBindGroupForRender = this.device.createBindGroup({
|
|
7906
8033
|
layout: this.bglForRender,
|
|
@@ -7924,73 +8051,94 @@ class Materials {
|
|
|
7924
8051
|
}, {
|
|
7925
8052
|
binding: 5,
|
|
7926
8053
|
resource: {
|
|
7927
|
-
buffer: this.
|
|
8054
|
+
buffer: !this.spotlightUniformBuffer ? this.dummySpotlightUniformBuffer : this.spotlightUniformBuffer
|
|
7928
8055
|
}
|
|
7929
8056
|
}]
|
|
7930
8057
|
});
|
|
7931
8058
|
}
|
|
7932
8059
|
}
|
|
7933
8060
|
createLayoutForRender() {
|
|
8061
|
+
if (this.isVideo == true) {
|
|
8062
|
+
console.info("✅ createLayoutForRender video [bglForRender]");
|
|
8063
|
+
} else {
|
|
8064
|
+
console.info("✅ normal createLayoutForRender [bglForRender]");
|
|
8065
|
+
}
|
|
8066
|
+
let e = [{
|
|
8067
|
+
binding: 0,
|
|
8068
|
+
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
|
|
8069
|
+
buffer: {
|
|
8070
|
+
type: 'uniform'
|
|
8071
|
+
}
|
|
8072
|
+
}, ...(this.isVideo == false ? [{
|
|
8073
|
+
binding: 1,
|
|
8074
|
+
visibility: GPUShaderStage.FRAGMENT,
|
|
8075
|
+
texture: {
|
|
8076
|
+
sampleType: "depth",
|
|
8077
|
+
viewDimension: "2d-array",
|
|
8078
|
+
// <- must match shadowMapArray
|
|
8079
|
+
multisampled: false
|
|
8080
|
+
}
|
|
8081
|
+
}] : [{
|
|
8082
|
+
binding: 1,
|
|
8083
|
+
visibility: GPUShaderStage.FRAGMENT,
|
|
8084
|
+
texture: {
|
|
8085
|
+
sampleType: "depth",
|
|
8086
|
+
viewDimension: "2d"
|
|
8087
|
+
}
|
|
8088
|
+
}]), {
|
|
8089
|
+
binding: 2,
|
|
8090
|
+
visibility: GPUShaderStage.FRAGMENT,
|
|
8091
|
+
sampler: {
|
|
8092
|
+
type: 'comparison'
|
|
8093
|
+
}
|
|
8094
|
+
}, ...(this.isVideo ? [
|
|
8095
|
+
// VIDEO
|
|
8096
|
+
{
|
|
8097
|
+
binding: 3,
|
|
8098
|
+
visibility: GPUShaderStage.FRAGMENT,
|
|
8099
|
+
externalTexture: {}
|
|
8100
|
+
}, {
|
|
8101
|
+
binding: 4,
|
|
8102
|
+
visibility: GPUShaderStage.FRAGMENT,
|
|
8103
|
+
sampler: {
|
|
8104
|
+
type: 'filtering'
|
|
8105
|
+
} // for video sampling
|
|
8106
|
+
}, {
|
|
8107
|
+
binding: 5,
|
|
8108
|
+
visibility: GPUShaderStage.FRAGMENT,
|
|
8109
|
+
buffer: {
|
|
8110
|
+
type: 'uniform'
|
|
8111
|
+
}
|
|
8112
|
+
}] : [
|
|
8113
|
+
// IMAGE
|
|
8114
|
+
{
|
|
8115
|
+
binding: 3,
|
|
8116
|
+
visibility: GPUShaderStage.FRAGMENT,
|
|
8117
|
+
texture: {
|
|
8118
|
+
sampleType: 'float',
|
|
8119
|
+
viewDimension: '2d'
|
|
8120
|
+
}
|
|
8121
|
+
}, {
|
|
8122
|
+
binding: 4,
|
|
8123
|
+
visibility: GPUShaderStage.FRAGMENT,
|
|
8124
|
+
sampler: {
|
|
8125
|
+
type: 'filtering'
|
|
8126
|
+
}
|
|
8127
|
+
}, {
|
|
8128
|
+
binding: 5,
|
|
8129
|
+
visibility: GPUShaderStage.FRAGMENT,
|
|
8130
|
+
buffer: {
|
|
8131
|
+
type: 'uniform'
|
|
8132
|
+
}
|
|
8133
|
+
}])];
|
|
8134
|
+
console.log("BG E : ", e);
|
|
7934
8135
|
this.bglForRender = this.device.createBindGroupLayout({
|
|
7935
|
-
|
|
7936
|
-
|
|
7937
|
-
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
|
|
7938
|
-
buffer: {
|
|
7939
|
-
type: 'uniform'
|
|
7940
|
-
}
|
|
7941
|
-
}, {
|
|
7942
|
-
binding: 1,
|
|
7943
|
-
visibility: GPUShaderStage.FRAGMENT,
|
|
7944
|
-
texture: {
|
|
7945
|
-
sampleType: 'depth'
|
|
7946
|
-
}
|
|
7947
|
-
}, {
|
|
7948
|
-
binding: 2,
|
|
7949
|
-
visibility: GPUShaderStage.FRAGMENT,
|
|
7950
|
-
sampler: {
|
|
7951
|
-
type: 'comparison'
|
|
7952
|
-
}
|
|
7953
|
-
}, ...(this.isVideo ? [
|
|
7954
|
-
// VIDEO
|
|
7955
|
-
{
|
|
7956
|
-
binding: 3,
|
|
7957
|
-
visibility: GPUShaderStage.FRAGMENT,
|
|
7958
|
-
externalTexture: {}
|
|
7959
|
-
}, {
|
|
7960
|
-
binding: 4,
|
|
7961
|
-
visibility: GPUShaderStage.FRAGMENT,
|
|
7962
|
-
sampler: {
|
|
7963
|
-
type: 'filtering'
|
|
7964
|
-
} // for video sampling
|
|
7965
|
-
}, {
|
|
7966
|
-
binding: 5,
|
|
7967
|
-
visibility: GPUShaderStage.FRAGMENT,
|
|
7968
|
-
buffer: {
|
|
7969
|
-
type: 'uniform'
|
|
7970
|
-
}
|
|
7971
|
-
}] : [
|
|
7972
|
-
// IMAGE
|
|
7973
|
-
{
|
|
7974
|
-
binding: 3,
|
|
7975
|
-
visibility: GPUShaderStage.FRAGMENT,
|
|
7976
|
-
texture: {
|
|
7977
|
-
sampleType: 'float',
|
|
7978
|
-
viewDimension: '2d'
|
|
7979
|
-
}
|
|
7980
|
-
}, {
|
|
7981
|
-
binding: 4,
|
|
7982
|
-
visibility: GPUShaderStage.FRAGMENT,
|
|
7983
|
-
sampler: {
|
|
7984
|
-
type: 'filtering'
|
|
7985
|
-
}
|
|
7986
|
-
}, {
|
|
7987
|
-
binding: 5,
|
|
7988
|
-
visibility: GPUShaderStage.FRAGMENT,
|
|
7989
|
-
buffer: {
|
|
7990
|
-
type: 'uniform'
|
|
7991
|
-
}
|
|
7992
|
-
}])]
|
|
8136
|
+
label: 'bglForRender',
|
|
8137
|
+
entries: e
|
|
7993
8138
|
});
|
|
8139
|
+
if (this.isVideo == true) {
|
|
8140
|
+
this.createBindGroupForRender();
|
|
8141
|
+
}
|
|
7994
8142
|
}
|
|
7995
8143
|
}
|
|
7996
8144
|
exports.default = Materials;
|
|
@@ -8248,9 +8396,9 @@ var _materials = _interopRequireDefault(require("./materials"));
|
|
|
8248
8396
|
var _fragmentVideo = require("../shaders/fragment.video.wgsl");
|
|
8249
8397
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
8250
8398
|
class MEMeshObj extends _materials.default {
|
|
8251
|
-
constructor(canvas, device, context, o,
|
|
8399
|
+
constructor(canvas, device, context, o, inputHandler) {
|
|
8252
8400
|
super(device);
|
|
8253
|
-
if (typeof o.name === 'undefined') o.name = (0, _utils.genName)(
|
|
8401
|
+
if (typeof o.name === 'undefined') o.name = (0, _utils.genName)(3);
|
|
8254
8402
|
if (typeof o.raycast === 'undefined') {
|
|
8255
8403
|
this.raycast = {
|
|
8256
8404
|
enabled: false,
|
|
@@ -8266,6 +8414,7 @@ class MEMeshObj extends _materials.default {
|
|
|
8266
8414
|
this.entityArgPass = o.entityArgPass;
|
|
8267
8415
|
this.clearColor = "red";
|
|
8268
8416
|
this.video = null;
|
|
8417
|
+
this.FINISH_VIDIO_INIT = false;
|
|
8269
8418
|
|
|
8270
8419
|
// Mesh stuff - for single mesh or t-posed (fiktive-first in loading order)
|
|
8271
8420
|
this.mesh = o.mesh;
|
|
@@ -8281,7 +8430,7 @@ class MEMeshObj extends _materials.default {
|
|
|
8281
8430
|
console.log(`%c Mesh objAnim exist: ${o.objAnim}`, _utils.LOG_FUNNY_SMALL);
|
|
8282
8431
|
this.drawElements = this.drawElementsAnim;
|
|
8283
8432
|
}
|
|
8284
|
-
this.inputHandler =
|
|
8433
|
+
this.inputHandler = inputHandler;
|
|
8285
8434
|
this.cameras = o.cameras;
|
|
8286
8435
|
this.mainCameraParams = {
|
|
8287
8436
|
type: o.mainCameraParams.type,
|
|
@@ -8302,7 +8451,6 @@ class MEMeshObj extends _materials.default {
|
|
|
8302
8451
|
this.runProgram = () => {
|
|
8303
8452
|
return new Promise(async resolve => {
|
|
8304
8453
|
this.shadowDepthTextureSize = 1024;
|
|
8305
|
-
// const aspect = canvas.width / canvas.height;
|
|
8306
8454
|
this.modelViewProjectionMatrix = _wgpuMatrix.mat4.create();
|
|
8307
8455
|
this.loadTex0(this.texturesPaths).then(() => {
|
|
8308
8456
|
resolve();
|
|
@@ -8310,7 +8458,6 @@ class MEMeshObj extends _materials.default {
|
|
|
8310
8458
|
});
|
|
8311
8459
|
};
|
|
8312
8460
|
this.runProgram().then(() => {
|
|
8313
|
-
// const aspect = canvas.width / canvas.height;
|
|
8314
8461
|
this.context.configure({
|
|
8315
8462
|
device: this.device,
|
|
8316
8463
|
format: this.presentationFormat,
|
|
@@ -8367,14 +8514,6 @@ class MEMeshObj extends _materials.default {
|
|
|
8367
8514
|
this.indexBuffer.unmap();
|
|
8368
8515
|
this.indexCount = indexCount;
|
|
8369
8516
|
|
|
8370
|
-
// Create the depth texture for rendering/sampling the shadow map.
|
|
8371
|
-
this.shadowDepthTexture = this.device.createTexture({
|
|
8372
|
-
size: [this.shadowDepthTextureSize, this.shadowDepthTextureSize, 1],
|
|
8373
|
-
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,
|
|
8374
|
-
format: 'depth32float'
|
|
8375
|
-
});
|
|
8376
|
-
this.shadowDepthTextureView = this.shadowDepthTexture.createView();
|
|
8377
|
-
|
|
8378
8517
|
// Create some common descriptors used for both the shadow pipeline
|
|
8379
8518
|
// and the color rendering pipeline.
|
|
8380
8519
|
this.vertexBuffers = [{
|
|
@@ -8404,91 +8543,37 @@ class MEMeshObj extends _materials.default {
|
|
|
8404
8543
|
}];
|
|
8405
8544
|
this.primitive = {
|
|
8406
8545
|
topology: 'triangle-list',
|
|
8407
|
-
|
|
8408
|
-
|
|
8546
|
+
cullMode: 'back',
|
|
8547
|
+
// typical for shadow passes
|
|
8548
|
+
frontFace: 'ccw'
|
|
8409
8549
|
};
|
|
8410
|
-
this.uniformBufferBindGroupLayout = this.device.createBindGroupLayout({
|
|
8411
|
-
entries: [{
|
|
8412
|
-
binding: 0,
|
|
8413
|
-
visibility: GPUShaderStage.VERTEX,
|
|
8414
|
-
buffer: {
|
|
8415
|
-
type: 'uniform'
|
|
8416
|
-
}
|
|
8417
|
-
}]
|
|
8418
|
-
});
|
|
8419
|
-
this.shadowPipeline = this.device.createRenderPipeline({
|
|
8420
|
-
layout: this.device.createPipelineLayout({
|
|
8421
|
-
bindGroupLayouts: [this.uniformBufferBindGroupLayout, this.uniformBufferBindGroupLayout]
|
|
8422
|
-
}),
|
|
8423
|
-
vertex: {
|
|
8424
|
-
module: this.device.createShaderModule({
|
|
8425
|
-
code: _vertexShadow.vertexShadowWGSL
|
|
8426
|
-
}),
|
|
8427
|
-
buffers: this.vertexBuffers
|
|
8428
|
-
},
|
|
8429
|
-
depthStencil: {
|
|
8430
|
-
depthWriteEnabled: true,
|
|
8431
|
-
depthCompare: 'less',
|
|
8432
|
-
format: 'depth32float'
|
|
8433
|
-
},
|
|
8434
|
-
primitive: this.primitive
|
|
8435
|
-
});
|
|
8436
8550
|
|
|
8437
8551
|
// Create a bind group layout which holds the scene uniforms and
|
|
8438
8552
|
// the texture+sampler for depth. We create it manually because the WebPU
|
|
8439
8553
|
// implementation doesn't infer this from the shader (yet).
|
|
8440
8554
|
this.createLayoutForRender();
|
|
8441
|
-
this.setupPipeline();
|
|
8442
|
-
const depthTexture = this.device.createTexture({
|
|
8443
|
-
size: [canvas.width, canvas.height],
|
|
8444
|
-
// format: 'depth24plus-stencil8',
|
|
8445
|
-
format: 'depth24plus',
|
|
8446
|
-
usage: GPUTextureUsage.RENDER_ATTACHMENT
|
|
8447
|
-
});
|
|
8448
|
-
this.renderPassDescriptor = {
|
|
8449
|
-
colorAttachments: [{
|
|
8450
|
-
// view is acquired and set in render loop.
|
|
8451
|
-
view: undefined,
|
|
8452
|
-
clearValue: this.clearColor,
|
|
8453
|
-
loadOp: 'clear',
|
|
8454
|
-
// load -> clear = fix for FF
|
|
8455
|
-
storeOp: 'store'
|
|
8456
|
-
}],
|
|
8457
|
-
depthStencilAttachment: {
|
|
8458
|
-
view: depthTexture.createView(),
|
|
8459
|
-
depthClearValue: 1.0,
|
|
8460
|
-
depthLoadOp: 'clear',
|
|
8461
|
-
depthStoreOp: 'store'
|
|
8462
|
-
// stencilClearValue: 0,
|
|
8463
|
-
// stencilLoadOp: 'clear',
|
|
8464
|
-
// stencilStoreOp: 'store',
|
|
8465
|
-
}
|
|
8466
|
-
};
|
|
8467
8555
|
this.modelUniformBuffer = this.device.createBuffer({
|
|
8468
8556
|
size: 4 * 16,
|
|
8469
8557
|
// 4x4 matrix
|
|
8470
8558
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
8471
8559
|
});
|
|
8472
8560
|
this.sceneUniformBuffer = this.device.createBuffer({
|
|
8473
|
-
|
|
8474
|
-
|
|
8475
|
-
// Then a vec3 for the light position.
|
|
8476
|
-
// Rounded to the nearest multiple of 16.
|
|
8477
|
-
size: 2 * 4 * 16 + 4 * 4,
|
|
8561
|
+
label: 'sceneUniformBuffer per mesh',
|
|
8562
|
+
size: 160,
|
|
8478
8563
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
8479
8564
|
});
|
|
8480
|
-
|
|
8481
|
-
|
|
8482
|
-
layout: this.uniformBufferBindGroupLayout,
|
|
8565
|
+
this.uniformBufferBindGroupLayout = this.device.createBindGroupLayout({
|
|
8566
|
+
label: 'uniformBufferBindGroupLayout in mesh',
|
|
8483
8567
|
entries: [{
|
|
8484
8568
|
binding: 0,
|
|
8485
|
-
|
|
8486
|
-
|
|
8569
|
+
visibility: GPUShaderStage.VERTEX,
|
|
8570
|
+
buffer: {
|
|
8571
|
+
type: 'uniform'
|
|
8487
8572
|
}
|
|
8488
8573
|
}]
|
|
8489
8574
|
});
|
|
8490
|
-
this.createBindGroupForRender();
|
|
8491
8575
|
this.modelBindGroup = this.device.createBindGroup({
|
|
8576
|
+
label: 'modelBindGroup in mesh',
|
|
8492
8577
|
layout: this.uniformBufferBindGroupLayout,
|
|
8493
8578
|
entries: [{
|
|
8494
8579
|
binding: 0,
|
|
@@ -8497,49 +8582,49 @@ class MEMeshObj extends _materials.default {
|
|
|
8497
8582
|
}
|
|
8498
8583
|
}]
|
|
8499
8584
|
});
|
|
8585
|
+
this.mainPassBindGroupLayout = this.device.createBindGroupLayout({
|
|
8586
|
+
entries: [{
|
|
8587
|
+
binding: 0,
|
|
8588
|
+
visibility: GPUShaderStage.FRAGMENT,
|
|
8589
|
+
texture: {
|
|
8590
|
+
sampleType: 'depth'
|
|
8591
|
+
}
|
|
8592
|
+
}, {
|
|
8593
|
+
binding: 1,
|
|
8594
|
+
visibility: GPUShaderStage.FRAGMENT,
|
|
8595
|
+
sampler: {
|
|
8596
|
+
type: 'comparison'
|
|
8597
|
+
}
|
|
8598
|
+
}]
|
|
8599
|
+
});
|
|
8500
8600
|
|
|
8501
8601
|
// Rotates the camera around the origin based on time.
|
|
8502
|
-
this.getTransformationMatrix =
|
|
8602
|
+
this.getTransformationMatrix = (mainRenderBundle, spotLight) => {
|
|
8503
8603
|
const now = Date.now();
|
|
8504
|
-
const
|
|
8604
|
+
const dt = (now - this.lastFrameMS) / this.mainCameraParams.responseCoef;
|
|
8505
8605
|
this.lastFrameMS = now;
|
|
8506
|
-
// const this.viewMatrix = mat4.identity()
|
|
8507
8606
|
const camera = this.cameras[this.mainCameraParams.type];
|
|
8508
|
-
|
|
8509
|
-
// engine frame
|
|
8510
8607
|
camera.update(dt, inputHandler());
|
|
8511
8608
|
const camVP = _wgpuMatrix.mat4.multiply(camera.projectionMatrix, camera.view);
|
|
8512
8609
|
for (const mesh of mainRenderBundle) {
|
|
8513
|
-
//
|
|
8514
|
-
|
|
8515
|
-
|
|
8610
|
+
// Flattened buffer: lightVP(16) + camVP(16) + cameraPos(3+pad) + lightPos(3+pad)
|
|
8611
|
+
const sceneData = new Float32Array(16 + 16 + 4 + 4); // 16+16+4+4 = 40 floats
|
|
8612
|
+
|
|
8613
|
+
// Light ViewProj
|
|
8516
8614
|
sceneData.set(spotLight.viewProjMatrix, 0);
|
|
8615
|
+
|
|
8616
|
+
// Camera VP
|
|
8517
8617
|
sceneData.set(camVP, 16);
|
|
8518
|
-
|
|
8618
|
+
|
|
8619
|
+
// Camera position + padding
|
|
8620
|
+
sceneData.set([camera.position.x, camera.position.y, camera.position.z, 0.0], 32);
|
|
8621
|
+
|
|
8622
|
+
// Light position + padding
|
|
8623
|
+
sceneData.set([spotLight.position[0], spotLight.position[1], spotLight.position[2], 0.0], 36);
|
|
8519
8624
|
device.queue.writeBuffer(mesh.sceneUniformBuffer,
|
|
8520
|
-
// or
|
|
8625
|
+
// or shared buffer
|
|
8521
8626
|
0, sceneData.buffer, sceneData.byteOffset, sceneData.byteLength);
|
|
8522
8627
|
}
|
|
8523
|
-
// this.viewMatrix = camera.update(deltaTime, this.inputHandler());
|
|
8524
|
-
// const scaleVec = [1, 1, 1]; // your desired scale OPTION 1
|
|
8525
|
-
// const scaleMatrix = mat4.scaling(scaleVec);
|
|
8526
|
-
// // Apply scaling
|
|
8527
|
-
// mat4.multiply(scaleMatrix, this.viewMatrix, this.viewMatrix);
|
|
8528
|
-
// mat4.translate(this.viewMatrix, vec3.fromValues(pos.x, pos.y, pos.z), this.viewMatrix);
|
|
8529
|
-
|
|
8530
|
-
// if(this.itIsPhysicsBody == true) {
|
|
8531
|
-
// mat4.rotate(
|
|
8532
|
-
// this.viewMatrix,
|
|
8533
|
-
// vec3.fromValues(this.rotation.axis.x, this.rotation.axis.y, this.rotation.axis.z),
|
|
8534
|
-
// degToRad(this.rotation.angle), this.viewMatrix)
|
|
8535
|
-
// } else {
|
|
8536
|
-
// mat4.rotateX(this.viewMatrix, Math.PI * this.rotation.getRotX(), this.viewMatrix);
|
|
8537
|
-
// mat4.rotateY(this.viewMatrix, Math.PI * this.rotation.getRotY(), this.viewMatrix);
|
|
8538
|
-
// mat4.rotateZ(this.viewMatrix, Math.PI * this.rotation.getRotZ(), this.viewMatrix);
|
|
8539
|
-
// // console.info('NOT PHYSICS angle: ', this.rotation.angle, ' axis ', this.rotation.axis.x, ' , ', this.rotation.axis.y, ' , ', this.rotation.axis.z)
|
|
8540
|
-
// }
|
|
8541
|
-
// mat4.multiply(camera.projectionMatrix, this.viewMatrix, this.modelViewProjectionMatrix);
|
|
8542
|
-
// return this.modelViewProjectionMatrix;
|
|
8543
8628
|
};
|
|
8544
8629
|
this.getModelMatrix = pos => {
|
|
8545
8630
|
let modelMatrix = _wgpuMatrix.mat4.identity();
|
|
@@ -8560,32 +8645,29 @@ class MEMeshObj extends _materials.default {
|
|
|
8560
8645
|
const modelMatrix = _wgpuMatrix.mat4.translation([0, 0, 0]);
|
|
8561
8646
|
const modelData = modelMatrix;
|
|
8562
8647
|
this.device.queue.writeBuffer(this.modelUniformBuffer, 0, modelData.buffer, modelData.byteOffset, modelData.byteLength);
|
|
8563
|
-
this.shadowPassDescriptor = {
|
|
8564
|
-
colorAttachments: [],
|
|
8565
|
-
depthStencilAttachment: {
|
|
8566
|
-
view: this.shadowDepthTextureView,
|
|
8567
|
-
depthClearValue: 1.0,
|
|
8568
|
-
depthLoadOp: 'clear',
|
|
8569
|
-
depthStoreOp: 'store'
|
|
8570
|
-
}
|
|
8571
|
-
};
|
|
8572
8648
|
this.done = true;
|
|
8649
|
+
try {
|
|
8650
|
+
this.setupPipeline();
|
|
8651
|
+
} catch (err) {
|
|
8652
|
+
console.log('err in create pipeline in init ', err);
|
|
8653
|
+
}
|
|
8573
8654
|
}).then(() => {
|
|
8574
8655
|
if (typeof this.objAnim !== 'undefined' && this.objAnim !== null) {
|
|
8575
|
-
console.log('after all
|
|
8656
|
+
console.log('after all updateMeshListBuffers...');
|
|
8576
8657
|
this.updateMeshListBuffers();
|
|
8577
8658
|
}
|
|
8578
8659
|
});
|
|
8579
8660
|
}
|
|
8580
8661
|
setupPipeline = () => {
|
|
8581
|
-
|
|
8662
|
+
this.createBindGroupForRender();
|
|
8582
8663
|
this.pipeline = this.device.createRenderPipeline({
|
|
8664
|
+
label: 'Mesh Pipeline ✅',
|
|
8583
8665
|
layout: this.device.createPipelineLayout({
|
|
8666
|
+
label: 'createPipelineLayout Mesh',
|
|
8584
8667
|
bindGroupLayouts: [this.bglForRender, this.uniformBufferBindGroupLayout]
|
|
8585
8668
|
}),
|
|
8586
8669
|
vertex: {
|
|
8587
8670
|
entryPoint: 'main',
|
|
8588
|
-
// ✅ Add this
|
|
8589
8671
|
module: this.device.createShaderModule({
|
|
8590
8672
|
code: _vertex.vertexWGSL
|
|
8591
8673
|
}),
|
|
@@ -8593,7 +8675,6 @@ class MEMeshObj extends _materials.default {
|
|
|
8593
8675
|
},
|
|
8594
8676
|
fragment: {
|
|
8595
8677
|
entryPoint: 'main',
|
|
8596
|
-
// ✅ Add this
|
|
8597
8678
|
module: this.device.createShaderModule({
|
|
8598
8679
|
code: this.isVideo == true ? _fragmentVideo.fragmentVideoWGSL : _fragment.fragmentWGSL
|
|
8599
8680
|
}),
|
|
@@ -8607,42 +8688,17 @@ class MEMeshObj extends _materials.default {
|
|
|
8607
8688
|
depthStencil: {
|
|
8608
8689
|
depthWriteEnabled: true,
|
|
8609
8690
|
depthCompare: 'less',
|
|
8610
|
-
// format: 'depth24plus-stencil8',
|
|
8611
8691
|
format: 'depth24plus'
|
|
8612
8692
|
},
|
|
8613
8693
|
primitive: this.primitive
|
|
8614
8694
|
});
|
|
8695
|
+
console.log('✅Set Pipeline done');
|
|
8615
8696
|
};
|
|
8616
|
-
|
|
8617
|
-
// This code -> light follow camera. can be used like options later!
|
|
8618
|
-
// if(this.done == false) return;
|
|
8619
|
-
// const transformationMatrix = this.getTransformationMatrix(this.position);
|
|
8620
|
-
// this.device.queue.writeBuffer(this.sceneUniformBuffer, 64, transformationMatrix.buffer, transformationMatrix.byteOffset, transformationMatrix.byteLength);
|
|
8621
|
-
// this.renderPassDescriptor.colorAttachments[0].view = this.context
|
|
8622
|
-
// .getCurrentTexture()
|
|
8623
|
-
// .createView();
|
|
8624
|
-
|
|
8625
|
-
// test
|
|
8697
|
+
updateModelUniformBuffer = () => {
|
|
8626
8698
|
if (this.done == false) return;
|
|
8627
|
-
|
|
8628
8699
|
// Per-object model matrix only
|
|
8629
8700
|
const modelMatrix = this.getModelMatrix(this.position);
|
|
8630
8701
|
this.device.queue.writeBuffer(this.modelUniformBuffer, 0, modelMatrix.buffer, modelMatrix.byteOffset, modelMatrix.byteLength);
|
|
8631
|
-
|
|
8632
|
-
// Acquire swapchain view for the pass
|
|
8633
|
-
this.renderPassDescriptor.colorAttachments[0].view = this.context.getCurrentTexture().createView();
|
|
8634
|
-
};
|
|
8635
|
-
drawElements = renderPass => {
|
|
8636
|
-
if (this.isVideo) {
|
|
8637
|
-
this.updateVideoTexture();
|
|
8638
|
-
}
|
|
8639
|
-
renderPass.setBindGroup(0, this.sceneBindGroupForRender);
|
|
8640
|
-
renderPass.setBindGroup(1, this.modelBindGroup);
|
|
8641
|
-
renderPass.setVertexBuffer(0, this.vertexBuffer);
|
|
8642
|
-
renderPass.setVertexBuffer(1, this.vertexNormalsBuffer);
|
|
8643
|
-
renderPass.setVertexBuffer(2, this.vertexTexCoordsBuffer);
|
|
8644
|
-
renderPass.setIndexBuffer(this.indexBuffer, 'uint16');
|
|
8645
|
-
renderPass.drawIndexed(this.indexCount);
|
|
8646
8702
|
};
|
|
8647
8703
|
createGPUBuffer(dataArray, usage) {
|
|
8648
8704
|
if (!dataArray || typeof dataArray.length !== 'number') {
|
|
@@ -8680,7 +8736,6 @@ class MEMeshObj extends _materials.default {
|
|
|
8680
8736
|
});
|
|
8681
8737
|
new Float32Array(mesh.vertexNormalsBuffer.getMappedRange()).set(mesh.vertexNormals);
|
|
8682
8738
|
mesh.vertexNormalsBuffer.unmap();
|
|
8683
|
-
|
|
8684
8739
|
// UVs
|
|
8685
8740
|
mesh.vertexTexCoordsBuffer = this.device.createBuffer({
|
|
8686
8741
|
size: mesh.textures.length * Float32Array.BYTES_PER_ELEMENT,
|
|
@@ -8689,7 +8744,6 @@ class MEMeshObj extends _materials.default {
|
|
|
8689
8744
|
});
|
|
8690
8745
|
new Float32Array(mesh.vertexTexCoordsBuffer.getMappedRange()).set(mesh.textures);
|
|
8691
8746
|
mesh.vertexTexCoordsBuffer.unmap();
|
|
8692
|
-
|
|
8693
8747
|
// Indices
|
|
8694
8748
|
const indexCount = mesh.indices.length;
|
|
8695
8749
|
const indexSize = Math.ceil(indexCount * Uint16Array.BYTES_PER_ELEMENT / 4) * 4;
|
|
@@ -8703,7 +8757,35 @@ class MEMeshObj extends _materials.default {
|
|
|
8703
8757
|
mesh.indexCount = indexCount;
|
|
8704
8758
|
}
|
|
8705
8759
|
}
|
|
8760
|
+
drawElements = (pass, lightContainer) => {
|
|
8761
|
+
if (this.isVideo) {
|
|
8762
|
+
this.updateVideoTexture();
|
|
8763
|
+
}
|
|
8764
|
+
// Bind per-mesh uniforms
|
|
8765
|
+
pass.setBindGroup(0, this.sceneBindGroupForRender); // camera/light UBOs
|
|
8766
|
+
pass.setBindGroup(1, this.modelBindGroup); // mesh transforms/textures
|
|
8767
|
+
// Bind each light’s shadow texture & sampler
|
|
8768
|
+
if (this.isVideo == false) {
|
|
8769
|
+
let bindIndex = 2; // start after UBO & model
|
|
8770
|
+
for (const light of lightContainer) {
|
|
8771
|
+
pass.setBindGroup(bindIndex++, light.getMainPassBindGroup(this));
|
|
8772
|
+
}
|
|
8773
|
+
}
|
|
8774
|
+
pass.setVertexBuffer(0, this.vertexBuffer);
|
|
8775
|
+
pass.setVertexBuffer(1, this.vertexNormalsBuffer);
|
|
8776
|
+
pass.setVertexBuffer(2, this.vertexTexCoordsBuffer);
|
|
8777
|
+
pass.setIndexBuffer(this.indexBuffer, 'uint16');
|
|
8778
|
+
pass.drawIndexed(this.indexCount);
|
|
8779
|
+
};
|
|
8706
8780
|
drawElementsAnim = renderPass => {
|
|
8781
|
+
if (!this.sceneBindGroupForRender || !this.modelBindGroup) {
|
|
8782
|
+
console.log(' NULL 1');
|
|
8783
|
+
return;
|
|
8784
|
+
}
|
|
8785
|
+
if (!this.objAnim.meshList[this.objAnim.id + this.objAnim.currentAni]) {
|
|
8786
|
+
console.log(' NULL 2');
|
|
8787
|
+
return;
|
|
8788
|
+
}
|
|
8707
8789
|
renderPass.setBindGroup(0, this.sceneBindGroupForRender);
|
|
8708
8790
|
renderPass.setBindGroup(1, this.modelBindGroup);
|
|
8709
8791
|
const mesh = this.objAnim.meshList[this.objAnim.id + this.objAnim.currentAni];
|
|
@@ -8724,9 +8806,7 @@ class MEMeshObj extends _materials.default {
|
|
|
8724
8806
|
}
|
|
8725
8807
|
}
|
|
8726
8808
|
};
|
|
8727
|
-
drawShadows = shadowPass => {
|
|
8728
|
-
shadowPass.setBindGroup(0, this.sceneBindGroupForShadow);
|
|
8729
|
-
shadowPass.setBindGroup(1, this.modelBindGroup);
|
|
8809
|
+
drawShadows = (shadowPass, light) => {
|
|
8730
8810
|
shadowPass.setVertexBuffer(0, this.vertexBuffer);
|
|
8731
8811
|
shadowPass.setVertexBuffer(1, this.vertexNormalsBuffer);
|
|
8732
8812
|
shadowPass.setVertexBuffer(2, this.vertexTexCoordsBuffer);
|
|
@@ -9946,7 +10026,6 @@ class MatrixAmmo {
|
|
|
9946
10026
|
CF_KINEMATIC_OBJECT: 2
|
|
9947
10027
|
};
|
|
9948
10028
|
let Ammo = this.Ammo;
|
|
9949
|
-
console.log(pOptions.radius + "<<pOptions.radius");
|
|
9950
10029
|
var colShape = new Ammo.btSphereShape(Array.isArray(pOptions.radius) ? pOptions.radius[0] : pOptions.radius),
|
|
9951
10030
|
startTransform = new Ammo.btTransform();
|
|
9952
10031
|
startTransform.setIdentity();
|
|
@@ -10106,46 +10185,11 @@ class MatrixAmmo {
|
|
|
10106
10185
|
// if(item.kB == contactManifold.getBody0().kB) {
|
|
10107
10186
|
// // console.log('Detected body0 =', item.name)
|
|
10108
10187
|
// }
|
|
10109
|
-
// if(item.kB == contactManifold.getBody1().kB) {
|
|
10110
|
-
// // console.log('Detected body1 =', item.name)
|
|
10111
|
-
// }
|
|
10112
|
-
// })
|
|
10113
|
-
|
|
10114
10188
|
if (this.ground.kB == contactManifold.getBody0().kB && this.getNameByBody(contactManifold.getBody1()) == 'CubePhysics1') {
|
|
10115
10189
|
// console.log(this.ground ,'GROUND IS IN CONTACT WHO IS BODY1 ', contactManifold.getBody1())
|
|
10116
10190
|
// console.log('GROUND IS IN CONTACT WHO IS BODY1 getNameByBody ', this.getNameByBody(contactManifold.getBody1()))
|
|
10117
10191
|
// CHECK ROTATION
|
|
10118
10192
|
var testR = contactManifold.getBody1().getWorldTransform().getRotation();
|
|
10119
|
-
if (Math.abs(testR.y()) < 0.00001) {
|
|
10120
|
-
this.lastRoll += " 4 +";
|
|
10121
|
-
this.presentScore += 4;
|
|
10122
|
-
dispatchEvent(new CustomEvent('dice-1', {}));
|
|
10123
|
-
}
|
|
10124
|
-
if (Math.abs(testR.x()) < 0.00001) {
|
|
10125
|
-
this.lastRoll += " 3 +";
|
|
10126
|
-
this.presentScore += 3;
|
|
10127
|
-
dispatchEvent(new CustomEvent('dice-4', {}));
|
|
10128
|
-
}
|
|
10129
|
-
if (testR.x().toString().substring(0, 5) == testR.y().toString().substring(1, 6)) {
|
|
10130
|
-
this.lastRoll += " 2 +";
|
|
10131
|
-
this.presentScore += 2;
|
|
10132
|
-
dispatchEvent(new CustomEvent('dice-6', {}));
|
|
10133
|
-
}
|
|
10134
|
-
if (testR.x().toString().substring(0, 5) == testR.y().toString().substring(0, 5)) {
|
|
10135
|
-
this.lastRoll += " 1 +";
|
|
10136
|
-
this.presentScore += 1;
|
|
10137
|
-
dispatchEvent(new CustomEvent('dice-2', {}));
|
|
10138
|
-
}
|
|
10139
|
-
if (testR.z().toString().substring(0, 5) == testR.y().toString().substring(1, 6)) {
|
|
10140
|
-
this.lastRoll += " 6 +";
|
|
10141
|
-
this.presentScore += 6;
|
|
10142
|
-
dispatchEvent(new CustomEvent('dice-5', {}));
|
|
10143
|
-
}
|
|
10144
|
-
if (testR.z().toString().substring(0, 5) == testR.y().toString().substring(0, 5)) {
|
|
10145
|
-
this.lastRoll += " 5 +";
|
|
10146
|
-
this.presentScore += 5;
|
|
10147
|
-
dispatchEvent(new CustomEvent('dice-3', {}));
|
|
10148
|
-
}
|
|
10149
10193
|
console.log('this.lastRoll = ', this.lastRoll, ' presentScore = ', this.presentScore);
|
|
10150
10194
|
}
|
|
10151
10195
|
}
|
|
@@ -10217,18 +10261,19 @@ struct Scene {
|
|
|
10217
10261
|
@group(0) @binding(2) var shadowSampler: sampler_comparison;
|
|
10218
10262
|
@group(0) @binding(3) var meshTexture: texture_external;
|
|
10219
10263
|
@group(0) @binding(4) var meshSampler: sampler;
|
|
10220
|
-
|
|
10221
10264
|
@group(0) @binding(5) var<uniform> postFXMode: u32;
|
|
10222
10265
|
|
|
10223
10266
|
// ❌ No binding(4) here!
|
|
10224
10267
|
|
|
10225
10268
|
struct FragmentInput {
|
|
10226
|
-
@location(0) shadowPos :
|
|
10269
|
+
@location(0) shadowPos : vec4f,
|
|
10227
10270
|
@location(1) fragPos : vec3f,
|
|
10228
10271
|
@location(2) fragNorm : vec3f,
|
|
10229
10272
|
@location(3) uv : vec2f,
|
|
10230
10273
|
}
|
|
10231
10274
|
|
|
10275
|
+
|
|
10276
|
+
|
|
10232
10277
|
const albedo = vec3f(0.9);
|
|
10233
10278
|
const ambientFactor = 0.7;
|
|
10234
10279
|
|
|
@@ -10297,79 +10342,141 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
10297
10342
|
exports.fragmentWGSL = void 0;
|
|
10298
10343
|
let fragmentWGSL = exports.fragmentWGSL = `override shadowDepthTextureSize: f32 = 1024.0;
|
|
10299
10344
|
|
|
10345
|
+
// Created by Nikola Lukic with chatgtp assist.
|
|
10346
|
+
|
|
10300
10347
|
struct Scene {
|
|
10301
|
-
|
|
10302
|
-
|
|
10303
|
-
|
|
10304
|
-
|
|
10305
|
-
|
|
10348
|
+
lightViewProjMatrix : mat4x4f,
|
|
10349
|
+
cameraViewProjMatrix : mat4x4f,
|
|
10350
|
+
cameraPos : vec3f,
|
|
10351
|
+
padding2 : f32, // align to 16 bytes
|
|
10352
|
+
lightPos : vec3f,
|
|
10353
|
+
padding : f32, // align to 16 bytes
|
|
10354
|
+
};
|
|
10306
10355
|
|
|
10307
10356
|
struct SpotLight {
|
|
10308
|
-
|
|
10309
|
-
|
|
10310
|
-
|
|
10311
|
-
|
|
10312
|
-
|
|
10313
|
-
|
|
10314
|
-
|
|
10315
|
-
|
|
10357
|
+
position : vec3f,
|
|
10358
|
+
_pad1 : f32,
|
|
10359
|
+
|
|
10360
|
+
direction : vec3f,
|
|
10361
|
+
_pad2 : f32,
|
|
10362
|
+
|
|
10363
|
+
innerCutoff : f32,
|
|
10364
|
+
outerCutoff : f32,
|
|
10365
|
+
intensity : f32,
|
|
10366
|
+
_pad3 : f32,
|
|
10367
|
+
|
|
10368
|
+
color : vec3f,
|
|
10369
|
+
_pad4 : f32,
|
|
10370
|
+
|
|
10371
|
+
range : f32,
|
|
10372
|
+
ambientFactor : f32,
|
|
10373
|
+
shadowBias : f32,
|
|
10374
|
+
_pad5 : f32,
|
|
10375
|
+
|
|
10376
|
+
lightViewProj : mat4x4<f32>,
|
|
10377
|
+
};
|
|
10378
|
+
|
|
10379
|
+
const MAX_SPOTLIGHTS = 20u;
|
|
10316
10380
|
|
|
10317
10381
|
@group(0) @binding(0) var<uniform> scene : Scene;
|
|
10318
|
-
@group(0) @binding(1) var
|
|
10382
|
+
@group(0) @binding(1) var shadowMapArray: texture_depth_2d_array;
|
|
10319
10383
|
@group(0) @binding(2) var shadowSampler: sampler_comparison;
|
|
10320
10384
|
@group(0) @binding(3) var meshTexture: texture_2d<f32>;
|
|
10321
10385
|
@group(0) @binding(4) var meshSampler: sampler;
|
|
10322
|
-
@group(0) @binding(5) var<uniform>
|
|
10386
|
+
@group(0) @binding(5) var<uniform> spotlights: array<SpotLight, MAX_SPOTLIGHTS>;
|
|
10323
10387
|
|
|
10324
10388
|
struct FragmentInput {
|
|
10325
|
-
|
|
10326
|
-
|
|
10327
|
-
|
|
10328
|
-
|
|
10389
|
+
@location(0) shadowPos : vec4f,
|
|
10390
|
+
@location(1) fragPos : vec3f,
|
|
10391
|
+
@location(2) fragNorm : vec3f,
|
|
10392
|
+
@location(3) uv : vec2f,
|
|
10329
10393
|
}
|
|
10330
10394
|
|
|
10331
10395
|
const albedo = vec3f(0.9);
|
|
10332
|
-
const ambientFactor = 0.7;
|
|
10333
10396
|
|
|
10334
10397
|
fn calculateSpotlightFactor(light: SpotLight, fragPos: vec3f) -> f32 {
|
|
10335
|
-
|
|
10336
|
-
|
|
10337
|
-
|
|
10338
|
-
|
|
10339
|
-
return intensity;
|
|
10398
|
+
let L = normalize(light.position - fragPos);
|
|
10399
|
+
let theta = dot(L, normalize(-light.direction));
|
|
10400
|
+
let epsilon = light.innerCutoff - light.outerCutoff;
|
|
10401
|
+
return clamp((theta - light.outerCutoff) / epsilon, 0.0, 1.0);
|
|
10340
10402
|
}
|
|
10341
10403
|
|
|
10342
|
-
|
|
10343
|
-
|
|
10344
|
-
|
|
10345
|
-
|
|
10346
|
-
let oneOverSize = 1.0 / shadowDepthTextureSize;
|
|
10347
|
-
for (var y = -1; y <= 1; y++) {
|
|
10348
|
-
for (var x = -1; x <= 1; x++) {
|
|
10349
|
-
let offset = vec2f(vec2(x, y)) * oneOverSize;
|
|
10350
|
-
visibility += textureSampleCompare(
|
|
10351
|
-
shadowMap, shadowSampler,
|
|
10352
|
-
input.shadowPos.xy + offset, input.shadowPos.z - 0.007
|
|
10353
|
-
);
|
|
10354
|
-
}
|
|
10355
|
-
}
|
|
10356
|
-
visibility /= 9.0;
|
|
10404
|
+
fn computeSpotLight(light: SpotLight, normal: vec3f, fragPos: vec3f, viewDir: vec3f) -> vec3f {
|
|
10405
|
+
let L = light.position - fragPos;
|
|
10406
|
+
let distance = length(L);
|
|
10407
|
+
let lightDir = normalize(L);
|
|
10357
10408
|
|
|
10358
|
-
|
|
10359
|
-
|
|
10360
|
-
let lightDir = normalize(scene.lightPos - input.fragPos);
|
|
10361
|
-
let lambert = max(dot(norm, lightDir), 0.0);
|
|
10409
|
+
let spotFactor = calculateSpotlightFactor(light, fragPos);
|
|
10410
|
+
let atten = clamp(1.0 - (distance / light.range), 0.0, 1.0);
|
|
10362
10411
|
|
|
10363
|
-
|
|
10364
|
-
|
|
10412
|
+
let diff = max(dot(normal, lightDir), 0.0);
|
|
10413
|
+
let halfwayDir = normalize(lightDir + viewDir);
|
|
10414
|
+
let spec = pow(max(dot(normal, halfwayDir), 0.0), 32.0);
|
|
10365
10415
|
|
|
10366
|
-
|
|
10367
|
-
|
|
10368
|
-
let texColor = textureSample(meshTexture, meshSampler, input.uv);
|
|
10416
|
+
let diffuse = diff * light.color * light.intensity * atten;
|
|
10417
|
+
let specular = spec * light.color * light.intensity * atten;
|
|
10369
10418
|
|
|
10370
|
-
|
|
10419
|
+
return (diffuse + specular) * spotFactor;
|
|
10371
10420
|
}
|
|
10372
|
-
|
|
10421
|
+
|
|
10422
|
+
// Corrected PCF for texture_depth_2d_array
|
|
10423
|
+
fn sampleShadow(shadowUV: vec2f, layer: i32, depthRef: f32, normal: vec3f, lightDir: vec3f) -> f32 {
|
|
10424
|
+
var visibility: f32 = 0.0;
|
|
10425
|
+
let biasConstant: f32 = 0.001;
|
|
10426
|
+
// Slope bias: avoid self-shadowing on steep angles
|
|
10427
|
+
// let slopeBias: f32 = max(0.002 * (1.0 - dot(normal, lightDir)), 0.0);
|
|
10428
|
+
let bias = biasConstant;// + slopeBias;
|
|
10429
|
+
|
|
10430
|
+
let oneOverSize = 1.0 / (shadowDepthTextureSize * 0.5);
|
|
10431
|
+
|
|
10432
|
+
// 3x3 PCF kernel
|
|
10433
|
+
let offsets: array<vec2f, 9> = array<vec2f, 9>(
|
|
10434
|
+
vec2(-1.0, -1.0), vec2(0.0, -1.0), vec2(1.0, -1.0),
|
|
10435
|
+
vec2(-1.0, 0.0), vec2(0.0, 0.0), vec2(1.0, 0.0),
|
|
10436
|
+
vec2(-1.0, 1.0), vec2(0.0, 1.0), vec2(1.0, 1.0)
|
|
10437
|
+
);
|
|
10438
|
+
|
|
10439
|
+
for(var i: u32 = 0u; i < 9u; i = i + 1u) {
|
|
10440
|
+
visibility += textureSampleCompare(
|
|
10441
|
+
shadowMapArray,
|
|
10442
|
+
shadowSampler,
|
|
10443
|
+
shadowUV + offsets[i] * oneOverSize,
|
|
10444
|
+
layer,
|
|
10445
|
+
depthRef //+ bias
|
|
10446
|
+
);
|
|
10447
|
+
}
|
|
10448
|
+
return visibility / 9.0;
|
|
10449
|
+
}
|
|
10450
|
+
|
|
10451
|
+
@fragment
|
|
10452
|
+
fn main(input: FragmentInput) -> @location(0) vec4f {
|
|
10453
|
+
let norm = normalize(input.fragNorm);
|
|
10454
|
+
|
|
10455
|
+
let viewDir = normalize(scene.cameraPos - input.fragPos);
|
|
10456
|
+
// let viewDir = normalize(scene.cameraViewProjMatrix[3].xyz - input.fragPos);
|
|
10457
|
+
|
|
10458
|
+
var lightContribution = vec3f(0.0);
|
|
10459
|
+
var ambient = vec3f(0.0);
|
|
10460
|
+
|
|
10461
|
+
for (var i: u32 = 0u; i < MAX_SPOTLIGHTS; i = i + 1u) {
|
|
10462
|
+
let sc = spotlights[i].lightViewProj * vec4<f32>(input.fragPos, 1.0);
|
|
10463
|
+
let p = sc.xyz / sc.w;
|
|
10464
|
+
let uv = clamp(p.xy * 0.5 + vec2<f32>(0.5), vec2<f32>(0.0), vec2<f32>(1.0));
|
|
10465
|
+
let depthRef = p.z * 0.5 + 0.5;
|
|
10466
|
+
let lightDir = normalize(spotlights[i].position - input.fragPos);
|
|
10467
|
+
let angleFactor = 1.0 - dot(norm, lightDir);
|
|
10468
|
+
let slopeBias = 0.01 * (1.0 - dot(norm, lightDir));
|
|
10469
|
+
let bias = spotlights[i].shadowBias + slopeBias;
|
|
10470
|
+
let visibility = sampleShadow(uv, i32(i), depthRef - bias, norm, lightDir);
|
|
10471
|
+
let contrib = computeSpotLight(spotlights[i], norm, input.fragPos, viewDir);
|
|
10472
|
+
lightContribution += contrib * visibility;
|
|
10473
|
+
ambient += spotlights[i].ambientFactor * spotlights[i].color;
|
|
10474
|
+
}
|
|
10475
|
+
|
|
10476
|
+
let texColor = textureSample(meshTexture, meshSampler, input.uv);
|
|
10477
|
+
let finalColor = texColor.rgb * (ambient + lightContribution); // * albedo;
|
|
10478
|
+
return vec4f(finalColor, 1.0);
|
|
10479
|
+
}`;
|
|
10373
10480
|
|
|
10374
10481
|
},{}],22:[function(require,module,exports){
|
|
10375
10482
|
"use strict";
|
|
@@ -10450,11 +10557,10 @@ struct Model {
|
|
|
10450
10557
|
@group(1) @binding(0) var<uniform> model : Model;
|
|
10451
10558
|
|
|
10452
10559
|
struct VertexOutput {
|
|
10453
|
-
@location(0) shadowPos:
|
|
10560
|
+
@location(0) shadowPos: vec4f, // now vec4
|
|
10454
10561
|
@location(1) fragPos: vec3f,
|
|
10455
10562
|
@location(2) fragNorm: vec3f,
|
|
10456
|
-
@location(3) uv
|
|
10457
|
-
|
|
10563
|
+
@location(3) uv: vec2f,
|
|
10458
10564
|
@builtin(position) Position: vec4f,
|
|
10459
10565
|
}
|
|
10460
10566
|
|
|
@@ -10462,34 +10568,21 @@ struct VertexOutput {
|
|
|
10462
10568
|
fn main(
|
|
10463
10569
|
@location(0) position: vec3f,
|
|
10464
10570
|
@location(1) normal: vec3f,
|
|
10465
|
-
@location(2) uv
|
|
10571
|
+
@location(2) uv: vec2f
|
|
10466
10572
|
) -> VertexOutput {
|
|
10467
10573
|
var output : VertexOutput;
|
|
10468
10574
|
|
|
10469
|
-
// XY is in (-1, 1) space, Z is in (0, 1) space
|
|
10470
10575
|
let posFromLight = scene.lightViewProjMatrix * model.modelMatrix * vec4(position, 1.0);
|
|
10471
|
-
|
|
10472
|
-
// Convert XY to (0, 1)
|
|
10473
|
-
// Y is flipped because texture coords are Y-down.
|
|
10474
|
-
output.shadowPos = vec3(
|
|
10475
|
-
posFromLight.xy * vec2(0.5, -0.5) + vec2(0.5),
|
|
10476
|
-
posFromLight.z
|
|
10477
|
-
);
|
|
10478
|
-
|
|
10479
|
-
// follewed camera code
|
|
10480
|
-
// output.Position = scene.cameraViewProjMatrix * model.modelMatrix * vec4(position, 1.0);
|
|
10481
|
-
// output.fragPos = output.Position.xyz;
|
|
10482
|
-
// output.fragNorm = normal;
|
|
10576
|
+
output.shadowPos = posFromLight; // pass full vec4 for perspective divide
|
|
10483
10577
|
|
|
10484
10578
|
let worldPos = model.modelMatrix * vec4(position, 1.0);
|
|
10485
10579
|
output.Position = scene.cameraViewProjMatrix * worldPos;
|
|
10486
|
-
output.fragPos = worldPos.xyz;
|
|
10580
|
+
output.fragPos = worldPos.xyz;
|
|
10487
10581
|
|
|
10488
10582
|
output.fragNorm = normalize((model.modelMatrix * vec4(normal, 0.0)).xyz);
|
|
10489
10583
|
output.uv = uv;
|
|
10490
10584
|
return output;
|
|
10491
|
-
}
|
|
10492
|
-
`;
|
|
10585
|
+
}`;
|
|
10493
10586
|
|
|
10494
10587
|
},{}],24:[function(require,module,exports){
|
|
10495
10588
|
"use strict";
|
|
@@ -10608,6 +10701,14 @@ var _sounds = require("./sounds/sounds.js");
|
|
|
10608
10701
|
var _loaderObj = require("./engine/loader-obj.js");
|
|
10609
10702
|
var _lights = require("./engine/lights.js");
|
|
10610
10703
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
10704
|
+
/**
|
|
10705
|
+
* @description
|
|
10706
|
+
* Main engine root class.
|
|
10707
|
+
* @author Nikola Lukic 2025
|
|
10708
|
+
* @email zlatnaspirala@gmail.com
|
|
10709
|
+
* @web https://maximumroulette.com
|
|
10710
|
+
* @github zlatnaspirala
|
|
10711
|
+
*/
|
|
10611
10712
|
class MatrixEngineWGPU {
|
|
10612
10713
|
mainRenderBundle = [];
|
|
10613
10714
|
lightContainer = [];
|
|
@@ -10621,10 +10722,7 @@ class MatrixEngineWGPU {
|
|
|
10621
10722
|
};
|
|
10622
10723
|
matrixAmmo = new _matrixAmmo.default();
|
|
10623
10724
|
matrixSounds = new _sounds.MatrixSounds();
|
|
10624
|
-
|
|
10625
|
-
// The input handler
|
|
10626
10725
|
constructor(options, callback) {
|
|
10627
|
-
// console.log('typeof options ', typeof options )
|
|
10628
10726
|
if (typeof options == 'undefined' || typeof options == "function") {
|
|
10629
10727
|
this.options = {
|
|
10630
10728
|
useSingleRenderPass: true,
|
|
@@ -10676,7 +10774,6 @@ class MatrixEngineWGPU {
|
|
|
10676
10774
|
|
|
10677
10775
|
// The camera types
|
|
10678
10776
|
const initialCameraPosition = _wgpuMatrix.vec3.create(0, 0, 0);
|
|
10679
|
-
// console.log('passed : o.mainCameraParams.responseCoef ', o.mainCameraParams.responseCoef)
|
|
10680
10777
|
this.mainCameraParams = {
|
|
10681
10778
|
type: this.options.mainCameraParams.type,
|
|
10682
10779
|
responseCoef: this.options.mainCameraParams.responseCoef
|
|
@@ -10713,14 +10810,6 @@ class MatrixEngineWGPU {
|
|
|
10713
10810
|
this.device = await this.adapter.requestDevice({
|
|
10714
10811
|
extensions: ["ray_tracing"]
|
|
10715
10812
|
});
|
|
10716
|
-
|
|
10717
|
-
// Maybe works in ssl with webworkers...
|
|
10718
|
-
// const adapterInfo = await this.adapter.requestAdapterInfo();
|
|
10719
|
-
// var test = this.adapter.features()
|
|
10720
|
-
// console.log(adapterInfo.vendor);
|
|
10721
|
-
// console.log('test' + test);
|
|
10722
|
-
// console.log("FEATURES : " + this.adapter.features)
|
|
10723
|
-
|
|
10724
10813
|
this.context = canvas.getContext('webgpu');
|
|
10725
10814
|
const devicePixelRatio = window.devicePixelRatio;
|
|
10726
10815
|
canvas.width = canvas.clientWidth * devicePixelRatio;
|
|
@@ -10736,20 +10825,87 @@ class MatrixEngineWGPU {
|
|
|
10736
10825
|
} else {
|
|
10737
10826
|
this.frame = this.framePassPerObject;
|
|
10738
10827
|
}
|
|
10739
|
-
|
|
10740
|
-
// Global SCENE BUFFER Good idea for future
|
|
10741
|
-
// this.sceneUniformBuffer = this.device.createBuffer({
|
|
10742
|
-
// // Two 4x4 viewProj matrices,
|
|
10743
|
-
// // one for the camera and one for the light.
|
|
10744
|
-
// // Then a vec3 for the light position.
|
|
10745
|
-
// // Rounded to the nearest multiple of 16.
|
|
10746
|
-
// size: 2 * 4 * 16 + 4 * 4,
|
|
10747
|
-
// usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
10748
|
-
// });
|
|
10749
|
-
|
|
10828
|
+
this.MAX_SPOTLIGHTS = 20;
|
|
10750
10829
|
this.inputHandler = (0, _engine.createInputHandler)(window, canvas);
|
|
10830
|
+
this.createGlobalStuff();
|
|
10751
10831
|
this.run(callback);
|
|
10752
10832
|
};
|
|
10833
|
+
createGlobalStuff() {
|
|
10834
|
+
this.spotlightUniformBuffer = this.device.createBuffer({
|
|
10835
|
+
label: 'spotlightUniformBufferGLOBAL',
|
|
10836
|
+
size: this.MAX_SPOTLIGHTS * 144,
|
|
10837
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
10838
|
+
});
|
|
10839
|
+
this.SHADOW_RES = 1024;
|
|
10840
|
+
this.createTexArrayForShadows();
|
|
10841
|
+
this.mainDepthTexture = this.device.createTexture({
|
|
10842
|
+
size: [this.canvas.width, this.canvas.height],
|
|
10843
|
+
format: 'depth24plus',
|
|
10844
|
+
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING
|
|
10845
|
+
});
|
|
10846
|
+
this.mainDepthView = this.mainDepthTexture.createView();
|
|
10847
|
+
this.mainRenderPassDesc = {
|
|
10848
|
+
label: 'mainRenderPassDesc',
|
|
10849
|
+
colorAttachments: [{
|
|
10850
|
+
view: undefined,
|
|
10851
|
+
// set each frame
|
|
10852
|
+
loadOp: 'clear',
|
|
10853
|
+
storeOp: 'store',
|
|
10854
|
+
clearValue: [0.02, 0.02, 0.02, 1]
|
|
10855
|
+
}],
|
|
10856
|
+
depthStencilAttachment: {
|
|
10857
|
+
view: this.mainDepthView,
|
|
10858
|
+
// fixed
|
|
10859
|
+
depthLoadOp: 'clear',
|
|
10860
|
+
depthStoreOp: 'store',
|
|
10861
|
+
depthClearValue: 1.0
|
|
10862
|
+
}
|
|
10863
|
+
};
|
|
10864
|
+
}
|
|
10865
|
+
createTexArrayForShadows() {
|
|
10866
|
+
let numberOfLights = this.lightContainer.length;
|
|
10867
|
+
if (this.lightContainer.length == 0) {
|
|
10868
|
+
// console.warn('Wait for init light instance')
|
|
10869
|
+
setTimeout(() => {
|
|
10870
|
+
// console.info('Test light again...')
|
|
10871
|
+
this.createMe();
|
|
10872
|
+
}, 800);
|
|
10873
|
+
}
|
|
10874
|
+
this.createMe = () => {
|
|
10875
|
+
Math.max(1, this.lightContainer.length);
|
|
10876
|
+
if (this.lightContainer.length == 0) {
|
|
10877
|
+
setTimeout(() => {
|
|
10878
|
+
console.warn('Create now test...');
|
|
10879
|
+
this.createMe();
|
|
10880
|
+
}, 800);
|
|
10881
|
+
return;
|
|
10882
|
+
}
|
|
10883
|
+
console.warn('Create this.shadowTextureArray...');
|
|
10884
|
+
this.shadowTextureArray = this.device.createTexture({
|
|
10885
|
+
label: `shadowTextureArray[GLOBAL] num of light ${numberOfLights}`,
|
|
10886
|
+
size: {
|
|
10887
|
+
width: 1024,
|
|
10888
|
+
height: 1024,
|
|
10889
|
+
depthOrArrayLayers: numberOfLights // at least 1
|
|
10890
|
+
},
|
|
10891
|
+
dimension: '2d',
|
|
10892
|
+
format: 'depth32float',
|
|
10893
|
+
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING
|
|
10894
|
+
});
|
|
10895
|
+
this.shadowArrayView = this.shadowTextureArray.createView({
|
|
10896
|
+
dimension: '2d-array'
|
|
10897
|
+
});
|
|
10898
|
+
this.shadowVideoTexture = this.device.createTexture({
|
|
10899
|
+
size: [1024, 1024],
|
|
10900
|
+
format: "depth32float",
|
|
10901
|
+
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING
|
|
10902
|
+
});
|
|
10903
|
+
this.shadowVideoView = this.shadowVideoTexture.createView({
|
|
10904
|
+
dimension: "2d"
|
|
10905
|
+
});
|
|
10906
|
+
};
|
|
10907
|
+
this.createMe();
|
|
10908
|
+
}
|
|
10753
10909
|
getSceneObjectByName(name) {
|
|
10754
10910
|
return this.mainRenderBundle.find(sceneObject => sceneObject.name === name);
|
|
10755
10911
|
}
|
|
@@ -10954,12 +11110,11 @@ class MatrixEngineWGPU {
|
|
|
10954
11110
|
this.mainRenderBundle.push(myBall1);
|
|
10955
11111
|
};
|
|
10956
11112
|
addLight(o) {
|
|
10957
|
-
// test light global; entity
|
|
10958
11113
|
const camera = this.cameras[this.mainCameraParams.type];
|
|
10959
|
-
let newLight = new _lights.SpotLight(camera, this.inputHandler);
|
|
10960
|
-
newLight.prepareBuffer(this.device);
|
|
11114
|
+
let newLight = new _lights.SpotLight(camera, this.inputHandler, this.device);
|
|
10961
11115
|
this.lightContainer.push(newLight);
|
|
10962
|
-
|
|
11116
|
+
this.createTexArrayForShadows();
|
|
11117
|
+
console.log(`%cAdd light: ${newLight}`, _utils.LOG_FUNNY_SMALL);
|
|
10963
11118
|
}
|
|
10964
11119
|
addMeshObj = (o, clearColor = this.options.clearColor) => {
|
|
10965
11120
|
if (typeof o.name === 'undefined') {
|
|
@@ -11036,12 +11191,9 @@ class MatrixEngineWGPU {
|
|
|
11036
11191
|
o.physics.rotation = o.rotation;
|
|
11037
11192
|
}
|
|
11038
11193
|
o.physics.position = o.position;
|
|
11039
|
-
// console.log('Mesh procedure', o)
|
|
11040
|
-
// TEST OBJS SEQ ANIMS
|
|
11041
11194
|
if (typeof o.objAnim == 'undefined' || typeof o.objAnim == null) {
|
|
11042
11195
|
o.objAnim = null;
|
|
11043
11196
|
} else {
|
|
11044
|
-
// console.log('o.anim', o.objAnim)
|
|
11045
11197
|
if (typeof o.objAnim.animations !== 'undefined') {
|
|
11046
11198
|
o.objAnim.play = _loaderObj.play;
|
|
11047
11199
|
}
|
|
@@ -11054,14 +11206,13 @@ class MatrixEngineWGPU {
|
|
|
11054
11206
|
// scale for all second option!
|
|
11055
11207
|
o.objAnim.scaleAll = function (s) {
|
|
11056
11208
|
for (var k in this.meshList) {
|
|
11057
|
-
console.log('SCALE');
|
|
11209
|
+
console.log('SCALE meshList');
|
|
11058
11210
|
this.meshList[k].setScale(s);
|
|
11059
11211
|
}
|
|
11060
11212
|
};
|
|
11061
11213
|
}
|
|
11062
|
-
let myMesh1 = new _meshObj.default(this.canvas, this.device, this.context, o);
|
|
11063
|
-
myMesh1.
|
|
11064
|
-
myMesh1.inputHandler = this.inputHandler;
|
|
11214
|
+
let myMesh1 = new _meshObj.default(this.canvas, this.device, this.context, o, this.inputHandler);
|
|
11215
|
+
myMesh1.spotlightUniformBuffer = this.spotlightUniformBuffer;
|
|
11065
11216
|
myMesh1.clearColor = clearColor;
|
|
11066
11217
|
if (o.physics.enabled == true) {
|
|
11067
11218
|
this.matrixAmmo.addPhysics(myMesh1, o.physics);
|
|
@@ -11080,49 +11231,19 @@ class MatrixEngineWGPU {
|
|
|
11080
11231
|
this.mainRenderBundle = [];
|
|
11081
11232
|
this.canvas.remove();
|
|
11082
11233
|
};
|
|
11083
|
-
|
|
11084
|
-
const
|
|
11085
|
-
|
|
11086
|
-
let
|
|
11087
|
-
|
|
11088
|
-
|
|
11234
|
+
updateLights() {
|
|
11235
|
+
const floatsPerLight = 36; // not 20 anymore
|
|
11236
|
+
const data = new Float32Array(this.MAX_SPOTLIGHTS * floatsPerLight);
|
|
11237
|
+
for (let i = 0; i < this.MAX_SPOTLIGHTS; i++) {
|
|
11238
|
+
if (i < this.lightContainer.length) {
|
|
11239
|
+
const buf = this.lightContainer[i].getLightDataBuffer();
|
|
11240
|
+
data.set(buf, i * floatsPerLight);
|
|
11241
|
+
} else {
|
|
11242
|
+
data.set(new Float32Array(floatsPerLight), i * floatsPerLight);
|
|
11243
|
+
}
|
|
11089
11244
|
}
|
|
11090
|
-
this.
|
|
11091
|
-
|
|
11092
|
-
|
|
11093
|
-
// engine, once per frame
|
|
11094
|
-
// const camera = this.cameras[this.mainCameraParams.type];
|
|
11095
|
-
camera.update(dt, this.inputHandler());
|
|
11096
|
-
const camVP = _wgpuMatrix.mat4.multiply(camera.projectionMatrix, camera.view); // P * V
|
|
11097
|
-
|
|
11098
|
-
for (const mesh of this.mainRenderBundle) {
|
|
11099
|
-
// scene buffer layout = 0..63 lightVP, 64..127 camVP, 128..143 lightPos(+pad)
|
|
11100
|
-
this.device.queue.writeBuffer(mesh.sceneUniformBuffer, 64,
|
|
11101
|
-
// cameraViewProjMatrix offset
|
|
11102
|
-
camVP.buffer, camVP.byteOffset, camVP.byteLength);
|
|
11103
|
-
}
|
|
11104
|
-
// engine frame
|
|
11105
|
-
// camera.update(dt, this.inputHandler());
|
|
11106
|
-
// const camVP = mat4.multiply(camera.projectionMatrix, camera.view);
|
|
11107
|
-
|
|
11108
|
-
// for(const mesh of this.mainRenderBundle) {
|
|
11109
|
-
// // Light’s viewProj should come from your SpotLight
|
|
11110
|
-
// // If you have multiple lights, you’ll need an array UBO or multiple passes.
|
|
11111
|
-
// const sceneData = new Float32Array(16 + 16 + 4); // lightVP, camVP, lightPos(+pad)
|
|
11112
|
-
// sceneData.set(this.lightContainer[0].viewProjMatrix, 0);
|
|
11113
|
-
// sceneData.set(camVP, 16);
|
|
11114
|
-
// sceneData.set(this.lightContainer[0].position, 32);
|
|
11115
|
-
|
|
11116
|
-
// // sceneUniformBuffer
|
|
11117
|
-
// this.device.queue.writeBuffer(
|
|
11118
|
-
// mesh.sceneUniformBuffer, // or a shared one if/when you centralize it
|
|
11119
|
-
// 0,
|
|
11120
|
-
// sceneData.buffer,
|
|
11121
|
-
// sceneData.byteOffset,
|
|
11122
|
-
// sceneData.byteLength
|
|
11123
|
-
// );
|
|
11124
|
-
// }
|
|
11125
|
-
};
|
|
11245
|
+
this.device.queue.writeBuffer(this.spotlightUniformBuffer, 0, data.buffer);
|
|
11246
|
+
}
|
|
11126
11247
|
frameSinglePass = () => {
|
|
11127
11248
|
if (typeof this.mainRenderBundle == 'undefined' || this.mainRenderBundle.length == 0) {
|
|
11128
11249
|
setTimeout(() => {
|
|
@@ -11130,66 +11251,109 @@ class MatrixEngineWGPU {
|
|
|
11130
11251
|
}, 200);
|
|
11131
11252
|
return;
|
|
11132
11253
|
}
|
|
11254
|
+
let noPass = false;
|
|
11255
|
+
this.mainRenderBundle.forEach((meItem, index) => {
|
|
11256
|
+
if (meItem.isVideo == true) {
|
|
11257
|
+
if (!meItem.externalTexture || meItem.video.readyState < 2) {
|
|
11258
|
+
console.log('no rendere for video not ready');
|
|
11259
|
+
// this.externalTexture = this.device.importExternalTexture({source: this.video});
|
|
11260
|
+
noPass = true;
|
|
11261
|
+
setTimeout(() => requestAnimationFrame(this.frame), 1500);
|
|
11262
|
+
return;
|
|
11263
|
+
}
|
|
11264
|
+
}
|
|
11265
|
+
});
|
|
11266
|
+
if (noPass == true) {
|
|
11267
|
+
console.log('no rendere for video not ready !!!!');
|
|
11268
|
+
return;
|
|
11269
|
+
}
|
|
11270
|
+
|
|
11271
|
+
// let pass;
|
|
11272
|
+
// let commandEncoder;
|
|
11133
11273
|
try {
|
|
11134
|
-
let shadowPass = null;
|
|
11135
|
-
let renderPass;
|
|
11136
11274
|
let commandEncoder = this.device.createCommandEncoder();
|
|
11137
|
-
this.
|
|
11275
|
+
this.updateLights();
|
|
11138
11276
|
// 1️⃣ Update light data (position, direction, uniforms)
|
|
11139
11277
|
for (const light of this.lightContainer) {
|
|
11140
|
-
light.
|
|
11278
|
+
light.update();
|
|
11279
|
+
// light.updateSceneUniforms(this.mainRenderBundle, this.cameras.WASD);
|
|
11141
11280
|
this.mainRenderBundle.forEach((meItem, index) => {
|
|
11142
|
-
|
|
11281
|
+
meItem.position.update();
|
|
11282
|
+
meItem.updateModelUniformBuffer();
|
|
11283
|
+
// if(meItem.isVideo != true) {
|
|
11284
|
+
meItem.getTransformationMatrix(this.mainRenderBundle, light);
|
|
11285
|
+
// }
|
|
11143
11286
|
});
|
|
11144
11287
|
}
|
|
11145
|
-
this.mainRenderBundle.forEach((meItem, index) => {
|
|
11146
|
-
meItem.position.update();
|
|
11147
|
-
});
|
|
11148
11288
|
if (this.matrixAmmo) this.matrixAmmo.updatePhysics();
|
|
11149
|
-
|
|
11150
|
-
|
|
11151
|
-
|
|
11152
|
-
|
|
11153
|
-
|
|
11154
|
-
|
|
11155
|
-
|
|
11156
|
-
|
|
11157
|
-
|
|
11158
|
-
|
|
11159
|
-
|
|
11160
|
-
|
|
11161
|
-
|
|
11162
|
-
|
|
11163
|
-
|
|
11164
|
-
|
|
11165
|
-
|
|
11166
|
-
|
|
11289
|
+
for (let i = 0; i < this.lightContainer.length; i++) {
|
|
11290
|
+
const light = this.lightContainer[i];
|
|
11291
|
+
let ViewPerLightRenderShadowPass = this.shadowTextureArray.createView({
|
|
11292
|
+
dimension: '2d',
|
|
11293
|
+
baseArrayLayer: i,
|
|
11294
|
+
arrayLayerCount: 1,
|
|
11295
|
+
// must be > 0
|
|
11296
|
+
baseMipLevel: 0,
|
|
11297
|
+
mipLevelCount: 1
|
|
11298
|
+
});
|
|
11299
|
+
const shadowPass = commandEncoder.beginRenderPass({
|
|
11300
|
+
label: "shadowPass",
|
|
11301
|
+
colorAttachments: [],
|
|
11302
|
+
depthStencilAttachment: {
|
|
11303
|
+
view: ViewPerLightRenderShadowPass,
|
|
11304
|
+
depthLoadOp: 'clear',
|
|
11305
|
+
depthStoreOp: 'store',
|
|
11306
|
+
depthClearValue: 1.0
|
|
11307
|
+
}
|
|
11308
|
+
});
|
|
11309
|
+
shadowPass.setPipeline(light.shadowPipeline);
|
|
11310
|
+
for (const [meshIndex, mesh] of this.mainRenderBundle.entries()) {
|
|
11311
|
+
if (mesh.videoIsReady == 'NONE') {
|
|
11312
|
+
shadowPass.setBindGroup(0, light.getShadowBindGroup(mesh, meshIndex));
|
|
11313
|
+
shadowPass.setBindGroup(1, mesh.modelBindGroup);
|
|
11314
|
+
mesh.drawShadows(shadowPass, light);
|
|
11315
|
+
}
|
|
11316
|
+
}
|
|
11317
|
+
shadowPass.end();
|
|
11167
11318
|
}
|
|
11168
|
-
|
|
11169
|
-
this.
|
|
11170
|
-
|
|
11171
|
-
|
|
11172
|
-
|
|
11173
|
-
|
|
11174
|
-
|
|
11175
|
-
|
|
11176
|
-
|
|
11319
|
+
const currentTextureView = this.context.getCurrentTexture().createView();
|
|
11320
|
+
this.mainRenderPassDesc.colorAttachments[0].view = currentTextureView;
|
|
11321
|
+
let pass = commandEncoder.beginRenderPass(this.mainRenderPassDesc);
|
|
11322
|
+
// Loop over each mesh
|
|
11323
|
+
for (const mesh of this.mainRenderBundle) {
|
|
11324
|
+
pass.setPipeline(mesh.pipeline);
|
|
11325
|
+
if (!mesh.sceneBindGroupForRender || mesh.FINISH_VIDIO_INIT == false && mesh.isVideo == true) {
|
|
11326
|
+
for (const m of this.mainRenderBundle) {
|
|
11327
|
+
if (m.isVideo == true) {
|
|
11328
|
+
console.log('✅✅✅ set shadowVideoView', this.shadowVideoView);
|
|
11329
|
+
m.shadowDepthTextureView = this.shadowVideoView;
|
|
11330
|
+
m.FINISH_VIDIO_INIT = true;
|
|
11331
|
+
m.setupPipeline();
|
|
11332
|
+
} else {
|
|
11333
|
+
console.log('✅ NORMAL shadowArrayView');
|
|
11334
|
+
m.shadowDepthTextureView = this.shadowArrayView;
|
|
11335
|
+
}
|
|
11336
|
+
}
|
|
11177
11337
|
}
|
|
11178
|
-
|
|
11179
|
-
|
|
11180
|
-
|
|
11181
|
-
|
|
11182
|
-
|
|
11338
|
+
mesh.drawElements(pass, this.lightContainer);
|
|
11339
|
+
}
|
|
11340
|
+
|
|
11341
|
+
// End render pass
|
|
11342
|
+
pass.end();
|
|
11183
11343
|
this.device.queue.submit([commandEncoder.finish()]);
|
|
11184
11344
|
requestAnimationFrame(this.frame);
|
|
11185
11345
|
} catch (err) {
|
|
11186
|
-
console.log('%
|
|
11346
|
+
console.log('%cLoop(err):' + err, _utils.LOG_WARN);
|
|
11347
|
+
// if(pass) pass.end();
|
|
11348
|
+
// this.device.queue.submit([commandEncoder.finish()]);
|
|
11187
11349
|
requestAnimationFrame(this.frame);
|
|
11350
|
+
} finally {
|
|
11351
|
+
//requestAnimationFrame(this.frame);
|
|
11188
11352
|
}
|
|
11189
11353
|
};
|
|
11190
11354
|
framePassPerObject = () => {
|
|
11191
11355
|
let commandEncoder = this.device.createCommandEncoder();
|
|
11192
|
-
this.matrixAmmo.updatePhysics();
|
|
11356
|
+
if (this.matrixAmmo.rigidBodies.length > 0) this.matrixAmmo.updatePhysics();
|
|
11193
11357
|
this.mainRenderBundle.forEach((meItem, index) => {
|
|
11194
11358
|
if (index === 0) {
|
|
11195
11359
|
if (meItem.renderPassDescriptor) meItem.renderPassDescriptor.colorAttachments[0].loadOp = 'clear';
|
|
@@ -11197,7 +11361,7 @@ class MatrixEngineWGPU {
|
|
|
11197
11361
|
if (meItem.renderPassDescriptor) meItem.renderPassDescriptor.colorAttachments[0].loadOp = 'load';
|
|
11198
11362
|
}
|
|
11199
11363
|
// Update transforms, physics, etc. (optional)
|
|
11200
|
-
meItem.draw(commandEncoder);
|
|
11364
|
+
meItem.draw(commandEncoder);
|
|
11201
11365
|
if (meItem.renderBundle) {
|
|
11202
11366
|
// Set up view per object
|
|
11203
11367
|
meItem.renderPassDescriptor.colorAttachments[0].view = this.context.getCurrentTexture().createView();
|
|
@@ -11205,7 +11369,7 @@ class MatrixEngineWGPU {
|
|
|
11205
11369
|
passEncoder.executeBundles([meItem.renderBundle]); // ✅ Use only this bundle
|
|
11206
11370
|
passEncoder.end();
|
|
11207
11371
|
} else {
|
|
11208
|
-
meItem.draw(commandEncoder);
|
|
11372
|
+
meItem.draw(commandEncoder);
|
|
11209
11373
|
}
|
|
11210
11374
|
});
|
|
11211
11375
|
this.device.queue.submit([commandEncoder.finish()]);
|