matrix-engine-wgpu 1.0.5 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/REFERENCE.md +5 -0
- package/examples/load-obj-file.js +1 -8
- package/main.js +27 -23
- package/package.json +35 -41
- package/public/app.js +642 -156
- package/public/css/style.css +6 -3
- package/public/empty.js +466 -84
- package/public/examples.js +466 -84
- package/public/index.html +4 -4
- package/public/res/fonts/Accuratist.ttf +0 -0
- package/public/res/fonts/Closeness.ttf +0 -0
- package/public/res/fonts/WARGAMES.TTF +0 -0
- package/public/res/fonts/readme.txt +5 -0
- package/public/res/fonts/stormfaze.ttf +0 -0
- package/public/res/meshes/blender/cube.blend +0 -0
- package/public/res/meshes/blender/cube.blend1 +0 -0
- package/public/res/meshes/blender/cube.mtl +12 -0
- package/public/res/meshes/blender/cube.obj +46 -0
- package/public/res/meshes/blender/cube.png +0 -0
- package/public/res/meshes/blender/cubeSmartUV.blend +0 -0
- package/public/res/meshes/blender/cubeSmartUV.mtl +12 -0
- package/public/res/meshes/blender/cubeSmartUV.obj +46 -0
- package/public/res/meshes/blender/sphepe.blend +0 -0
- package/public/res/meshes/blender/sphepe.blend1 +0 -0
- package/public/res/meshes/blender/sphere.mtl +10 -0
- package/public/res/meshes/blender/sphere.obj +3402 -0
- package/readme.md +72 -30
- package/src/engine/cube.js +0 -4
- package/src/engine/engine.js +2 -4
- package/src/engine/matrix-class.js +11 -6
- package/src/engine/mesh-obj.js +9 -19
- package/src/engine/mesh.js +476 -0
- package/src/engine/utils.js +63 -15
- package/src/physics/matrix-ammo.js +43 -22
- package/src/world.js +75 -62
- package/src/engine/matrix-mesh.js +0 -49
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
import {mat4, vec3} from 'wgpu-matrix';
|
|
2
|
+
import {Position, Rotation} from "./matrix-class";
|
|
3
|
+
import {createInputHandler} from "./engine";
|
|
4
|
+
import {vertexShadowWGSL} from '../shaders/vertexShadow.wgsl';
|
|
5
|
+
import {fragmentWGSL} from '../shaders/fragment.wgsl';
|
|
6
|
+
import {vertexWGSL} from '../shaders/vertex.wgsl';
|
|
7
|
+
import {downloadMeshes} from './loader-obj';
|
|
8
|
+
|
|
9
|
+
export default class MEMesh {
|
|
10
|
+
|
|
11
|
+
constructor(canvas, device, context, o) {
|
|
12
|
+
|
|
13
|
+
this.done = false;
|
|
14
|
+
this.device = device;
|
|
15
|
+
this.context = context;
|
|
16
|
+
this.entityArgPass = o.entityArgPass;
|
|
17
|
+
|
|
18
|
+
this.mesh = o.mesh;
|
|
19
|
+
this.inputHandler = createInputHandler(window, canvas);
|
|
20
|
+
this.cameras = o.cameras;
|
|
21
|
+
this.mainCameraParams = {
|
|
22
|
+
type: o.mainCameraParams.type,
|
|
23
|
+
responseCoef: o.mainCameraParams.responseCoef
|
|
24
|
+
}
|
|
25
|
+
this.lastFrameMS = 0;
|
|
26
|
+
this.texturesPaths = [];
|
|
27
|
+
o.texturesPaths.forEach((t) => {this.texturesPaths.push(t)})
|
|
28
|
+
this.presentationFormat = navigator.gpu.getPreferredCanvasFormat();
|
|
29
|
+
this.position = new Position(o.position.x, o.position.y, o.position.z);
|
|
30
|
+
// console.log('cube added on pos : ', this.position)
|
|
31
|
+
this.rotation = new Rotation(o.rotation.x, o.rotation.y, o.rotation.z);
|
|
32
|
+
this.rotation.rotationSpeed.x = o.rotationSpeed.x;
|
|
33
|
+
this.rotation.rotationSpeed.y = o.rotationSpeed.y;
|
|
34
|
+
this.rotation.rotationSpeed.z = o.rotationSpeed.z;
|
|
35
|
+
this.scale = o.scale;
|
|
36
|
+
|
|
37
|
+
// new
|
|
38
|
+
this.runProgram = () => {
|
|
39
|
+
return new Promise(async (resolve) => {
|
|
40
|
+
this.shadowDepthTextureSize = 1024;
|
|
41
|
+
const aspect = canvas.width / canvas.height;
|
|
42
|
+
this.projectionMatrix = mat4.perspective((2 * Math.PI) / 5, aspect, 1, 2000.0);
|
|
43
|
+
this.modelViewProjectionMatrix = mat4.create();
|
|
44
|
+
|
|
45
|
+
this.loadTex0(this.texturesPaths, device).then(() => {
|
|
46
|
+
resolve()
|
|
47
|
+
console.log('load tex for mesh', this.texture0)
|
|
48
|
+
})
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
this.runProgram().then(() => {
|
|
53
|
+
const aspect = canvas.width / canvas.height;
|
|
54
|
+
const presentationFormat = navigator.gpu.getPreferredCanvasFormat();
|
|
55
|
+
this.context.configure({
|
|
56
|
+
device: this.device,
|
|
57
|
+
format: presentationFormat,
|
|
58
|
+
alphaMode: 'premultiplied',
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Create the model vertex buffer.
|
|
62
|
+
this.vertexBuffer = this.device.createBuffer({
|
|
63
|
+
size: this.mesh.positions.length * 3 * 2 * Float32Array.BYTES_PER_ELEMENT,
|
|
64
|
+
usage: GPUBufferUsage.VERTEX,
|
|
65
|
+
mappedAtCreation: true,
|
|
66
|
+
});
|
|
67
|
+
{
|
|
68
|
+
const mapping = new Float32Array(this.vertexBuffer.getMappedRange());
|
|
69
|
+
for(let i = 0;i < this.mesh.positions.length;++i) {
|
|
70
|
+
mapping.set(this.mesh.positions[i], 6 * i);
|
|
71
|
+
mapping.set(this.mesh.normals[i], 6 * i + 3);
|
|
72
|
+
}
|
|
73
|
+
this.vertexBuffer.unmap();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Create the model index buffer.
|
|
77
|
+
this.indexCount = this.mesh.triangles.length * 3;
|
|
78
|
+
this.indexBuffer = this.device.createBuffer({
|
|
79
|
+
size: this.indexCount * Uint16Array.BYTES_PER_ELEMENT,
|
|
80
|
+
usage: GPUBufferUsage.INDEX,
|
|
81
|
+
mappedAtCreation: true,
|
|
82
|
+
});
|
|
83
|
+
{
|
|
84
|
+
const mapping = new Uint16Array(this.indexBuffer.getMappedRange());
|
|
85
|
+
for(let i = 0;i < this.mesh.triangles.length;++i) {
|
|
86
|
+
mapping.set(this.mesh.triangles[i], 3 * i);
|
|
87
|
+
}
|
|
88
|
+
this.indexBuffer.unmap();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Create the depth texture for rendering/sampling the shadow map.
|
|
92
|
+
this.shadowDepthTexture = this.device.createTexture({
|
|
93
|
+
size: [this.shadowDepthTextureSize, this.shadowDepthTextureSize, 1],
|
|
94
|
+
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,
|
|
95
|
+
format: 'depth32float',
|
|
96
|
+
});
|
|
97
|
+
this.shadowDepthTextureView = this.shadowDepthTexture.createView();
|
|
98
|
+
|
|
99
|
+
// Create some common descriptors used for both the shadow pipeline
|
|
100
|
+
// and the color rendering pipeline.
|
|
101
|
+
this.vertexBuffers = [
|
|
102
|
+
{
|
|
103
|
+
arrayStride: Float32Array.BYTES_PER_ELEMENT * 6,
|
|
104
|
+
attributes: [
|
|
105
|
+
{
|
|
106
|
+
// position
|
|
107
|
+
shaderLocation: 0,
|
|
108
|
+
offset: 0,
|
|
109
|
+
format: 'float32x3',
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
// normal
|
|
113
|
+
shaderLocation: 1,
|
|
114
|
+
offset: Float32Array.BYTES_PER_ELEMENT * 3,
|
|
115
|
+
format: 'float32x3',
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
},
|
|
119
|
+
];
|
|
120
|
+
|
|
121
|
+
const primitive = {
|
|
122
|
+
topology: 'triangle-list',
|
|
123
|
+
cullMode: 'back',
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
this.uniformBufferBindGroupLayout = this.device.createBindGroupLayout({
|
|
127
|
+
entries: [
|
|
128
|
+
{
|
|
129
|
+
binding: 0,
|
|
130
|
+
visibility: GPUShaderStage.VERTEX,
|
|
131
|
+
buffer: {
|
|
132
|
+
type: 'uniform',
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
this.shadowPipeline = this.device.createRenderPipeline({
|
|
139
|
+
layout: this.device.createPipelineLayout({
|
|
140
|
+
bindGroupLayouts: [
|
|
141
|
+
this.uniformBufferBindGroupLayout,
|
|
142
|
+
this.uniformBufferBindGroupLayout,
|
|
143
|
+
],
|
|
144
|
+
}),
|
|
145
|
+
vertex: {
|
|
146
|
+
module: this.device.createShaderModule({
|
|
147
|
+
code: vertexShadowWGSL,
|
|
148
|
+
}),
|
|
149
|
+
buffers: this.vertexBuffers,
|
|
150
|
+
},
|
|
151
|
+
depthStencil: {
|
|
152
|
+
depthWriteEnabled: true,
|
|
153
|
+
depthCompare: 'less',
|
|
154
|
+
format: 'depth32float',
|
|
155
|
+
},
|
|
156
|
+
primitive,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// Create a bind group layout which holds the scene uniforms and
|
|
160
|
+
// the texture+sampler for depth. We create it manually because the WebPU
|
|
161
|
+
// implementation doesn't infer this from the shader (yet).
|
|
162
|
+
this.bglForRender = this.device.createBindGroupLayout({
|
|
163
|
+
entries: [
|
|
164
|
+
{
|
|
165
|
+
binding: 0,
|
|
166
|
+
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
|
|
167
|
+
buffer: {
|
|
168
|
+
type: 'uniform',
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
binding: 1,
|
|
173
|
+
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
|
|
174
|
+
texture: {
|
|
175
|
+
sampleType: 'depth',
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
binding: 2,
|
|
180
|
+
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
|
|
181
|
+
sampler: {
|
|
182
|
+
type: 'comparison',
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
binding: 3,
|
|
187
|
+
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
|
|
188
|
+
texture: {
|
|
189
|
+
sampleType: 'float',
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
binding: 4,
|
|
194
|
+
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
|
|
195
|
+
sampler: {
|
|
196
|
+
type: 'filtering',
|
|
197
|
+
},
|
|
198
|
+
}
|
|
199
|
+
],
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
this.pipeline = this.device.createRenderPipeline({
|
|
203
|
+
layout: this.device.createPipelineLayout({
|
|
204
|
+
bindGroupLayouts: [this.bglForRender, this.uniformBufferBindGroupLayout],
|
|
205
|
+
}),
|
|
206
|
+
vertex: {
|
|
207
|
+
module: this.device.createShaderModule({
|
|
208
|
+
code: vertexWGSL,
|
|
209
|
+
}),
|
|
210
|
+
buffers: this.vertexBuffers,
|
|
211
|
+
},
|
|
212
|
+
fragment: {
|
|
213
|
+
module: this.device.createShaderModule({
|
|
214
|
+
code: fragmentWGSL,
|
|
215
|
+
}),
|
|
216
|
+
targets: [
|
|
217
|
+
{
|
|
218
|
+
format: presentationFormat,
|
|
219
|
+
},
|
|
220
|
+
],
|
|
221
|
+
constants: {
|
|
222
|
+
shadowDepthTextureSize: this.shadowDepthTextureSize,
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
depthStencil: {
|
|
226
|
+
depthWriteEnabled: true,
|
|
227
|
+
depthCompare: 'less',
|
|
228
|
+
format: 'depth24plus-stencil8',
|
|
229
|
+
},
|
|
230
|
+
primitive,
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
const depthTexture = this.device.createTexture({
|
|
234
|
+
size: [canvas.width, canvas.height],
|
|
235
|
+
format: 'depth24plus-stencil8',
|
|
236
|
+
usage: GPUTextureUsage.RENDER_ATTACHMENT,
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
this.renderPassDescriptor = {
|
|
240
|
+
colorAttachments: [
|
|
241
|
+
{
|
|
242
|
+
// view is acquired and set in render loop.
|
|
243
|
+
view: undefined,
|
|
244
|
+
|
|
245
|
+
clearValue: {r: 0.5, g: 0.5, b: 0.5, a: 1.0},
|
|
246
|
+
loadOp: 'load',
|
|
247
|
+
storeOp: 'store',
|
|
248
|
+
},
|
|
249
|
+
],
|
|
250
|
+
depthStencilAttachment: {
|
|
251
|
+
view: depthTexture.createView(),
|
|
252
|
+
|
|
253
|
+
depthClearValue: 1.0,
|
|
254
|
+
depthLoadOp: 'clear',
|
|
255
|
+
depthStoreOp: 'store',
|
|
256
|
+
stencilClearValue: 0,
|
|
257
|
+
stencilLoadOp: 'clear',
|
|
258
|
+
stencilStoreOp: 'store',
|
|
259
|
+
},
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
this.modelUniformBuffer = this.device.createBuffer({
|
|
263
|
+
size: 4 * 16, // 4x4 matrix
|
|
264
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
this.sceneUniformBuffer = this.device.createBuffer({
|
|
268
|
+
// Two 4x4 viewProj matrices,
|
|
269
|
+
// one for the camera and one for the light.
|
|
270
|
+
// Then a vec3 for the light position.
|
|
271
|
+
// Rounded to the nearest multiple of 16.
|
|
272
|
+
size: 2 * 4 * 16 + 4 * 4,
|
|
273
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
this.sceneBindGroupForShadow = this.device.createBindGroup({
|
|
277
|
+
layout: this.uniformBufferBindGroupLayout,
|
|
278
|
+
entries: [
|
|
279
|
+
{
|
|
280
|
+
binding: 0,
|
|
281
|
+
resource: {
|
|
282
|
+
buffer: this.sceneUniformBuffer,
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
],
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
this.sceneBindGroupForRender = this.device.createBindGroup({
|
|
289
|
+
layout: this.bglForRender,
|
|
290
|
+
entries: [
|
|
291
|
+
{
|
|
292
|
+
binding: 0,
|
|
293
|
+
resource: {
|
|
294
|
+
buffer: this.sceneUniformBuffer,
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
binding: 1,
|
|
299
|
+
resource: this.shadowDepthTextureView,
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
binding: 2,
|
|
303
|
+
resource: this.device.createSampler({
|
|
304
|
+
compare: 'less',
|
|
305
|
+
}),
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
binding: 3,
|
|
309
|
+
resource: this.texture0.createView(),
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
binding: 4,
|
|
313
|
+
resource: this.sampler,
|
|
314
|
+
},
|
|
315
|
+
],
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
this.modelBindGroup = this.device.createBindGroup({
|
|
319
|
+
layout: this.uniformBufferBindGroupLayout,
|
|
320
|
+
entries: [
|
|
321
|
+
{
|
|
322
|
+
binding: 0,
|
|
323
|
+
resource: {
|
|
324
|
+
buffer: this.modelUniformBuffer,
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
],
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
// Rotates the camera around the origin based on time.
|
|
331
|
+
this.getTransformationMatrix = (pos) => {
|
|
332
|
+
const now = Date.now();
|
|
333
|
+
const deltaTime = (now - this.lastFrameMS) / this.mainCameraParams.responseCoef;
|
|
334
|
+
this.lastFrameMS = now;
|
|
335
|
+
|
|
336
|
+
const camera = this.cameras[this.mainCameraParams.type];
|
|
337
|
+
this.viewMatrix = camera.update(deltaTime, this.inputHandler());
|
|
338
|
+
|
|
339
|
+
mat4.translate(this.viewMatrix, vec3.fromValues(pos.x, pos.y, pos.z), this.viewMatrix);
|
|
340
|
+
mat4.rotateX(this.viewMatrix, Math.PI * this.rotation.getRotX(), this.viewMatrix);
|
|
341
|
+
mat4.rotateY(this.viewMatrix, Math.PI * this.rotation.getRotY(), this.viewMatrix);
|
|
342
|
+
mat4.rotateZ(this.viewMatrix, Math.PI * this.rotation.getRotZ(), this.viewMatrix);
|
|
343
|
+
mat4.multiply(this.projectionMatrix, this.viewMatrix, this.modelViewProjectionMatrix);
|
|
344
|
+
|
|
345
|
+
return this.modelViewProjectionMatrix;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
this.upVector = vec3.fromValues(0, 1, 0);
|
|
349
|
+
this.origin = vec3.fromValues(0, 0, 0);
|
|
350
|
+
|
|
351
|
+
const lightPosition = vec3.fromValues(50, 100, -100);
|
|
352
|
+
const lightViewMatrix = mat4.lookAt(lightPosition, this.origin, this.upVector);
|
|
353
|
+
const lightProjectionMatrix = mat4.create();
|
|
354
|
+
{
|
|
355
|
+
const left = -80;
|
|
356
|
+
const right = 80;
|
|
357
|
+
const bottom = -80;
|
|
358
|
+
const top = 80;
|
|
359
|
+
const near = -200;
|
|
360
|
+
const far = 300;
|
|
361
|
+
mat4.ortho(left, right, bottom, top, near, far, lightProjectionMatrix);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const lightViewProjMatrix = mat4.multiply(
|
|
365
|
+
lightProjectionMatrix,
|
|
366
|
+
lightViewMatrix
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
// looks like affect on transformations for now const 0
|
|
370
|
+
const modelMatrix = mat4.translation([0, 0, 0]);
|
|
371
|
+
// The camera/light aren't moving, so write them into buffers now.
|
|
372
|
+
{
|
|
373
|
+
const lightMatrixData = lightViewProjMatrix; // as Float32Array;
|
|
374
|
+
this.device.queue.writeBuffer(
|
|
375
|
+
this.sceneUniformBuffer,
|
|
376
|
+
0,
|
|
377
|
+
lightMatrixData.buffer,
|
|
378
|
+
lightMatrixData.byteOffset,
|
|
379
|
+
lightMatrixData.byteLength
|
|
380
|
+
);
|
|
381
|
+
|
|
382
|
+
const lightData = lightPosition;
|
|
383
|
+
this.device.queue.writeBuffer(
|
|
384
|
+
this.sceneUniformBuffer,
|
|
385
|
+
128,
|
|
386
|
+
lightData.buffer,
|
|
387
|
+
lightData.byteOffset,
|
|
388
|
+
lightData.byteLength
|
|
389
|
+
);
|
|
390
|
+
|
|
391
|
+
const modelData = modelMatrix;
|
|
392
|
+
this.device.queue.writeBuffer(
|
|
393
|
+
this.modelUniformBuffer,
|
|
394
|
+
0,
|
|
395
|
+
modelData.buffer,
|
|
396
|
+
modelData.byteOffset,
|
|
397
|
+
modelData.byteLength
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
this.shadowPassDescriptor = {
|
|
402
|
+
colorAttachments: [],
|
|
403
|
+
depthStencilAttachment: {
|
|
404
|
+
view: this.shadowDepthTextureView,
|
|
405
|
+
depthClearValue: 1.0,
|
|
406
|
+
depthLoadOp: 'clear',
|
|
407
|
+
depthStoreOp: 'store',
|
|
408
|
+
},
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
this.done = true;
|
|
412
|
+
})
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
async loadTex0(texturesPaths, device) {
|
|
416
|
+
this.sampler = device.createSampler({
|
|
417
|
+
magFilter: 'linear',
|
|
418
|
+
minFilter: 'linear',
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
return new Promise(async (resolve) => {
|
|
422
|
+
const response = await fetch(texturesPaths[0]);
|
|
423
|
+
const imageBitmap = await createImageBitmap(await response.blob());
|
|
424
|
+
this.texture0 = device.createTexture({
|
|
425
|
+
size: [imageBitmap.width, imageBitmap.height, 1],
|
|
426
|
+
format: 'rgba8unorm',
|
|
427
|
+
usage:
|
|
428
|
+
GPUTextureUsage.TEXTURE_BINDING |
|
|
429
|
+
GPUTextureUsage.COPY_DST |
|
|
430
|
+
GPUTextureUsage.RENDER_ATTACHMENT,
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
device.queue.copyExternalImageToTexture(
|
|
434
|
+
{source: imageBitmap},
|
|
435
|
+
{texture: this.texture0},
|
|
436
|
+
[imageBitmap.width, imageBitmap.height]
|
|
437
|
+
);
|
|
438
|
+
resolve()
|
|
439
|
+
})
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
draw = (commandEncoder) => {
|
|
443
|
+
if(this.done == false) return;
|
|
444
|
+
const transformationMatrix = this.getTransformationMatrix(this.position);
|
|
445
|
+
this.device.queue.writeBuffer(
|
|
446
|
+
this.sceneUniformBuffer,
|
|
447
|
+
64,
|
|
448
|
+
transformationMatrix.buffer,
|
|
449
|
+
transformationMatrix.byteOffset,
|
|
450
|
+
transformationMatrix.byteLength
|
|
451
|
+
);
|
|
452
|
+
this.renderPassDescriptor.colorAttachments[0].view = this.context
|
|
453
|
+
.getCurrentTexture()
|
|
454
|
+
.createView();
|
|
455
|
+
{
|
|
456
|
+
const shadowPass = commandEncoder.beginRenderPass(this.shadowPassDescriptor);
|
|
457
|
+
shadowPass.setPipeline(this.shadowPipeline);
|
|
458
|
+
shadowPass.setBindGroup(0, this.sceneBindGroupForShadow);
|
|
459
|
+
shadowPass.setBindGroup(1, this.modelBindGroup);
|
|
460
|
+
shadowPass.setVertexBuffer(0, this.vertexBuffer);
|
|
461
|
+
shadowPass.setIndexBuffer(this.indexBuffer, 'uint16');
|
|
462
|
+
shadowPass.drawIndexed(this.indexCount);
|
|
463
|
+
shadowPass.end();
|
|
464
|
+
}
|
|
465
|
+
{
|
|
466
|
+
const renderPass = commandEncoder.beginRenderPass(this.renderPassDescriptor);
|
|
467
|
+
renderPass.setPipeline(this.pipeline);
|
|
468
|
+
renderPass.setBindGroup(0, this.sceneBindGroupForRender);
|
|
469
|
+
renderPass.setBindGroup(1, this.modelBindGroup);
|
|
470
|
+
renderPass.setVertexBuffer(0, this.vertexBuffer);
|
|
471
|
+
renderPass.setIndexBuffer(this.indexBuffer, 'uint16');
|
|
472
|
+
renderPass.drawIndexed(this.indexCount);
|
|
473
|
+
renderPass.end();
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
package/src/engine/utils.js
CHANGED
|
@@ -543,17 +543,18 @@ export var QueryString = (function() {
|
|
|
543
543
|
|
|
544
544
|
|
|
545
545
|
export function getAxisRot(q1) {
|
|
546
|
-
var x,y,z;
|
|
546
|
+
var x, y, z;
|
|
547
547
|
|
|
548
548
|
// if w>1 acos and sqrt will produce errors, this cant happen if quaternion is normalised
|
|
549
|
-
if
|
|
549
|
+
if(q1.w > 1) q1.normalise();
|
|
550
550
|
var angle = 2 * Math.acos(q1.w);
|
|
551
551
|
// assuming quaternion normalised then w is less than 1, so term always positive.
|
|
552
|
-
var s = Math.sqrt(1-q1.w*q1.w);
|
|
553
|
-
|
|
554
|
-
if
|
|
552
|
+
var s = Math.sqrt(1 - q1.w * q1.w);
|
|
553
|
+
// test to avoid divide by zero, s is always positive due to sqrt
|
|
554
|
+
if(s < 0.001) {
|
|
555
555
|
// if s close to zero then direction of axis not important
|
|
556
|
-
|
|
556
|
+
// if it is important that axis is normalised then replace with x=1; y=z=0;
|
|
557
|
+
|
|
557
558
|
x = q1.x;
|
|
558
559
|
y = q1.y;
|
|
559
560
|
z = q1.z;
|
|
@@ -562,12 +563,53 @@ export function getAxisRot(q1) {
|
|
|
562
563
|
y = q1.y / s;
|
|
563
564
|
z = q1.z / s;
|
|
564
565
|
}
|
|
565
|
-
return [radToDeg(x),radToDeg(y), radToDeg(z)]
|
|
566
|
+
return [radToDeg(x), radToDeg(y), radToDeg(z)]
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
export function getAxisRot2(targetAxis, Q) {
|
|
570
|
+
Q.normalize(); // if w>1 acos and sqrt will produce errors, this cant happen if quaternion is normalised
|
|
571
|
+
var angle = 2 * Math.acos(Q.w());
|
|
572
|
+
var s = Math.sqrt(1 - Q.w() * Q.w()); // assuming quaternion normalised then w is less than 1, so term always positive.
|
|
573
|
+
if(s < 0.001) { // test to avoid divide by zero, s is always positive due to sqrt
|
|
574
|
+
// if s close to zero then direction of axis not important
|
|
575
|
+
// if it is important that axis is normalised then replace with x=1; y=z=0;
|
|
576
|
+
// targetAxis.x = 1;
|
|
577
|
+
// targetAxis.y = 0;
|
|
578
|
+
// targetAxis.z = 0;
|
|
579
|
+
targetAxis.x = Q.x();
|
|
580
|
+
targetAxis.y = Q.y();
|
|
581
|
+
targetAxis.z = Q.z();
|
|
582
|
+
} else {
|
|
583
|
+
targetAxis.x = Q.x() / s; // normalise axis
|
|
584
|
+
targetAxis.y = Q.y() / s;
|
|
585
|
+
targetAxis.z = Q.z() / s;
|
|
586
|
+
}
|
|
587
|
+
return [targetAxis, angle];
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
export function getAxisRot3(Q) {
|
|
591
|
+
|
|
592
|
+
var angle = Math.acos(Q.w) * 2;
|
|
593
|
+
var axis = {};
|
|
594
|
+
|
|
595
|
+
if(Math.sin(Math.acos(angle)) > 0) {
|
|
596
|
+
|
|
597
|
+
axis.x = Q.x / Math.sin(Math.acos(angle / 2));
|
|
598
|
+
axis.y = Q.y / Math.sin(Math.acos(angle / 2));
|
|
599
|
+
axis.z = Q.z / Math.sin(Math.acos(angle / 2));
|
|
600
|
+
|
|
601
|
+
} else {
|
|
602
|
+
axis.x = 0;
|
|
603
|
+
axis.y = 0;
|
|
604
|
+
axis.z = 0;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
return axis;
|
|
566
608
|
}
|
|
567
609
|
|
|
568
610
|
// NTO TESTED
|
|
569
611
|
export function quaternion_rotation_matrix(Q) {
|
|
570
|
-
|
|
612
|
+
|
|
571
613
|
// Covert a quaternion into a full three-dimensional rotation matrix.
|
|
572
614
|
|
|
573
615
|
// Input
|
|
@@ -583,26 +625,32 @@ export function quaternion_rotation_matrix(Q) {
|
|
|
583
625
|
var q1 = Q[1]
|
|
584
626
|
var q2 = Q[2]
|
|
585
627
|
var q3 = Q[3]
|
|
586
|
-
|
|
628
|
+
|
|
587
629
|
// # First row of the rotation matrix
|
|
588
630
|
var r00 = 2 * (q0 * q0 + q1 * q1) - 1
|
|
589
631
|
var r01 = 2 * (q1 * q2 - q0 * q3)
|
|
590
632
|
var r02 = 2 * (q1 * q3 + q0 * q2)
|
|
591
|
-
|
|
633
|
+
|
|
592
634
|
// # Second row of the rotation matrix
|
|
593
635
|
var r10 = 2 * (q1 * q2 + q0 * q3)
|
|
594
636
|
var r11 = 2 * (q0 * q0 + q2 * q2) - 1
|
|
595
637
|
var r12 = 2 * (q2 * q3 - q0 * q1)
|
|
596
|
-
|
|
638
|
+
|
|
597
639
|
// # Third row of the rotation matrix
|
|
598
640
|
var r20 = 2 * (q1 * q3 - q0 * q2)
|
|
599
641
|
var r21 = 2 * (q2 * q3 + q0 * q1)
|
|
600
642
|
var r22 = 2 * (q0 * q0 + q3 * q3) - 1
|
|
601
|
-
|
|
643
|
+
|
|
602
644
|
// # 3x3 rotation matrix
|
|
603
645
|
var rot_matrix = [[r00, r01, r02],
|
|
604
|
-
|
|
605
|
-
|
|
646
|
+
[r10, r11, r12],
|
|
647
|
+
[r20, r21, r22]]
|
|
606
648
|
|
|
607
649
|
return rot_matrix;
|
|
608
|
-
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// copnsole log graphics
|
|
653
|
+
export const LOG_WARN = 'background: gray; color: yellow; font-size:10px';
|
|
654
|
+
export const LOG_INFO = 'background: green; color: white; font-size:11px';
|
|
655
|
+
export const LOG_MATRIX = "font-family: verdana;color: #lime; font-size:11px;text-shadow: 2px 2px 4px orangered;background: black;";
|
|
656
|
+
export const LOG_FUNNY = "font-family: stormfaze;color: #f1f033; font-size:14px;text-shadow: 2px 2px 4px #f335f4, 4px 4px 4px #d64444, 2px 2px 4px #c160a6, 6px 2px 0px #123de3;background: black;";
|