Skip to content

Commit d67ae2a

Browse files
committed
Simplify normal map sample, fix toy box normals.
Mirror the toy-box texture to fix the normals. Simplify the `box.ts` code. This was more complicated than it needed to be, and borrowed code from another project. This code also used vec3 methods with two-element vectors, which might cause issues with future versions of 'wgpu-matrix' Simplfiy `normalMap.wgsl` * Use `const` declarations to name the various modes instead of magic literals. * Calculate the `worldViewProj` and `worldView` matrices on the CPU and pass them in as part of the uniform buffer. Reduces duplicated work in the vertex shader, and reduces the amount of data needed to be passed in. * Use `vec3f` for the light position instead of scalar. Pass in the position in view-space. * Reduce the amount of data passed from vertex to fragment. * Rename `tbn` to `tangent`, `bitangent` and `normal`. * Remove unused function `when_greater` * Split `parallax_uv` into two functions. * Simplify steep-parallax loop. Pre-calculate the UV derivatives so we can break early from the loop. Rename 'diffuse' textures to 'albedo'. Technically a diffuse texture already has diffuse lighting applied. Fixed: #317
1 parent b77d32c commit d67ae2a

File tree

11 files changed

+270
-538
lines changed

11 files changed

+270
-538
lines changed

public/assets/img/toybox_height.png

5.38 KB
Loading

public/assets/img/toybox_normal.png

3.71 KB
Loading
File renamed without changes.

public/img/toybox_height.png

345 Bytes
Loading

public/img/toybox_normal.png

-477 Bytes
Loading
File renamed without changes.

src/meshes/box.ts

Lines changed: 97 additions & 339 deletions
Large diffs are not rendered by default.

src/sample/normalMap/main.ts

Lines changed: 53 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { mat4 } from 'wgpu-matrix';
1+
import { mat4, vec3 } from 'wgpu-matrix';
22
import { makeSample, SampleInit } from '../../components/SampleLayout';
33
import normalMapWGSL from './normalMap.wgsl';
44
import { createMeshRenderable } from '../../meshes/mesh';
@@ -33,7 +33,7 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => {
3333

3434
interface GUISettings {
3535
'Bump Mode':
36-
| 'Diffuse Texture'
36+
| 'Albedo Texture'
3737
| 'Normal Texture'
3838
| 'Depth Texture'
3939
| 'Normal Map'
@@ -60,7 +60,7 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => {
6060
lightPosX: 1.7,
6161
lightPosY: 0.7,
6262
lightPosZ: -1.9,
63-
lightIntensity: 0.02,
63+
lightIntensity: 5.0,
6464
depthScale: 0.05,
6565
depthLayers: 16,
6666
Texture: 'Spiral',
@@ -76,24 +76,26 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => {
7676
usage: GPUTextureUsage.RENDER_ATTACHMENT,
7777
});
7878

79-
const uniformBuffer = device.createBuffer({
79+
const spaceTransformsBuffer = device.createBuffer({
8080
// Buffer holding projection, view, and model matrices plus padding bytes
8181
size: MAT4X4_BYTES * 4,
8282
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
8383
});
8484

85-
const mapMethodBuffer = device.createBuffer({
85+
const mapInfoBuffer = device.createBuffer({
8686
// Buffer holding mapping type, light uniforms, and depth uniforms
87-
size: Float32Array.BYTES_PER_ELEMENT * 7,
87+
size: Float32Array.BYTES_PER_ELEMENT * 8,
8888
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
8989
});
90+
const mapInfoArray = new ArrayBuffer(mapInfoBuffer.size);
91+
const mapInfoView = new DataView(mapInfoArray, 0, mapInfoArray.byteLength);
9092

9193
// Fetch the image and upload it into a GPUTexture.
92-
let woodDiffuseTexture: GPUTexture;
94+
let woodAlbedoTexture: GPUTexture;
9395
{
94-
const response = await fetch('../assets/img/wood_diffuse.png');
96+
const response = await fetch('../assets/img/wood_albedo.png');
9597
const imageBitmap = await createImageBitmap(await response.blob());
96-
woodDiffuseTexture = createTextureFromImage(device, imageBitmap);
98+
woodAlbedoTexture = createTextureFromImage(device, imageBitmap);
9799
}
98100

99101
let spiralNormalTexture: GPUTexture;
@@ -124,11 +126,11 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => {
124126
toyboxHeightTexture = createTextureFromImage(device, imageBitmap);
125127
}
126128

127-
let brickwallDiffuseTexture: GPUTexture;
129+
let brickwallAlbedoTexture: GPUTexture;
128130
{
129-
const response = await fetch('../assets/img/brickwall_diffuse.png');
131+
const response = await fetch('../assets/img/brickwall_albedo.png');
130132
const imageBitmap = await createImageBitmap(await response.blob());
131-
brickwallDiffuseTexture = createTextureFromImage(device, imageBitmap);
133+
brickwallAlbedoTexture = createTextureFromImage(device, imageBitmap);
132134
}
133135

134136
let brickwallNormalTexture: GPUTexture;
@@ -184,7 +186,7 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => {
184186
],
185187
['buffer', 'buffer'],
186188
[{ type: 'uniform' }, { type: 'uniform' }],
187-
[[{ buffer: uniformBuffer }, { buffer: mapMethodBuffer }]],
189+
[[{ buffer: spaceTransformsBuffer }, { buffer: mapInfoBuffer }]],
188190
'Frame',
189191
device
190192
);
@@ -204,19 +206,19 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => {
204206
[
205207
[
206208
sampler,
207-
woodDiffuseTexture.createView(),
209+
woodAlbedoTexture.createView(),
208210
spiralNormalTexture.createView(),
209211
spiralHeightTexture.createView(),
210212
],
211213
[
212214
sampler,
213-
woodDiffuseTexture.createView(),
215+
woodAlbedoTexture.createView(),
214216
toyboxNormalTexture.createView(),
215217
toyboxHeightTexture.createView(),
216218
],
217219
[
218220
sampler,
219-
brickwallDiffuseTexture.createView(),
221+
brickwallAlbedoTexture.createView(),
220222
brickwallNormalTexture.createView(),
221223
brickwallHeightTexture.createView(),
222224
],
@@ -250,9 +252,9 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => {
250252
}
251253

252254
// Change the model mapping type
253-
const getMappingType = (): number => {
255+
const getMode = (): number => {
254256
switch (settings['Bump Mode']) {
255-
case 'Diffuse Texture':
257+
case 'Albedo Texture':
256258
return 0;
257259
case 'Normal Texture':
258260
return 1;
@@ -285,7 +287,7 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => {
285287
};
286288

287289
gui.add(settings, 'Bump Mode', [
288-
'Diffuse Texture',
290+
'Albedo Texture',
289291
'Normal Texture',
290292
'Depth Texture',
291293
'Normal Map',
@@ -301,7 +303,7 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => {
301303
lightPosXController.setValue(1.7);
302304
lightPosYController.setValue(0.7);
303305
lightPosZController.setValue(-1.9);
304-
lightIntensityController.setValue(0.02);
306+
lightIntensityController.setValue(5.0);
305307
});
306308
const lightPosXController = lightFolder
307309
.add(settings, 'lightPosX', -5, 5)
@@ -313,53 +315,54 @@ const init: SampleInit = async ({ canvas, pageState, gui }) => {
313315
.add(settings, 'lightPosZ', -5, 5)
314316
.step(0.1);
315317
const lightIntensityController = lightFolder
316-
.add(settings, 'lightIntensity', 0.0, 0.1)
317-
.step(0.002);
318+
.add(settings, 'lightIntensity', 0.0, 10)
319+
.step(0.1);
318320
depthFolder.add(settings, 'depthScale', 0.0, 0.1).step(0.01);
319321
depthFolder.add(settings, 'depthLayers', 1, 32).step(1);
320322

321323
function frame() {
322324
if (!pageState.active) return;
323325

324-
// Write to normal map shader
326+
// Update spaceTransformsBuffer
325327
const viewMatrix = getViewMatrix();
326-
327-
const modelMatrix = getModelMatrix();
328-
328+
const worldViewMatrix = mat4.mul(viewMatrix, getModelMatrix());
329+
const worldViewProjMatrix = mat4.mul(projectionMatrix, worldViewMatrix);
329330
const matrices = new Float32Array([
330-
...projectionMatrix,
331-
...viewMatrix,
332-
...modelMatrix,
331+
...worldViewProjMatrix,
332+
...worldViewMatrix,
333333
]);
334334

335-
const mappingType = getMappingType();
336-
335+
// Update mapInfoBuffer
336+
const lightPosWS = vec3.create(
337+
settings.lightPosX,
338+
settings.lightPosY,
339+
settings.lightPosZ
340+
);
341+
const lightPosVS = vec3.transformMat4(lightPosWS, viewMatrix);
342+
const mode = getMode();
337343
device.queue.writeBuffer(
338-
uniformBuffer,
344+
spaceTransformsBuffer,
339345
0,
340346
matrices.buffer,
341347
matrices.byteOffset,
342348
matrices.byteLength
343349
);
344350

345-
device.queue.writeBuffer(
346-
mapMethodBuffer,
347-
0,
348-
new Uint32Array([mappingType])
349-
);
350-
351-
device.queue.writeBuffer(
352-
mapMethodBuffer,
353-
4,
354-
new Float32Array([
355-
settings.lightPosX,
356-
settings.lightPosY,
357-
settings.lightPosZ,
358-
settings.lightIntensity,
359-
settings.depthScale,
360-
settings.depthLayers,
361-
])
362-
);
351+
// struct MapInfo {
352+
// lightPosVS: vec3f,
353+
// mode: u32,
354+
// lightIntensity: f32,
355+
// depthScale: f32,
356+
// depthLayers: f32,
357+
// }
358+
mapInfoView.setFloat32(0, lightPosVS[0], true);
359+
mapInfoView.setFloat32(4, lightPosVS[1], true);
360+
mapInfoView.setFloat32(8, lightPosVS[2], true);
361+
mapInfoView.setUint32(12, mode, true);
362+
mapInfoView.setFloat32(16, settings.lightIntensity, true);
363+
mapInfoView.setFloat32(20, settings.depthScale, true);
364+
mapInfoView.setFloat32(24, settings.depthLayers, true);
365+
device.queue.writeBuffer(mapInfoBuffer, 0, mapInfoArray);
363366

364367
renderPassDescriptor.colorAttachments[0].view = context
365368
.getCurrentTexture()

0 commit comments

Comments
 (0)