matrix-engine-wgpu 1.4.0 → 1.4.2
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 +6 -6
- package/examples/load-objs-sequence.js +8 -0
- package/examples/video-texture.js +13 -7
- package/package.json +4 -2
- package/public/examples.js +625 -402
- package/readme.md +19 -8
- package/src/engine/engine.js +1 -1
- package/src/engine/lights.js +177 -77
- package/src/engine/materials.js +125 -63
- package/src/engine/mesh-obj.js +91 -151
- package/src/shaders/fragment.video.wgsl.js +3 -2
- package/src/shaders/fragment.wgsl.js +77 -47
- package/src/shaders/shaders.js +0 -1
- package/src/shaders/vertex.wgsl.js +6 -20
- package/src/world.js +175 -71
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",
|
|
@@ -186,7 +187,7 @@ var loadObjFile = function () {
|
|
|
186
187
|
(0, _loaderObj.downloadMeshes)({
|
|
187
188
|
cube: "./res/meshes/blender/cube.obj"
|
|
188
189
|
}, onGround, {
|
|
189
|
-
scale: [
|
|
190
|
+
scale: [20, 1, 20]
|
|
190
191
|
});
|
|
191
192
|
|
|
192
193
|
// loadObjFile.addLight();
|
|
@@ -228,7 +229,7 @@ var loadObjFile = function () {
|
|
|
228
229
|
position: {
|
|
229
230
|
x: 0,
|
|
230
231
|
y: 2,
|
|
231
|
-
z: -
|
|
232
|
+
z: -20
|
|
232
233
|
},
|
|
233
234
|
rotation: {
|
|
234
235
|
x: 0,
|
|
@@ -244,16 +245,16 @@ var loadObjFile = function () {
|
|
|
244
245
|
name: 'cube1',
|
|
245
246
|
mesh: m.cube,
|
|
246
247
|
physics: {
|
|
247
|
-
enabled:
|
|
248
|
+
enabled: false,
|
|
248
249
|
geometry: "Cube"
|
|
249
250
|
}
|
|
250
251
|
// raycast: { enabled: true , radius: 2 }
|
|
251
252
|
});
|
|
252
253
|
loadObjFile.addMeshObj({
|
|
253
254
|
position: {
|
|
254
|
-
x:
|
|
255
|
-
y:
|
|
256
|
-
z: -
|
|
255
|
+
x: 0,
|
|
256
|
+
y: -1,
|
|
257
|
+
z: -20
|
|
257
258
|
},
|
|
258
259
|
rotation: {
|
|
259
260
|
x: 0,
|
|
@@ -269,7 +270,7 @@ var loadObjFile = function () {
|
|
|
269
270
|
name: 'ball1',
|
|
270
271
|
mesh: m.ball,
|
|
271
272
|
physics: {
|
|
272
|
-
enabled:
|
|
273
|
+
enabled: false,
|
|
273
274
|
geometry: "Sphere"
|
|
274
275
|
}
|
|
275
276
|
// raycast: { enabled: true , radius: 2 }
|
|
@@ -277,7 +278,7 @@ var loadObjFile = function () {
|
|
|
277
278
|
var TEST = loadObjFile.getSceneObjectByName('cube2');
|
|
278
279
|
console.log(`%c Test access scene ${TEST} object.`, _utils.LOG_MATRIX);
|
|
279
280
|
loadObjFile.addLight();
|
|
280
|
-
loadObjFile.addLight();
|
|
281
|
+
// loadObjFile.addLight();
|
|
281
282
|
}
|
|
282
283
|
});
|
|
283
284
|
// just for dev
|
|
@@ -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,18 +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));
|
|
7149
7167
|
this.intensity = 1.0;
|
|
7150
7168
|
this.color = _wgpuMatrix.vec3.create(1.0, 1.0, 1.0); // white
|
|
7151
7169
|
|
|
7152
7170
|
this.viewMatrix = _wgpuMatrix.mat4.lookAt(position, target, this.up);
|
|
7153
|
-
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;
|
|
7154
7179
|
this.viewProjMatrix = _wgpuMatrix.mat4.multiply(this.projectionMatrix, this.viewMatrix);
|
|
7155
7180
|
this.fov = fov;
|
|
7156
7181
|
this.aspect = aspect;
|
|
@@ -7159,63 +7184,144 @@ class SpotLight {
|
|
|
7159
7184
|
this.innerCutoff = Math.cos(Math.PI / 180 * 12.5);
|
|
7160
7185
|
this.outerCutoff = Math.cos(Math.PI / 180 * 17.5);
|
|
7161
7186
|
this.ambientFactor = 0.5;
|
|
7162
|
-
this.range =
|
|
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
|
+
};
|
|
7163
7305
|
}
|
|
7164
7306
|
update() {
|
|
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
|
-
}
|
|
7188
|
-
|
|
7189
|
-
// DEPLACED
|
|
7190
|
-
prepareBuffer(device) {
|
|
7191
|
-
if (!this.device) this.device = device;
|
|
7192
|
-
this.spotlightUniformBuffer = this.device.createBuffer({
|
|
7193
|
-
label: 'spotlightUniformBuffer',
|
|
7194
|
-
size: 80,
|
|
7195
|
-
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
7196
|
-
});
|
|
7197
|
-
const spotlightData = this.getLightDataBuffer();
|
|
7198
|
-
this.device.queue.writeBuffer(this.spotlightUniformBuffer, 0, spotlightData.buffer, spotlightData.byteOffset, spotlightData.byteLength);
|
|
7199
|
-
}
|
|
7200
|
-
|
|
7201
|
-
// DEPLACED
|
|
7202
|
-
updateLightBuffer() {
|
|
7203
|
-
if (!this.device || !this.spotlightUniformBuffer) {
|
|
7204
|
-
return;
|
|
7205
|
-
}
|
|
7206
|
-
const spotlightData = this.getLightDataBuffer();
|
|
7207
|
-
this.device.queue.writeBuffer(this.spotlightUniformBuffer, 0, spotlightData.buffer, spotlightData.byteOffset, spotlightData.byteLength);
|
|
7208
|
-
}
|
|
7209
7313
|
getLightDataBuffer() {
|
|
7210
|
-
|
|
7211
|
-
|
|
7212
|
-
|
|
7213
|
-
|
|
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]);
|
|
7214
7320
|
}
|
|
7215
7321
|
}
|
|
7216
7322
|
exports.SpotLight = SpotLight;
|
|
7217
7323
|
|
|
7218
|
-
},{"wgpu-matrix":7}],12:[function(require,module,exports){
|
|
7324
|
+
},{"../shaders/vertexShadow.wgsl":24,"wgpu-matrix":7}],12:[function(require,module,exports){
|
|
7219
7325
|
"use strict";
|
|
7220
7326
|
|
|
7221
7327
|
Object.defineProperty(exports, "__esModule", {
|
|
@@ -7702,8 +7808,17 @@ class Materials {
|
|
|
7702
7808
|
constructor(device) {
|
|
7703
7809
|
this.device = device;
|
|
7704
7810
|
this.isVideo = false;
|
|
7811
|
+
this.videoIsReady = 'NONE';
|
|
7812
|
+
// this.compareSampler = this.device.createSampler({compare: 'less'});
|
|
7705
7813
|
this.compareSampler = this.device.createSampler({
|
|
7706
|
-
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'
|
|
7707
7822
|
});
|
|
7708
7823
|
// For image textures (standard sampler)
|
|
7709
7824
|
this.imageSampler = this.device.createSampler({
|
|
@@ -7758,7 +7873,8 @@ class Materials {
|
|
|
7758
7873
|
});
|
|
7759
7874
|
}
|
|
7760
7875
|
async loadVideoTexture(arg) {
|
|
7761
|
-
this.isVideo = true;
|
|
7876
|
+
// this.isVideo = true;
|
|
7877
|
+
this.videoIsReady = 'MAYBE';
|
|
7762
7878
|
if (arg.type === 'video') {
|
|
7763
7879
|
this.video = document.createElement('video');
|
|
7764
7880
|
this.video.src = arg.src || 'res/videos/tunel.mp4';
|
|
@@ -7767,7 +7883,11 @@ class Materials {
|
|
|
7767
7883
|
this.video.loop = true;
|
|
7768
7884
|
document.body.append(this.video);
|
|
7769
7885
|
this.video.style.display = 'none';
|
|
7886
|
+
this.video.style.position = 'absolute';
|
|
7887
|
+
this.video.style.top = '50px';
|
|
7888
|
+
this.video.style.left = '50px';
|
|
7770
7889
|
await this.video.play();
|
|
7890
|
+
this.isVideo = true;
|
|
7771
7891
|
} else if (arg.type === 'videoElement') {
|
|
7772
7892
|
this.video = arg.el;
|
|
7773
7893
|
await this.video.play();
|
|
@@ -7792,6 +7912,7 @@ class Materials {
|
|
|
7792
7912
|
});
|
|
7793
7913
|
this.video.srcObject = stream;
|
|
7794
7914
|
await this.video.play();
|
|
7915
|
+
this.isVideo = true;
|
|
7795
7916
|
} catch (err) {
|
|
7796
7917
|
console.error("❌ Failed to access camera:", err);
|
|
7797
7918
|
return;
|
|
@@ -7811,6 +7932,7 @@ class Materials {
|
|
|
7811
7932
|
}
|
|
7812
7933
|
this.video.srcObject = stream;
|
|
7813
7934
|
await this.video.play();
|
|
7935
|
+
this.isVideo = true;
|
|
7814
7936
|
} else if (arg.type === 'canvas2d-inline') {
|
|
7815
7937
|
// Miniature inline-drawn canvas created dynamically
|
|
7816
7938
|
const canvas = document.createElement('canvas');
|
|
@@ -7831,6 +7953,7 @@ class Materials {
|
|
|
7831
7953
|
this.video.playsInline = true;
|
|
7832
7954
|
this.video.style.display = 'none';
|
|
7833
7955
|
document.body.append(this.video);
|
|
7956
|
+
this.isVideo = true;
|
|
7834
7957
|
const stream = canvas.captureStream?.() || canvas.mozCaptureStream?.();
|
|
7835
7958
|
if (!stream) {
|
|
7836
7959
|
console.error('❌ Cannot capture stream from inline canvas');
|
|
@@ -7844,25 +7967,37 @@ class Materials {
|
|
|
7844
7967
|
minFilter: 'linear'
|
|
7845
7968
|
});
|
|
7846
7969
|
|
|
7847
|
-
// ✅ Now
|
|
7970
|
+
// ✅ Now - maybe noT
|
|
7848
7971
|
this.createLayoutForRender();
|
|
7849
|
-
this.setupPipeline();
|
|
7850
7972
|
}
|
|
7851
7973
|
updateVideoTexture() {
|
|
7852
7974
|
if (!this.video || this.video.readyState < 2) return;
|
|
7853
|
-
this.externalTexture
|
|
7854
|
-
|
|
7855
|
-
|
|
7856
|
-
|
|
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
|
+
}
|
|
7857
7989
|
}
|
|
7858
7990
|
createBindGroupForRender() {
|
|
7859
|
-
const textureResource = this.isVideo ? this.externalTexture
|
|
7860
|
-
|
|
7861
|
-
|
|
7862
|
-
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();
|
|
7863
7997
|
return;
|
|
7864
|
-
}
|
|
7998
|
+
} else {}
|
|
7865
7999
|
if (this.isVideo == true) {
|
|
8000
|
+
console.info("✅ video sceneBindGroupForRender ");
|
|
7866
8001
|
this.sceneBindGroupForRender = this.device.createBindGroup({
|
|
7867
8002
|
layout: this.bglForRender,
|
|
7868
8003
|
entries: [{
|
|
@@ -7889,6 +8024,10 @@ class Materials {
|
|
|
7889
8024
|
}
|
|
7890
8025
|
}]
|
|
7891
8026
|
});
|
|
8027
|
+
|
|
8028
|
+
// special case for video meybe better solution exist
|
|
8029
|
+
// this.setupPipeline();
|
|
8030
|
+
this.video.play();
|
|
7892
8031
|
} else {
|
|
7893
8032
|
this.sceneBindGroupForRender = this.device.createBindGroup({
|
|
7894
8033
|
layout: this.bglForRender,
|
|
@@ -7919,66 +8058,87 @@ class Materials {
|
|
|
7919
8058
|
}
|
|
7920
8059
|
}
|
|
7921
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);
|
|
7922
8135
|
this.bglForRender = this.device.createBindGroupLayout({
|
|
7923
|
-
|
|
7924
|
-
|
|
7925
|
-
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
|
|
7926
|
-
buffer: {
|
|
7927
|
-
type: 'uniform'
|
|
7928
|
-
}
|
|
7929
|
-
}, {
|
|
7930
|
-
binding: 1,
|
|
7931
|
-
visibility: GPUShaderStage.FRAGMENT,
|
|
7932
|
-
texture: {
|
|
7933
|
-
sampleType: 'depth'
|
|
7934
|
-
}
|
|
7935
|
-
}, {
|
|
7936
|
-
binding: 2,
|
|
7937
|
-
visibility: GPUShaderStage.FRAGMENT,
|
|
7938
|
-
sampler: {
|
|
7939
|
-
type: 'comparison'
|
|
7940
|
-
}
|
|
7941
|
-
}, ...(this.isVideo ? [
|
|
7942
|
-
// VIDEO
|
|
7943
|
-
{
|
|
7944
|
-
binding: 3,
|
|
7945
|
-
visibility: GPUShaderStage.FRAGMENT,
|
|
7946
|
-
externalTexture: {}
|
|
7947
|
-
}, {
|
|
7948
|
-
binding: 4,
|
|
7949
|
-
visibility: GPUShaderStage.FRAGMENT,
|
|
7950
|
-
sampler: {
|
|
7951
|
-
type: 'filtering'
|
|
7952
|
-
} // for video sampling
|
|
7953
|
-
}, {
|
|
7954
|
-
binding: 5,
|
|
7955
|
-
visibility: GPUShaderStage.FRAGMENT,
|
|
7956
|
-
buffer: {
|
|
7957
|
-
type: 'uniform'
|
|
7958
|
-
}
|
|
7959
|
-
}] : [
|
|
7960
|
-
// IMAGE
|
|
7961
|
-
{
|
|
7962
|
-
binding: 3,
|
|
7963
|
-
visibility: GPUShaderStage.FRAGMENT,
|
|
7964
|
-
texture: {
|
|
7965
|
-
sampleType: 'float',
|
|
7966
|
-
viewDimension: '2d'
|
|
7967
|
-
}
|
|
7968
|
-
}, {
|
|
7969
|
-
binding: 4,
|
|
7970
|
-
visibility: GPUShaderStage.FRAGMENT,
|
|
7971
|
-
sampler: {
|
|
7972
|
-
type: 'filtering'
|
|
7973
|
-
}
|
|
7974
|
-
}, {
|
|
7975
|
-
binding: 5,
|
|
7976
|
-
visibility: GPUShaderStage.FRAGMENT,
|
|
7977
|
-
buffer: {
|
|
7978
|
-
type: 'uniform'
|
|
7979
|
-
}
|
|
7980
|
-
}])]
|
|
8136
|
+
label: 'bglForRender',
|
|
8137
|
+
entries: e
|
|
7981
8138
|
});
|
|
8139
|
+
if (this.isVideo == true) {
|
|
8140
|
+
this.createBindGroupForRender();
|
|
8141
|
+
}
|
|
7982
8142
|
}
|
|
7983
8143
|
}
|
|
7984
8144
|
exports.default = Materials;
|
|
@@ -8236,7 +8396,7 @@ var _materials = _interopRequireDefault(require("./materials"));
|
|
|
8236
8396
|
var _fragmentVideo = require("../shaders/fragment.video.wgsl");
|
|
8237
8397
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
8238
8398
|
class MEMeshObj extends _materials.default {
|
|
8239
|
-
constructor(canvas, device, context, o,
|
|
8399
|
+
constructor(canvas, device, context, o, inputHandler) {
|
|
8240
8400
|
super(device);
|
|
8241
8401
|
if (typeof o.name === 'undefined') o.name = (0, _utils.genName)(3);
|
|
8242
8402
|
if (typeof o.raycast === 'undefined') {
|
|
@@ -8254,6 +8414,7 @@ class MEMeshObj extends _materials.default {
|
|
|
8254
8414
|
this.entityArgPass = o.entityArgPass;
|
|
8255
8415
|
this.clearColor = "red";
|
|
8256
8416
|
this.video = null;
|
|
8417
|
+
this.FINISH_VIDIO_INIT = false;
|
|
8257
8418
|
|
|
8258
8419
|
// Mesh stuff - for single mesh or t-posed (fiktive-first in loading order)
|
|
8259
8420
|
this.mesh = o.mesh;
|
|
@@ -8269,7 +8430,7 @@ class MEMeshObj extends _materials.default {
|
|
|
8269
8430
|
console.log(`%c Mesh objAnim exist: ${o.objAnim}`, _utils.LOG_FUNNY_SMALL);
|
|
8270
8431
|
this.drawElements = this.drawElementsAnim;
|
|
8271
8432
|
}
|
|
8272
|
-
this.inputHandler =
|
|
8433
|
+
this.inputHandler = inputHandler;
|
|
8273
8434
|
this.cameras = o.cameras;
|
|
8274
8435
|
this.mainCameraParams = {
|
|
8275
8436
|
type: o.mainCameraParams.type,
|
|
@@ -8353,14 +8514,6 @@ class MEMeshObj extends _materials.default {
|
|
|
8353
8514
|
this.indexBuffer.unmap();
|
|
8354
8515
|
this.indexCount = indexCount;
|
|
8355
8516
|
|
|
8356
|
-
// Create the depth texture for rendering/sampling the shadow map.
|
|
8357
|
-
this.shadowDepthTexture = this.device.createTexture({
|
|
8358
|
-
size: [this.shadowDepthTextureSize, this.shadowDepthTextureSize, 1],
|
|
8359
|
-
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,
|
|
8360
|
-
format: 'depth32float'
|
|
8361
|
-
});
|
|
8362
|
-
this.shadowDepthTextureView = this.shadowDepthTexture.createView();
|
|
8363
|
-
|
|
8364
8517
|
// Create some common descriptors used for both the shadow pipeline
|
|
8365
8518
|
// and the color rendering pipeline.
|
|
8366
8519
|
this.vertexBuffers = [{
|
|
@@ -8390,91 +8543,37 @@ class MEMeshObj extends _materials.default {
|
|
|
8390
8543
|
}];
|
|
8391
8544
|
this.primitive = {
|
|
8392
8545
|
topology: 'triangle-list',
|
|
8393
|
-
|
|
8394
|
-
|
|
8546
|
+
cullMode: 'back',
|
|
8547
|
+
// typical for shadow passes
|
|
8548
|
+
frontFace: 'ccw'
|
|
8395
8549
|
};
|
|
8396
|
-
this.uniformBufferBindGroupLayout = this.device.createBindGroupLayout({
|
|
8397
|
-
entries: [{
|
|
8398
|
-
binding: 0,
|
|
8399
|
-
visibility: GPUShaderStage.VERTEX,
|
|
8400
|
-
buffer: {
|
|
8401
|
-
type: 'uniform'
|
|
8402
|
-
}
|
|
8403
|
-
}]
|
|
8404
|
-
});
|
|
8405
|
-
this.shadowPipeline = this.device.createRenderPipeline({
|
|
8406
|
-
layout: this.device.createPipelineLayout({
|
|
8407
|
-
bindGroupLayouts: [this.uniformBufferBindGroupLayout, this.uniformBufferBindGroupLayout]
|
|
8408
|
-
}),
|
|
8409
|
-
vertex: {
|
|
8410
|
-
module: this.device.createShaderModule({
|
|
8411
|
-
code: _vertexShadow.vertexShadowWGSL
|
|
8412
|
-
}),
|
|
8413
|
-
buffers: this.vertexBuffers
|
|
8414
|
-
},
|
|
8415
|
-
depthStencil: {
|
|
8416
|
-
depthWriteEnabled: true,
|
|
8417
|
-
depthCompare: 'less',
|
|
8418
|
-
format: 'depth32float'
|
|
8419
|
-
},
|
|
8420
|
-
primitive: this.primitive
|
|
8421
|
-
});
|
|
8422
8550
|
|
|
8423
8551
|
// Create a bind group layout which holds the scene uniforms and
|
|
8424
8552
|
// the texture+sampler for depth. We create it manually because the WebPU
|
|
8425
8553
|
// implementation doesn't infer this from the shader (yet).
|
|
8426
8554
|
this.createLayoutForRender();
|
|
8427
|
-
this.setupPipeline();
|
|
8428
|
-
const depthTexture = this.device.createTexture({
|
|
8429
|
-
size: [canvas.width, canvas.height],
|
|
8430
|
-
// format: 'depth24plus-stencil8',
|
|
8431
|
-
format: 'depth24plus',
|
|
8432
|
-
usage: GPUTextureUsage.RENDER_ATTACHMENT
|
|
8433
|
-
});
|
|
8434
|
-
this.renderPassDescriptor = {
|
|
8435
|
-
colorAttachments: [{
|
|
8436
|
-
// view is acquired and set in render loop.
|
|
8437
|
-
view: undefined,
|
|
8438
|
-
clearValue: this.clearColor,
|
|
8439
|
-
loadOp: 'clear',
|
|
8440
|
-
// load -> clear = fix for FF
|
|
8441
|
-
storeOp: 'store'
|
|
8442
|
-
}],
|
|
8443
|
-
depthStencilAttachment: {
|
|
8444
|
-
view: depthTexture.createView(),
|
|
8445
|
-
depthClearValue: 1.0,
|
|
8446
|
-
depthLoadOp: 'clear',
|
|
8447
|
-
depthStoreOp: 'store'
|
|
8448
|
-
// stencilClearValue: 0,
|
|
8449
|
-
// stencilLoadOp: 'clear',
|
|
8450
|
-
// stencilStoreOp: 'store',
|
|
8451
|
-
}
|
|
8452
|
-
};
|
|
8453
8555
|
this.modelUniformBuffer = this.device.createBuffer({
|
|
8454
8556
|
size: 4 * 16,
|
|
8455
8557
|
// 4x4 matrix
|
|
8456
8558
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
8457
8559
|
});
|
|
8458
8560
|
this.sceneUniformBuffer = this.device.createBuffer({
|
|
8459
|
-
|
|
8460
|
-
|
|
8461
|
-
// Then a vec3 for the light position.
|
|
8462
|
-
// Rounded to the nearest multiple of 16.
|
|
8463
|
-
size: 2 * 4 * 16 + 4 * 4,
|
|
8561
|
+
label: 'sceneUniformBuffer per mesh',
|
|
8562
|
+
size: 160,
|
|
8464
8563
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
8465
8564
|
});
|
|
8466
|
-
|
|
8467
|
-
|
|
8468
|
-
layout: this.uniformBufferBindGroupLayout,
|
|
8565
|
+
this.uniformBufferBindGroupLayout = this.device.createBindGroupLayout({
|
|
8566
|
+
label: 'uniformBufferBindGroupLayout in mesh',
|
|
8469
8567
|
entries: [{
|
|
8470
8568
|
binding: 0,
|
|
8471
|
-
|
|
8472
|
-
|
|
8569
|
+
visibility: GPUShaderStage.VERTEX,
|
|
8570
|
+
buffer: {
|
|
8571
|
+
type: 'uniform'
|
|
8473
8572
|
}
|
|
8474
8573
|
}]
|
|
8475
8574
|
});
|
|
8476
|
-
this.createBindGroupForRender();
|
|
8477
8575
|
this.modelBindGroup = this.device.createBindGroup({
|
|
8576
|
+
label: 'modelBindGroup in mesh',
|
|
8478
8577
|
layout: this.uniformBufferBindGroupLayout,
|
|
8479
8578
|
entries: [{
|
|
8480
8579
|
binding: 0,
|
|
@@ -8483,49 +8582,49 @@ class MEMeshObj extends _materials.default {
|
|
|
8483
8582
|
}
|
|
8484
8583
|
}]
|
|
8485
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
|
+
});
|
|
8486
8600
|
|
|
8487
8601
|
// Rotates the camera around the origin based on time.
|
|
8488
|
-
this.getTransformationMatrix =
|
|
8602
|
+
this.getTransformationMatrix = (mainRenderBundle, spotLight) => {
|
|
8489
8603
|
const now = Date.now();
|
|
8490
|
-
const
|
|
8604
|
+
const dt = (now - this.lastFrameMS) / this.mainCameraParams.responseCoef;
|
|
8491
8605
|
this.lastFrameMS = now;
|
|
8492
|
-
// const this.viewMatrix = mat4.identity()
|
|
8493
8606
|
const camera = this.cameras[this.mainCameraParams.type];
|
|
8494
|
-
|
|
8495
|
-
// engine frame
|
|
8496
8607
|
camera.update(dt, inputHandler());
|
|
8497
8608
|
const camVP = _wgpuMatrix.mat4.multiply(camera.projectionMatrix, camera.view);
|
|
8498
8609
|
for (const mesh of mainRenderBundle) {
|
|
8499
|
-
//
|
|
8500
|
-
|
|
8501
|
-
|
|
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
|
|
8502
8614
|
sceneData.set(spotLight.viewProjMatrix, 0);
|
|
8615
|
+
|
|
8616
|
+
// Camera VP
|
|
8503
8617
|
sceneData.set(camVP, 16);
|
|
8504
|
-
|
|
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);
|
|
8505
8624
|
device.queue.writeBuffer(mesh.sceneUniformBuffer,
|
|
8506
|
-
// or
|
|
8625
|
+
// or shared buffer
|
|
8507
8626
|
0, sceneData.buffer, sceneData.byteOffset, sceneData.byteLength);
|
|
8508
8627
|
}
|
|
8509
|
-
// this.viewMatrix = camera.update(deltaTime, this.inputHandler());
|
|
8510
|
-
// const scaleVec = [1, 1, 1]; // your desired scale OPTION 1
|
|
8511
|
-
// const scaleMatrix = mat4.scaling(scaleVec);
|
|
8512
|
-
// // Apply scaling
|
|
8513
|
-
// mat4.multiply(scaleMatrix, this.viewMatrix, this.viewMatrix);
|
|
8514
|
-
// mat4.translate(this.viewMatrix, vec3.fromValues(pos.x, pos.y, pos.z), this.viewMatrix);
|
|
8515
|
-
|
|
8516
|
-
// if(this.itIsPhysicsBody == true) {
|
|
8517
|
-
// mat4.rotate(
|
|
8518
|
-
// this.viewMatrix,
|
|
8519
|
-
// vec3.fromValues(this.rotation.axis.x, this.rotation.axis.y, this.rotation.axis.z),
|
|
8520
|
-
// degToRad(this.rotation.angle), this.viewMatrix)
|
|
8521
|
-
// } else {
|
|
8522
|
-
// mat4.rotateX(this.viewMatrix, Math.PI * this.rotation.getRotX(), this.viewMatrix);
|
|
8523
|
-
// mat4.rotateY(this.viewMatrix, Math.PI * this.rotation.getRotY(), this.viewMatrix);
|
|
8524
|
-
// mat4.rotateZ(this.viewMatrix, Math.PI * this.rotation.getRotZ(), this.viewMatrix);
|
|
8525
|
-
// // console.info('NOT PHYSICS angle: ', this.rotation.angle, ' axis ', this.rotation.axis.x, ' , ', this.rotation.axis.y, ' , ', this.rotation.axis.z)
|
|
8526
|
-
// }
|
|
8527
|
-
// mat4.multiply(camera.projectionMatrix, this.viewMatrix, this.modelViewProjectionMatrix);
|
|
8528
|
-
// return this.modelViewProjectionMatrix;
|
|
8529
8628
|
};
|
|
8530
8629
|
this.getModelMatrix = pos => {
|
|
8531
8630
|
let modelMatrix = _wgpuMatrix.mat4.identity();
|
|
@@ -8546,28 +8645,25 @@ class MEMeshObj extends _materials.default {
|
|
|
8546
8645
|
const modelMatrix = _wgpuMatrix.mat4.translation([0, 0, 0]);
|
|
8547
8646
|
const modelData = modelMatrix;
|
|
8548
8647
|
this.device.queue.writeBuffer(this.modelUniformBuffer, 0, modelData.buffer, modelData.byteOffset, modelData.byteLength);
|
|
8549
|
-
this.shadowPassDescriptor = {
|
|
8550
|
-
colorAttachments: [],
|
|
8551
|
-
depthStencilAttachment: {
|
|
8552
|
-
view: this.shadowDepthTextureView,
|
|
8553
|
-
depthClearValue: 1.0,
|
|
8554
|
-
depthLoadOp: 'clear',
|
|
8555
|
-
depthStoreOp: 'store'
|
|
8556
|
-
}
|
|
8557
|
-
};
|
|
8558
8648
|
this.done = true;
|
|
8649
|
+
try {
|
|
8650
|
+
this.setupPipeline();
|
|
8651
|
+
} catch (err) {
|
|
8652
|
+
console.log('err in create pipeline in init ', err);
|
|
8653
|
+
}
|
|
8559
8654
|
}).then(() => {
|
|
8560
8655
|
if (typeof this.objAnim !== 'undefined' && this.objAnim !== null) {
|
|
8561
|
-
console.log('after all
|
|
8656
|
+
console.log('after all updateMeshListBuffers...');
|
|
8562
8657
|
this.updateMeshListBuffers();
|
|
8563
8658
|
}
|
|
8564
8659
|
});
|
|
8565
8660
|
}
|
|
8566
8661
|
setupPipeline = () => {
|
|
8567
|
-
|
|
8662
|
+
this.createBindGroupForRender();
|
|
8568
8663
|
this.pipeline = this.device.createRenderPipeline({
|
|
8569
8664
|
label: 'Mesh Pipeline ✅',
|
|
8570
8665
|
layout: this.device.createPipelineLayout({
|
|
8666
|
+
label: 'createPipelineLayout Mesh',
|
|
8571
8667
|
bindGroupLayouts: [this.bglForRender, this.uniformBufferBindGroupLayout]
|
|
8572
8668
|
}),
|
|
8573
8669
|
vertex: {
|
|
@@ -8596,26 +8692,13 @@ class MEMeshObj extends _materials.default {
|
|
|
8596
8692
|
},
|
|
8597
8693
|
primitive: this.primitive
|
|
8598
8694
|
});
|
|
8695
|
+
console.log('✅Set Pipeline done');
|
|
8599
8696
|
};
|
|
8600
|
-
|
|
8697
|
+
updateModelUniformBuffer = () => {
|
|
8601
8698
|
if (this.done == false) return;
|
|
8602
8699
|
// Per-object model matrix only
|
|
8603
8700
|
const modelMatrix = this.getModelMatrix(this.position);
|
|
8604
8701
|
this.device.queue.writeBuffer(this.modelUniformBuffer, 0, modelMatrix.buffer, modelMatrix.byteOffset, modelMatrix.byteLength);
|
|
8605
|
-
// Acquire swapchain view for the pass
|
|
8606
|
-
this.renderPassDescriptor.colorAttachments[0].view = this.context.getCurrentTexture().createView();
|
|
8607
|
-
};
|
|
8608
|
-
drawElements = renderPass => {
|
|
8609
|
-
if (this.isVideo) {
|
|
8610
|
-
this.updateVideoTexture();
|
|
8611
|
-
}
|
|
8612
|
-
renderPass.setBindGroup(0, this.sceneBindGroupForRender);
|
|
8613
|
-
renderPass.setBindGroup(1, this.modelBindGroup);
|
|
8614
|
-
renderPass.setVertexBuffer(0, this.vertexBuffer);
|
|
8615
|
-
renderPass.setVertexBuffer(1, this.vertexNormalsBuffer);
|
|
8616
|
-
renderPass.setVertexBuffer(2, this.vertexTexCoordsBuffer);
|
|
8617
|
-
renderPass.setIndexBuffer(this.indexBuffer, 'uint16');
|
|
8618
|
-
renderPass.drawIndexed(this.indexCount);
|
|
8619
8702
|
};
|
|
8620
8703
|
createGPUBuffer(dataArray, usage) {
|
|
8621
8704
|
if (!dataArray || typeof dataArray.length !== 'number') {
|
|
@@ -8674,7 +8757,35 @@ class MEMeshObj extends _materials.default {
|
|
|
8674
8757
|
mesh.indexCount = indexCount;
|
|
8675
8758
|
}
|
|
8676
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
|
+
};
|
|
8677
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
|
+
}
|
|
8678
8789
|
renderPass.setBindGroup(0, this.sceneBindGroupForRender);
|
|
8679
8790
|
renderPass.setBindGroup(1, this.modelBindGroup);
|
|
8680
8791
|
const mesh = this.objAnim.meshList[this.objAnim.id + this.objAnim.currentAni];
|
|
@@ -8695,9 +8806,7 @@ class MEMeshObj extends _materials.default {
|
|
|
8695
8806
|
}
|
|
8696
8807
|
}
|
|
8697
8808
|
};
|
|
8698
|
-
drawShadows = shadowPass => {
|
|
8699
|
-
shadowPass.setBindGroup(0, this.sceneBindGroupForShadow);
|
|
8700
|
-
shadowPass.setBindGroup(1, this.modelBindGroup);
|
|
8809
|
+
drawShadows = (shadowPass, light) => {
|
|
8701
8810
|
shadowPass.setVertexBuffer(0, this.vertexBuffer);
|
|
8702
8811
|
shadowPass.setVertexBuffer(1, this.vertexNormalsBuffer);
|
|
8703
8812
|
shadowPass.setVertexBuffer(2, this.vertexTexCoordsBuffer);
|
|
@@ -10152,18 +10261,19 @@ struct Scene {
|
|
|
10152
10261
|
@group(0) @binding(2) var shadowSampler: sampler_comparison;
|
|
10153
10262
|
@group(0) @binding(3) var meshTexture: texture_external;
|
|
10154
10263
|
@group(0) @binding(4) var meshSampler: sampler;
|
|
10155
|
-
|
|
10156
10264
|
@group(0) @binding(5) var<uniform> postFXMode: u32;
|
|
10157
10265
|
|
|
10158
10266
|
// ❌ No binding(4) here!
|
|
10159
10267
|
|
|
10160
10268
|
struct FragmentInput {
|
|
10161
|
-
@location(0) shadowPos :
|
|
10269
|
+
@location(0) shadowPos : vec4f,
|
|
10162
10270
|
@location(1) fragPos : vec3f,
|
|
10163
10271
|
@location(2) fragNorm : vec3f,
|
|
10164
10272
|
@location(3) uv : vec2f,
|
|
10165
10273
|
}
|
|
10166
10274
|
|
|
10275
|
+
|
|
10276
|
+
|
|
10167
10277
|
const albedo = vec3f(0.9);
|
|
10168
10278
|
const ambientFactor = 0.7;
|
|
10169
10279
|
|
|
@@ -10232,52 +10342,57 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
10232
10342
|
exports.fragmentWGSL = void 0;
|
|
10233
10343
|
let fragmentWGSL = exports.fragmentWGSL = `override shadowDepthTextureSize: f32 = 1024.0;
|
|
10234
10344
|
|
|
10345
|
+
// Created by Nikola Lukic with chatgtp assist.
|
|
10346
|
+
|
|
10235
10347
|
struct Scene {
|
|
10236
|
-
lightViewProjMatrix
|
|
10348
|
+
lightViewProjMatrix : mat4x4f,
|
|
10237
10349
|
cameraViewProjMatrix : mat4x4f,
|
|
10238
|
-
|
|
10239
|
-
|
|
10240
|
-
|
|
10350
|
+
cameraPos : vec3f,
|
|
10351
|
+
padding2 : f32, // align to 16 bytes
|
|
10352
|
+
lightPos : vec3f,
|
|
10353
|
+
padding : f32, // align to 16 bytes
|
|
10354
|
+
};
|
|
10241
10355
|
|
|
10242
10356
|
struct SpotLight {
|
|
10243
|
-
position
|
|
10244
|
-
_pad1
|
|
10357
|
+
position : vec3f,
|
|
10358
|
+
_pad1 : f32,
|
|
10359
|
+
|
|
10360
|
+
direction : vec3f,
|
|
10361
|
+
_pad2 : f32,
|
|
10245
10362
|
|
|
10246
|
-
|
|
10247
|
-
|
|
10363
|
+
innerCutoff : f32,
|
|
10364
|
+
outerCutoff : f32,
|
|
10365
|
+
intensity : f32,
|
|
10366
|
+
_pad3 : f32,
|
|
10248
10367
|
|
|
10249
|
-
|
|
10250
|
-
|
|
10251
|
-
intensity : f32,
|
|
10252
|
-
_pad3 : f32,
|
|
10368
|
+
color : vec3f,
|
|
10369
|
+
_pad4 : f32,
|
|
10253
10370
|
|
|
10254
|
-
|
|
10255
|
-
|
|
10371
|
+
range : f32,
|
|
10372
|
+
ambientFactor : f32,
|
|
10373
|
+
shadowBias : f32,
|
|
10374
|
+
_pad5 : f32,
|
|
10256
10375
|
|
|
10257
|
-
|
|
10258
|
-
ambientFactor: f32, // new
|
|
10259
|
-
_pad5 : vec2f, // padding to align to 16 bytes
|
|
10376
|
+
lightViewProj : mat4x4<f32>,
|
|
10260
10377
|
};
|
|
10261
10378
|
|
|
10262
|
-
const MAX_SPOTLIGHTS = 20u;
|
|
10379
|
+
const MAX_SPOTLIGHTS = 20u;
|
|
10263
10380
|
|
|
10264
10381
|
@group(0) @binding(0) var<uniform> scene : Scene;
|
|
10265
|
-
@group(0) @binding(1) var
|
|
10382
|
+
@group(0) @binding(1) var shadowMapArray: texture_depth_2d_array;
|
|
10266
10383
|
@group(0) @binding(2) var shadowSampler: sampler_comparison;
|
|
10267
10384
|
@group(0) @binding(3) var meshTexture: texture_2d<f32>;
|
|
10268
10385
|
@group(0) @binding(4) var meshSampler: sampler;
|
|
10269
10386
|
@group(0) @binding(5) var<uniform> spotlights: array<SpotLight, MAX_SPOTLIGHTS>;
|
|
10270
|
-
// @group(0) @binding(6) var<uniform> spotlight1: SpotLight;
|
|
10271
10387
|
|
|
10272
10388
|
struct FragmentInput {
|
|
10273
|
-
@location(0) shadowPos :
|
|
10274
|
-
@location(1) fragPos
|
|
10275
|
-
@location(2) fragNorm
|
|
10276
|
-
@location(3) uv
|
|
10389
|
+
@location(0) shadowPos : vec4f,
|
|
10390
|
+
@location(1) fragPos : vec3f,
|
|
10391
|
+
@location(2) fragNorm : vec3f,
|
|
10392
|
+
@location(3) uv : vec2f,
|
|
10277
10393
|
}
|
|
10278
10394
|
|
|
10279
10395
|
const albedo = vec3f(0.9);
|
|
10280
|
-
// const ambientFactor = 0.7;
|
|
10281
10396
|
|
|
10282
10397
|
fn calculateSpotlightFactor(light: SpotLight, fragPos: vec3f) -> f32 {
|
|
10283
10398
|
let L = normalize(light.position - fragPos);
|
|
@@ -10304,39 +10419,64 @@ fn computeSpotLight(light: SpotLight, normal: vec3f, fragPos: vec3f, viewDir: ve
|
|
|
10304
10419
|
return (diffuse + specular) * spotFactor;
|
|
10305
10420
|
}
|
|
10306
10421
|
|
|
10307
|
-
|
|
10308
|
-
fn
|
|
10309
|
-
|
|
10310
|
-
|
|
10311
|
-
|
|
10312
|
-
|
|
10313
|
-
|
|
10314
|
-
|
|
10315
|
-
|
|
10316
|
-
|
|
10317
|
-
|
|
10318
|
-
|
|
10319
|
-
|
|
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
|
+
);
|
|
10320
10447
|
}
|
|
10321
|
-
visibility
|
|
10448
|
+
return visibility / 9.0;
|
|
10449
|
+
}
|
|
10450
|
+
|
|
10451
|
+
@fragment
|
|
10452
|
+
fn main(input: FragmentInput) -> @location(0) vec4f {
|
|
10322
10453
|
let norm = normalize(input.fragNorm);
|
|
10323
|
-
let viewDir = normalize(scene.cameraViewProjMatrix[3].xyz - input.fragPos);
|
|
10324
10454
|
|
|
10325
|
-
|
|
10455
|
+
let viewDir = normalize(scene.cameraPos - input.fragPos);
|
|
10456
|
+
// let viewDir = normalize(scene.cameraViewProjMatrix[3].xyz - input.fragPos);
|
|
10457
|
+
|
|
10326
10458
|
var lightContribution = vec3f(0.0);
|
|
10327
10459
|
var ambient = vec3f(0.0);
|
|
10328
10460
|
|
|
10329
|
-
for (var i = 0u; i < MAX_SPOTLIGHTS; i
|
|
10330
|
-
|
|
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;
|
|
10331
10473
|
ambient += spotlights[i].ambientFactor * spotlights[i].color;
|
|
10332
10474
|
}
|
|
10333
10475
|
|
|
10334
10476
|
let texColor = textureSample(meshTexture, meshSampler, input.uv);
|
|
10335
|
-
let finalColor = texColor.rgb * (ambient + lightContribution
|
|
10336
|
-
|
|
10477
|
+
let finalColor = texColor.rgb * (ambient + lightContribution); // * albedo;
|
|
10337
10478
|
return vec4f(finalColor, 1.0);
|
|
10338
|
-
}
|
|
10339
|
-
`;
|
|
10479
|
+
}`;
|
|
10340
10480
|
|
|
10341
10481
|
},{}],22:[function(require,module,exports){
|
|
10342
10482
|
"use strict";
|
|
@@ -10417,11 +10557,10 @@ struct Model {
|
|
|
10417
10557
|
@group(1) @binding(0) var<uniform> model : Model;
|
|
10418
10558
|
|
|
10419
10559
|
struct VertexOutput {
|
|
10420
|
-
@location(0) shadowPos:
|
|
10560
|
+
@location(0) shadowPos: vec4f, // now vec4
|
|
10421
10561
|
@location(1) fragPos: vec3f,
|
|
10422
10562
|
@location(2) fragNorm: vec3f,
|
|
10423
|
-
@location(3) uv
|
|
10424
|
-
|
|
10563
|
+
@location(3) uv: vec2f,
|
|
10425
10564
|
@builtin(position) Position: vec4f,
|
|
10426
10565
|
}
|
|
10427
10566
|
|
|
@@ -10429,34 +10568,21 @@ struct VertexOutput {
|
|
|
10429
10568
|
fn main(
|
|
10430
10569
|
@location(0) position: vec3f,
|
|
10431
10570
|
@location(1) normal: vec3f,
|
|
10432
|
-
@location(2) uv
|
|
10571
|
+
@location(2) uv: vec2f
|
|
10433
10572
|
) -> VertexOutput {
|
|
10434
10573
|
var output : VertexOutput;
|
|
10435
10574
|
|
|
10436
|
-
// XY is in (-1, 1) space, Z is in (0, 1) space
|
|
10437
10575
|
let posFromLight = scene.lightViewProjMatrix * model.modelMatrix * vec4(position, 1.0);
|
|
10438
|
-
|
|
10439
|
-
// Convert XY to (0, 1)
|
|
10440
|
-
// Y is flipped because texture coords are Y-down.
|
|
10441
|
-
output.shadowPos = vec3(
|
|
10442
|
-
posFromLight.xy * vec2(0.5, -0.5) + vec2(0.5),
|
|
10443
|
-
posFromLight.z
|
|
10444
|
-
);
|
|
10445
|
-
|
|
10446
|
-
// follewed camera code
|
|
10447
|
-
// output.Position = scene.cameraViewProjMatrix * model.modelMatrix * vec4(position, 1.0);
|
|
10448
|
-
// output.fragPos = output.Position.xyz;
|
|
10449
|
-
// output.fragNorm = normal;
|
|
10576
|
+
output.shadowPos = posFromLight; // pass full vec4 for perspective divide
|
|
10450
10577
|
|
|
10451
10578
|
let worldPos = model.modelMatrix * vec4(position, 1.0);
|
|
10452
10579
|
output.Position = scene.cameraViewProjMatrix * worldPos;
|
|
10453
|
-
output.fragPos = worldPos.xyz;
|
|
10580
|
+
output.fragPos = worldPos.xyz;
|
|
10454
10581
|
|
|
10455
10582
|
output.fragNorm = normalize((model.modelMatrix * vec4(normal, 0.0)).xyz);
|
|
10456
10583
|
output.uv = uv;
|
|
10457
10584
|
return output;
|
|
10458
|
-
}
|
|
10459
|
-
`;
|
|
10585
|
+
}`;
|
|
10460
10586
|
|
|
10461
10587
|
},{}],24:[function(require,module,exports){
|
|
10462
10588
|
"use strict";
|
|
@@ -10584,7 +10710,6 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
10584
10710
|
* @github zlatnaspirala
|
|
10585
10711
|
*/
|
|
10586
10712
|
class MatrixEngineWGPU {
|
|
10587
|
-
lightContainer;
|
|
10588
10713
|
mainRenderBundle = [];
|
|
10589
10714
|
lightContainer = [];
|
|
10590
10715
|
frame = () => {};
|
|
@@ -10649,7 +10774,6 @@ class MatrixEngineWGPU {
|
|
|
10649
10774
|
|
|
10650
10775
|
// The camera types
|
|
10651
10776
|
const initialCameraPosition = _wgpuMatrix.vec3.create(0, 0, 0);
|
|
10652
|
-
// console.log('passed : o.mainCameraParams.responseCoef ', o.mainCameraParams.responseCoef)
|
|
10653
10777
|
this.mainCameraParams = {
|
|
10654
10778
|
type: this.options.mainCameraParams.type,
|
|
10655
10779
|
responseCoef: this.options.mainCameraParams.responseCoef
|
|
@@ -10709,9 +10833,78 @@ class MatrixEngineWGPU {
|
|
|
10709
10833
|
createGlobalStuff() {
|
|
10710
10834
|
this.spotlightUniformBuffer = this.device.createBuffer({
|
|
10711
10835
|
label: 'spotlightUniformBufferGLOBAL',
|
|
10712
|
-
size: this.MAX_SPOTLIGHTS *
|
|
10836
|
+
size: this.MAX_SPOTLIGHTS * 144,
|
|
10713
10837
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
10714
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();
|
|
10715
10908
|
}
|
|
10716
10909
|
getSceneObjectByName(name) {
|
|
10717
10910
|
return this.mainRenderBundle.find(sceneObject => sceneObject.name === name);
|
|
@@ -10918,9 +11111,9 @@ class MatrixEngineWGPU {
|
|
|
10918
11111
|
};
|
|
10919
11112
|
addLight(o) {
|
|
10920
11113
|
const camera = this.cameras[this.mainCameraParams.type];
|
|
10921
|
-
let newLight = new _lights.SpotLight(camera, this.inputHandler);
|
|
10922
|
-
newLight.prepareBuffer(this.device);
|
|
11114
|
+
let newLight = new _lights.SpotLight(camera, this.inputHandler, this.device);
|
|
10923
11115
|
this.lightContainer.push(newLight);
|
|
11116
|
+
this.createTexArrayForShadows();
|
|
10924
11117
|
console.log(`%cAdd light: ${newLight}`, _utils.LOG_FUNNY_SMALL);
|
|
10925
11118
|
}
|
|
10926
11119
|
addMeshObj = (o, clearColor = this.options.clearColor) => {
|
|
@@ -11013,14 +11206,13 @@ class MatrixEngineWGPU {
|
|
|
11013
11206
|
// scale for all second option!
|
|
11014
11207
|
o.objAnim.scaleAll = function (s) {
|
|
11015
11208
|
for (var k in this.meshList) {
|
|
11016
|
-
console.log('SCALE');
|
|
11209
|
+
console.log('SCALE meshList');
|
|
11017
11210
|
this.meshList[k].setScale(s);
|
|
11018
11211
|
}
|
|
11019
11212
|
};
|
|
11020
11213
|
}
|
|
11021
|
-
let myMesh1 = new _meshObj.default(this.canvas, this.device, this.context, o);
|
|
11214
|
+
let myMesh1 = new _meshObj.default(this.canvas, this.device, this.context, o, this.inputHandler);
|
|
11022
11215
|
myMesh1.spotlightUniformBuffer = this.spotlightUniformBuffer;
|
|
11023
|
-
myMesh1.inputHandler = this.inputHandler;
|
|
11024
11216
|
myMesh1.clearColor = clearColor;
|
|
11025
11217
|
if (o.physics.enabled == true) {
|
|
11026
11218
|
this.matrixAmmo.addPhysics(myMesh1, o.physics);
|
|
@@ -11039,33 +11231,15 @@ class MatrixEngineWGPU {
|
|
|
11039
11231
|
this.mainRenderBundle = [];
|
|
11040
11232
|
this.canvas.remove();
|
|
11041
11233
|
};
|
|
11042
|
-
test = () => {
|
|
11043
|
-
const now = Date.now();
|
|
11044
|
-
// First frame safety
|
|
11045
|
-
let dt = (now - this.lastFrameMS) / this.mainCameraParams.responseCoef;
|
|
11046
|
-
if (!this.lastFrameMS) {
|
|
11047
|
-
dt = 16;
|
|
11048
|
-
}
|
|
11049
|
-
this.lastFrameMS = now;
|
|
11050
|
-
const camera = this.cameras[this.mainCameraParams.type];
|
|
11051
|
-
camera.update(dt, this.inputHandler());
|
|
11052
|
-
const camVP = _wgpuMatrix.mat4.multiply(camera.projectionMatrix, camera.view); // P * V
|
|
11053
|
-
|
|
11054
|
-
for (const mesh of this.mainRenderBundle) {
|
|
11055
|
-
// scene buffer layout = 0..63 lightVP, 64..127 camVP, 128..143 lightPos(+pad)
|
|
11056
|
-
this.device.queue.writeBuffer(mesh.sceneUniformBuffer, 64,
|
|
11057
|
-
// cameraViewProjMatrix offset
|
|
11058
|
-
camVP.buffer, camVP.byteOffset, camVP.byteLength);
|
|
11059
|
-
}
|
|
11060
|
-
};
|
|
11061
11234
|
updateLights() {
|
|
11062
|
-
//
|
|
11063
|
-
const data = new Float32Array(this.MAX_SPOTLIGHTS *
|
|
11235
|
+
const floatsPerLight = 36; // not 20 anymore
|
|
11236
|
+
const data = new Float32Array(this.MAX_SPOTLIGHTS * floatsPerLight);
|
|
11064
11237
|
for (let i = 0; i < this.MAX_SPOTLIGHTS; i++) {
|
|
11065
11238
|
if (i < this.lightContainer.length) {
|
|
11066
|
-
|
|
11239
|
+
const buf = this.lightContainer[i].getLightDataBuffer();
|
|
11240
|
+
data.set(buf, i * floatsPerLight);
|
|
11067
11241
|
} else {
|
|
11068
|
-
data.set(new Float32Array(
|
|
11242
|
+
data.set(new Float32Array(floatsPerLight), i * floatsPerLight);
|
|
11069
11243
|
}
|
|
11070
11244
|
}
|
|
11071
11245
|
this.device.queue.writeBuffer(this.spotlightUniformBuffer, 0, data.buffer);
|
|
@@ -11077,54 +11251,103 @@ class MatrixEngineWGPU {
|
|
|
11077
11251
|
}, 200);
|
|
11078
11252
|
return;
|
|
11079
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;
|
|
11080
11273
|
try {
|
|
11081
|
-
let shadowPass = null;
|
|
11082
|
-
let renderPass;
|
|
11083
11274
|
let commandEncoder = this.device.createCommandEncoder();
|
|
11084
11275
|
this.updateLights();
|
|
11085
|
-
this.test();
|
|
11086
|
-
|
|
11087
11276
|
// 1️⃣ Update light data (position, direction, uniforms)
|
|
11088
11277
|
for (const light of this.lightContainer) {
|
|
11278
|
+
light.update();
|
|
11279
|
+
// light.updateSceneUniforms(this.mainRenderBundle, this.cameras.WASD);
|
|
11089
11280
|
this.mainRenderBundle.forEach((meItem, index) => {
|
|
11090
|
-
|
|
11281
|
+
meItem.position.update();
|
|
11282
|
+
meItem.updateModelUniformBuffer();
|
|
11283
|
+
// if(meItem.isVideo != true) {
|
|
11284
|
+
meItem.getTransformationMatrix(this.mainRenderBundle, light);
|
|
11285
|
+
// }
|
|
11091
11286
|
});
|
|
11092
11287
|
}
|
|
11093
|
-
this.mainRenderBundle.forEach((meItem, index) => {
|
|
11094
|
-
meItem.position.update();
|
|
11095
|
-
});
|
|
11096
11288
|
if (this.matrixAmmo) this.matrixAmmo.updatePhysics();
|
|
11097
|
-
|
|
11098
|
-
|
|
11099
|
-
|
|
11100
|
-
|
|
11101
|
-
|
|
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();
|
|
11102
11318
|
}
|
|
11103
|
-
|
|
11104
|
-
this.
|
|
11105
|
-
|
|
11106
|
-
|
|
11107
|
-
|
|
11108
|
-
|
|
11109
|
-
|
|
11110
|
-
|
|
11111
|
-
|
|
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('✅shadowVideoView', this.shadowVideoView);
|
|
11329
|
+
m.shadowDepthTextureView = this.shadowVideoView;
|
|
11330
|
+
m.FINISH_VIDIO_INIT = true;
|
|
11331
|
+
m.setupPipeline();
|
|
11332
|
+
} else {
|
|
11333
|
+
m.shadowDepthTextureView = this.shadowArrayView;
|
|
11334
|
+
m.setupPipeline();
|
|
11335
|
+
}
|
|
11336
|
+
}
|
|
11112
11337
|
}
|
|
11113
|
-
|
|
11114
|
-
|
|
11115
|
-
|
|
11116
|
-
});
|
|
11117
|
-
if (renderPass) renderPass.end();
|
|
11338
|
+
mesh.drawElements(pass, this.lightContainer);
|
|
11339
|
+
}
|
|
11340
|
+
pass.end();
|
|
11118
11341
|
this.device.queue.submit([commandEncoder.finish()]);
|
|
11119
11342
|
requestAnimationFrame(this.frame);
|
|
11120
11343
|
} catch (err) {
|
|
11121
|
-
console.log('%cLoop
|
|
11344
|
+
console.log('%cLoop(err):' + err, _utils.LOG_WARN);
|
|
11122
11345
|
requestAnimationFrame(this.frame);
|
|
11123
11346
|
}
|
|
11124
11347
|
};
|
|
11125
11348
|
framePassPerObject = () => {
|
|
11126
11349
|
let commandEncoder = this.device.createCommandEncoder();
|
|
11127
|
-
this.matrixAmmo.updatePhysics();
|
|
11350
|
+
if (this.matrixAmmo.rigidBodies.length > 0) this.matrixAmmo.updatePhysics();
|
|
11128
11351
|
this.mainRenderBundle.forEach((meItem, index) => {
|
|
11129
11352
|
if (index === 0) {
|
|
11130
11353
|
if (meItem.renderPassDescriptor) meItem.renderPassDescriptor.colorAttachments[0].loadOp = 'clear';
|