mirror of
https://github.com/visgl/luma.gl.git
synced 2026-02-01 14:33:49 +00:00
feat(webgpu): Add two cubes example (#1558)
This commit is contained in:
parent
b923efb3c6
commit
352be62c8a
@ -45,36 +45,6 @@ fn main([[location(0)]] fragUV: vec2<f32>,
|
||||
}
|
||||
};
|
||||
|
||||
// const vertexBufferLayout = {
|
||||
// arrayStride: cubeVertexSize,
|
||||
// attributes: [
|
||||
// {
|
||||
// // position
|
||||
// shaderLocation: 0,
|
||||
// offset: cubePositionOffset,
|
||||
// format: 'float32x4',
|
||||
// },
|
||||
// {
|
||||
// // uv
|
||||
// shaderLocation: 1,
|
||||
// offset: cubeUVOffset,
|
||||
// format: 'float32x2',
|
||||
// },
|
||||
// ],
|
||||
// };
|
||||
|
||||
// const uniformBindGroup = device.handle.createBindGroup({
|
||||
// layout: pipeline.handle.getBindGroupLayout(0),
|
||||
// entries: [
|
||||
// {
|
||||
// binding: 0,
|
||||
// resource: {
|
||||
// buffer: uniformBuffer.handle,
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
|
||||
const UNIFORM_BUFFER_SIZE = 4 * 16; // 4x4 matrix
|
||||
|
||||
export async function init(canvas: HTMLCanvasElement, language: 'glsl' | 'wgsl') {
|
||||
@ -84,8 +54,8 @@ export async function init(canvas: HTMLCanvasElement, language: 'glsl' | 'wgsl')
|
||||
const positionBuffer = device.createBuffer({id: 'cube-positions', data: cubePositions});
|
||||
const uvBuffer = device.createBuffer({id: 'cube-uvs', data: cubeUVs});
|
||||
|
||||
|
||||
const uniformBuffer = device.createBuffer({
|
||||
id: 'uniforms',
|
||||
byteLength: UNIFORM_BUFFER_SIZE,
|
||||
// TODO - use API constants instead of WebGPU constants
|
||||
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
||||
@ -141,26 +111,3 @@ export async function init(canvas: HTMLCanvasElement, language: 'glsl' | 'wgsl')
|
||||
}
|
||||
|
||||
init(document.getElementById('canvas') as HTMLCanvasElement, 'wgsl');
|
||||
|
||||
|
||||
/*
|
||||
const projectionMatrix = mat4.create();
|
||||
mat4.perspective(projectionMatrix, );
|
||||
|
||||
function getTransformationMatrix() {
|
||||
const viewMatrix = mat4.create();
|
||||
mat4.translate(viewMatrix, viewMatrix, vec3.fromValues(0, 0, -4));
|
||||
const now = Date.now() / 1000;
|
||||
mat4.rotate(
|
||||
viewMatrix,
|
||||
viewMatrix,
|
||||
1,
|
||||
vec3.fromValues(Math.sin(now), Math.cos(now), 0)
|
||||
);
|
||||
|
||||
const modelViewProjectionMatrix = mat4.create();
|
||||
mat4.multiply(modelViewProjectionMatrix, projectionMatrix, viewMatrix);
|
||||
|
||||
return modelViewProjectionMatrix as Float32Array;
|
||||
}
|
||||
*/
|
||||
|
||||
141
examples/webgpu/two-cubes/app.ts
Normal file
141
examples/webgpu/two-cubes/app.ts
Normal file
@ -0,0 +1,141 @@
|
||||
import {AttributeBinding, RenderPipelineParameters} from '@luma.gl/api';
|
||||
import {Model, WebGPUDevice} from '@luma.gl/webgpu';
|
||||
import {Matrix4} from '@math.gl/core';
|
||||
|
||||
import {
|
||||
cubePositions,
|
||||
cubeUVs,
|
||||
cubeVertexCount
|
||||
} from './cube';
|
||||
|
||||
export const title = 'Two Cubes';
|
||||
export const description = 'Shows usage of multiple uniform buffers.';
|
||||
|
||||
/** Provide both GLSL and WGSL shaders */
|
||||
const SHADERS = {
|
||||
wgsl: {
|
||||
vertex: `
|
||||
struct Uniforms {
|
||||
modelViewProjectionMatrix : mat4x4<f32>;
|
||||
};
|
||||
[[binding(0), group(0)]] var<uniform> uniforms : Uniforms;
|
||||
|
||||
struct VertexOutput {
|
||||
[[builtin(position)]] Position : vec4<f32>;
|
||||
[[location(0)]] fragUV : vec2<f32>;
|
||||
[[location(1)]] fragPosition: vec4<f32>;
|
||||
};
|
||||
|
||||
[[stage(vertex)]]
|
||||
fn main([[location(0)]] position : vec4<f32>,
|
||||
[[location(1)]] uv : vec2<f32>) -> VertexOutput {
|
||||
var output : VertexOutput;
|
||||
output.Position = uniforms.modelViewProjectionMatrix * position;
|
||||
output.fragUV = uv;
|
||||
output.fragPosition = 0.5 * (position + vec4<f32>(1.0, 1.0, 1.0, 1.0));
|
||||
return output;
|
||||
}
|
||||
`,
|
||||
fragment: `
|
||||
[[stage(fragment)]]
|
||||
fn main([[location(0)]] fragUV: vec2<f32>,
|
||||
[[location(1)]] fragPosition: vec4<f32>) -> [[location(0)]] vec4<f32> {
|
||||
return fragPosition;
|
||||
}
|
||||
`
|
||||
}
|
||||
};
|
||||
|
||||
const UNIFORM_BUFFER_SIZE = 4 * 16; // 4x4 matrix
|
||||
|
||||
const CUBE_ATTRIBUTE_LAYOUTS: AttributeBinding[] = [
|
||||
{name: 'position', location: 0, accessor: {format: 'float32x4'}},
|
||||
{name: 'uv', location: 1, accessor: {format: 'float32x2'}}
|
||||
];
|
||||
|
||||
const CUBE_RENDER_PARAMETERS: RenderPipelineParameters = {
|
||||
// Enable depth testing so that the fragment closest to the camera
|
||||
// is rendered in front.
|
||||
depthWriteEnabled: true,
|
||||
depthCompare: 'less',
|
||||
depthFormat: 'depth24plus',
|
||||
|
||||
// Backface culling since the cube is solid piece of geometry.
|
||||
// Faces pointing away from the camera will be occluded by faces
|
||||
// pointing toward the camera.
|
||||
cullMode: 'back',
|
||||
};
|
||||
|
||||
export async function init(canvas: HTMLCanvasElement, language: 'glsl' | 'wgsl') {
|
||||
const device = await WebGPUDevice.create({canvas});
|
||||
|
||||
// Create a vertex buffer from the cube data.
|
||||
const positionBuffer = device.createBuffer({id: 'cube-positions', data: cubePositions});
|
||||
const uvBuffer = device.createBuffer({id: 'cube-uvs', data: cubeUVs});
|
||||
|
||||
const uniformBuffer1 = device.createBuffer({
|
||||
id: 'uniforms-1',
|
||||
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
||||
byteLength: UNIFORM_BUFFER_SIZE,
|
||||
});
|
||||
|
||||
const cubeModel1 = new Model(device, {
|
||||
id: 'cube',
|
||||
vs: SHADERS[language].vertex,
|
||||
fs: SHADERS[language].fragment,
|
||||
topology: 'triangle-list',
|
||||
attributeLayouts: CUBE_ATTRIBUTE_LAYOUTS,
|
||||
attributeBuffers: [positionBuffer, uvBuffer],
|
||||
bindings: [uniformBuffer1],
|
||||
vertexCount: cubeVertexCount,
|
||||
parameters: CUBE_RENDER_PARAMETERS
|
||||
});
|
||||
|
||||
const uniformBuffer2 = device.createBuffer({
|
||||
id: 'uniforms-1',
|
||||
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
||||
byteLength: UNIFORM_BUFFER_SIZE,
|
||||
});
|
||||
|
||||
const cubeModel2 = new Model(device, {
|
||||
id: 'cube',
|
||||
vs: SHADERS[language].vertex,
|
||||
fs: SHADERS[language].fragment,
|
||||
topology: 'triangle-list',
|
||||
attributeLayouts: CUBE_ATTRIBUTE_LAYOUTS,
|
||||
attributeBuffers: [positionBuffer, uvBuffer],
|
||||
bindings: [uniformBuffer2],
|
||||
vertexCount: cubeVertexCount,
|
||||
parameters: CUBE_RENDER_PARAMETERS
|
||||
});
|
||||
|
||||
const projectionMatrix = new Matrix4();
|
||||
const viewMatrix = new Matrix4();
|
||||
const modelViewProjectionMatrix = new Matrix4();
|
||||
|
||||
function frame() {
|
||||
const aspect = canvas.width / canvas.height;
|
||||
const now = Date.now() / 1000;
|
||||
|
||||
projectionMatrix.perspective({fov: (2 * Math.PI) / 5, aspect, near: 1, far: 100.0});
|
||||
|
||||
viewMatrix.identity().translate([-2, 0, -7]).rotateAxis(1, [Math.sin(now), Math.cos(now), 0]);
|
||||
modelViewProjectionMatrix.copy(viewMatrix).multiplyLeft(projectionMatrix);
|
||||
uniformBuffer1.write(new Float32Array(modelViewProjectionMatrix));
|
||||
|
||||
viewMatrix.identity().translate([2, 0, -7]).rotateAxis(1, [Math.cos(now), Math.sin(now), 0]);
|
||||
modelViewProjectionMatrix.copy(viewMatrix).multiplyLeft(projectionMatrix);
|
||||
uniformBuffer2.write(new Float32Array(modelViewProjectionMatrix));
|
||||
|
||||
device.beginRenderPass();
|
||||
cubeModel1.draw();
|
||||
cubeModel2.draw();
|
||||
device.submit();
|
||||
|
||||
requestAnimationFrame(frame);
|
||||
}
|
||||
|
||||
requestAnimationFrame(frame);
|
||||
}
|
||||
|
||||
init(document.getElementById('canvas') as HTMLCanvasElement, 'wgsl');
|
||||
142
examples/webgpu/two-cubes/cube.ts
Normal file
142
examples/webgpu/two-cubes/cube.ts
Normal file
@ -0,0 +1,142 @@
|
||||
export const cubeVertexSize = 4 * 10; // Byte size of one cube vertex.
|
||||
export const cubePositionOffset = 0;
|
||||
export const cubeColorOffset = 4 * 4; // Byte offset of cube vertex color attribute.
|
||||
export const cubeUVOffset = 4 * 8;
|
||||
export const cubeVertexCount = 36;
|
||||
|
||||
// float4 position
|
||||
// prettier-ignore
|
||||
export const cubePositions = new Float32Array([
|
||||
1, -1, 1, 1,
|
||||
-1, -1, 1, 1,
|
||||
-1, -1, -1, 1,
|
||||
1, -1, -1, 1,
|
||||
1, -1, 1, 1,
|
||||
-1, -1, -1, 1,
|
||||
|
||||
1, 1, 1, 1,
|
||||
1, -1, 1, 1,
|
||||
1, -1, -1, 1,
|
||||
1, 1, -1, 1,
|
||||
1, 1, 1, 1,
|
||||
1, -1, -1, 1,
|
||||
|
||||
-1, 1, 1, 1,
|
||||
1, 1, 1, 1,
|
||||
1, 1, -1, 1,
|
||||
-1, 1, -1, 1,
|
||||
-1, 1, 1, 1,
|
||||
1, 1, -1, 1,
|
||||
|
||||
-1, -1, 1, 1,
|
||||
-1, 1, 1, 1,
|
||||
-1, 1, -1, 1,
|
||||
-1, -1, -1, 1,
|
||||
-1, -1, 1, 1,
|
||||
-1, 1, -1, 1,
|
||||
|
||||
1, 1, 1, 1,
|
||||
-1, 1, 1, 1,
|
||||
-1, -1, 1, 1,
|
||||
-1, -1, 1, 1,
|
||||
1, -1, 1, 1,
|
||||
1, 1, 1, 1,
|
||||
|
||||
1, -1, -1, 1,
|
||||
-1, -1, -1, 1,
|
||||
-1, 1, -1, 1,
|
||||
1, 1, -1, 1,
|
||||
1, -1, -1, 1,
|
||||
-1, 1, -1, 1,
|
||||
]);
|
||||
|
||||
// float2 uv,
|
||||
// prettier-ignore
|
||||
export const cubeUVs = new Float32Array([
|
||||
1, 1,
|
||||
0, 1,
|
||||
0, 0,
|
||||
1, 0,
|
||||
1, 1,
|
||||
0, 0,
|
||||
|
||||
1, 1,
|
||||
0, 1,
|
||||
0, 0,
|
||||
1, 0,
|
||||
1, 1,
|
||||
0, 0,
|
||||
|
||||
1, 1,
|
||||
0, 1,
|
||||
0, 0,
|
||||
1, 0,
|
||||
1, 1,
|
||||
0, 0,
|
||||
|
||||
1, 1,
|
||||
0, 1,
|
||||
0, 0,
|
||||
1, 0,
|
||||
1, 1,
|
||||
0, 0,
|
||||
|
||||
1, 1,
|
||||
0, 1,
|
||||
0, 0,
|
||||
0, 0,
|
||||
1, 0,
|
||||
1, 1,
|
||||
|
||||
1, 1,
|
||||
0, 1,
|
||||
0, 0,
|
||||
1, 0,
|
||||
1, 1,
|
||||
0, 0,
|
||||
]);
|
||||
|
||||
export const cubeColors = new Float32Array([
|
||||
// float4 position, float4 color, float2 uv,
|
||||
1, 0, 1, 1,
|
||||
0, 0, 1, 1,
|
||||
0, 0, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 0, 1, 1,
|
||||
0, 0, 0, 1,
|
||||
|
||||
1, 1, 1, 1,
|
||||
1, 0, 1, 1,
|
||||
1, 0, 0, 1,
|
||||
1, 1, 0, 1,
|
||||
1, 1, 1, 1,
|
||||
1, 0, 0, 1,
|
||||
|
||||
0, 1, 1, 1,
|
||||
1, 1, 1, 1,
|
||||
1, 1, 0, 1,
|
||||
0, 1, 0, 1,
|
||||
0, 1, 1, 1,
|
||||
1, 1, 0, 1,
|
||||
|
||||
0, 0, 1, 1,
|
||||
0, 1, 1, 1,
|
||||
0, 1, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
0, 0, 1, 1,
|
||||
0, 1, 0, 1,
|
||||
|
||||
1, 1, 1, 1,
|
||||
0, 1, 1, 1,
|
||||
0, 0, 1, 1,
|
||||
0, 0, 1, 1,
|
||||
1, 0, 1, 1,
|
||||
1, 1, 1, 1,
|
||||
|
||||
1, 0, 0, 1,
|
||||
0, 0, 0, 1,
|
||||
0, 1, 0, 1,
|
||||
1, 1, 0, 1,
|
||||
1, 0, 0, 1,
|
||||
0, 1, 0, 1,
|
||||
]);
|
||||
7
examples/webgpu/two-cubes/index.html
Normal file
7
examples/webgpu/two-cubes/index.html
Normal file
@ -0,0 +1,7 @@
|
||||
<!doctype html>
|
||||
<script type="module">
|
||||
import './app.ts';
|
||||
</script>
|
||||
<body>
|
||||
<canvas id="canvas"></canvas>
|
||||
</body>
|
||||
20
examples/webgpu/two-cubes/package.json
Normal file
20
examples/webgpu/two-cubes/package.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "luma.gl-examples-webgpu-two-cubes",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"serve": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@luma.gl/engine": "8.6.0-alpha.5",
|
||||
"@luma.gl/shadertools": "8.6.0-alpha.5",
|
||||
"@luma.gl/webgpu": "8.6.0-alpha.5",
|
||||
"@math.gl/core": "^3.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^4.3.2",
|
||||
"vite": "^2.6.4"
|
||||
}
|
||||
}
|
||||
18
examples/webgpu/two-cubes/vite.config.ts
Normal file
18
examples/webgpu/two-cubes/vite.config.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import fs from 'fs/promises';
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
/** @see https://vitejs.dev/config/ */
|
||||
export default defineConfig(async () => ({
|
||||
resolve: {alias: await getAliases('@luma.gl', `${__dirname}/../../..`)},
|
||||
server: {open: true}
|
||||
}));
|
||||
|
||||
/** Run against local source */
|
||||
const getAliases = async (frameworkName, frameworkRootDir) => {
|
||||
const modules = await fs.readdir(`${frameworkRootDir}/modules`)
|
||||
const aliases = {}
|
||||
for (const module of modules) {
|
||||
aliases[`${frameworkName}/${module}`] = `${frameworkRootDir}/modules/${module}/src`
|
||||
}
|
||||
return aliases
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user