From 208b02653037a14b4e43ceae669727389ce0f217 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 25 May 2024 00:50:53 +0300 Subject: [PATCH 1/6] instancing --- prismarine-viewer/examples/Cube.vert.wgsl | 6 +- .../examples/webglRendererWorker.ts | 593 ------------------ .../examples/webgpuRendererWorker.ts | 21 +- 3 files changed, 18 insertions(+), 602 deletions(-) delete mode 100644 prismarine-viewer/examples/webglRendererWorker.ts diff --git a/prismarine-viewer/examples/Cube.vert.wgsl b/prismarine-viewer/examples/Cube.vert.wgsl index a3b59c62..bce33581 100644 --- a/prismarine-viewer/examples/Cube.vert.wgsl +++ b/prismarine-viewer/examples/Cube.vert.wgsl @@ -16,11 +16,11 @@ struct VertexOutput { fn main( //@builtin(instance_index) instanceIdx : u32, @location(0) position : vec4f, - @location(1) uv : vec2f - //@location(2) ModelMatrix : mat4x4f, + @location(1) uv : vec2f, + @location(2) ModelMatrix : vec3f, ) -> VertexOutput { var output : VertexOutput; - output.Position = uniforms.modelViewProjectionMatrix * position; + output.Position = uniforms.modelViewProjectionMatrix * (position +vec4f(ModelMatrix, 0.0)); //output.Position = uniforms.modelViewProjectionMatrix[instanceIdx] * position; output.fragUV = uv; output.fragPosition = 0.5 * (position + vec4(1.0, 1.0, 1.0, 1.0)); diff --git a/prismarine-viewer/examples/webglRendererWorker.ts b/prismarine-viewer/examples/webglRendererWorker.ts deleted file mode 100644 index 9f59ba59..00000000 --- a/prismarine-viewer/examples/webglRendererWorker.ts +++ /dev/null @@ -1,593 +0,0 @@ -import * as THREE from 'three' - -//@ts-ignore -import VertShader from './_VertexShader.vert' -//@ts-ignore -import FragShader from './_FragmentShader.frag' -import { BlockFaceType, BlockType } from './shared' -import * as tweenJs from '@tweenjs/tween.js' - -let allSides = [] as ([number, number, number, BlockFaceType] | undefined)[] -let allSidesAdded = 0 -let needsSidesUpdate = false - -let chunksArrIndexes = {} -let freeArrayIndexes = [] as [number, number][] -let rendering = true -let sidePositions -let updateCubes: (startIndex: any, forceUpdate?) => void -let lastNotUpdatedIndex -let lastNotUpdatedArrSize -let animationTick = 0; - -const updateCubesWhenAvailable = (pos) => { - if (updateCubes) { - updateCubes(pos) - } else { - setTimeout(updateCubesWhenAvailable, 100) - } -} - -const camera = new THREE.PerspectiveCamera(75, 1 / 1, 0.1, 1000) - -let renderedFrames = 0 -setInterval(() => { - // console.log('FPS:', renderedFrames) - postMessage({ type: 'fps', fps: renderedFrames }) - renderedFrames = 0 -}, 1000) - -const updateSize = (width, height) => { - camera.aspect = width / height - camera.updateProjectionMatrix() -} - - -export const initWebglRenderer = async (canvas: HTMLCanvasElement, imageBlob: ImageBitmapSource, isPlayground: boolean, FragShaderOverride?) => { - // isPlayground = false - // blockStates = blockStatesJson - const textureBitmap = await createImageBitmap(imageBlob) - const textureWidth = textureBitmap.width - const textureHeight = textureBitmap.height - - const gl = canvas.getContext('webgl2')! - - const program = createProgram(gl, VertShader, FragShaderOverride || FragShader) - - let CubeMesh = new Float32Array([ - -0.5, -0.5, -0.5, 0.0, 0.0, 0.0, // Bottom-let - 0.5, -0.5, -0.5, 1.0, 0.0, 0.0, // bottom-right - 0.5, 0.5, -0.5, 1.0, 1.0, 0.0, // top-right - 0.5, 0.5, -0.5, 1.0, 1.0, 0.0, // top-right - -0.5, 0.5, -0.5, 0.0, 1.0, 0.0, // top-let - -0.5, -0.5, -0.5, 0.0, 0.0, 0.0, // bottom-let - // ront ace - -0.5, -0.5, 0.5, 0.0, 0.0, 1.0, // bottom-let - 0.5, 0.5, 0.5, 1.0, 1.0, 1.0, // top-right - 0.5, -0.5, 0.5, 1.0, 0.0, 1.0, // bottom-right - 0.5, 0.5, 0.5, 1.0, 1.0, 1.0,// top-right - -0.5, -0.5, 0.5, 0.0, 0.0, 1.0,// bottom-let - -0.5, 0.5, 0.5, 0.0, 1.0, 1.0,// top-let - // Let ace - -0.5, 0.5, 0.5, 1.0, 0.0, 2.0,// top-right - -0.5, -0.5, -0.5, 0.0, 1.0, 2.0,// bottom-let - -0.5, 0.5, -0.5, 1.0, 1.0, 2.0,// top-let - -0.5, -0.5, -0.5, 0.0, 1.0, 2.0,// bottom-let - -0.5, 0.5, 0.5, 1.0, 0.0, 2.0, // top-right - -0.5, -0.5, 0.5, 0.0, 0.0, 2.0,// bottom-right - // Right ace - 0.5, 0.5, 0.5, 1.0, 0.0, 3.0,// top-let - 0.5, 0.5, -0.5, 1.0, 1.0, 3.0,// top-right - 0.5, -0.5, -0.5, 0.0, 1.0, 3.0,// bottom-right - 0.5, -0.5, -0.5, 0.0, 1.0, 3.0,// bottom-right - 0.5, -0.5, 0.5, 0.0, 0.0, 3.0,// bottom-let - 0.5, 0.5, 0.5, 1.0, 0.0, 3.0, // top-let - // Bottom ace - -0.5, -0.5, -0.5, 0.0, 1.0, 4.0,// top-right - 0.5, -0.5, 0.5, 1.0, 0.0, 4.0,// bottom-let - 0.5, -0.5, -0.5, 1.0, 1.0, 4.0,// top-let - 0.5, -0.5, 0.5, 1.0, 0.0, 4.0, // bottom-let - -0.5, -0.5, -0.5, 0.0, 1.0, 4.0, // top-right - -0.5, -0.5, 0.5, 0.0, 0.0, 4.0, // bottom-right - // Top ace - -0.5, 0.5, -0.5, 0.0, 1.0, 5.0,// top-let - 0.5, 0.5, -0.5, 1.0, 1.0, 5.0,// top-right - 0.5, 0.5, 0.5, 1.0, 0.0, 5.0,// bottom-right - 0.5, 0.5, 0.5, 1.0, 0.0, 5.0,// bottom-right - -0.5, 0.5, 0.5, 0.0, 0.0, 5.0,// bottom-let - -0.5, 0.5, -0.5, 0.0, 1.0, 5.0// top-let - ]) - - let SideMesh = new Float32Array([ - -0.5, -0.5, -0.5, 0.0, 0.0, // Bottom-let - 0.5, -0.5, -0.5, 1.0, 0.0, // bottom-right - -0.5, 0.5, -0.5, 0.0, 1.0, // top-let - 0.5, 0.5, -0.5, 1.0, 1.0, // top-right - // 0.5, 0.5, -0.5, 1.0, 1.0, // top-right - // -0.5, -0.5, -0.5, 0.0, 0.0, // bottom-let - // ront ace - ]) - - - - let NumberOfCube = isPlayground ? 10_000 : 16_000_000 - - sidePositions = new Float32Array(NumberOfCube * 3 * 6) - let sideTextureIndices = new Float32Array(NumberOfCube * 1 * 6); - let sideIndexes = new Float32Array(NumberOfCube * 1 * 6); - let sideBiomeColor = new Float32Array(NumberOfCube * 3 * 6); - - - // write random coordinates to cube positions xyz ten cubes; - if (isPlayground) { - for (let i = 0; i < NumberOfCube * 18; i += 18) { - - sidePositions[i] = Math.floor(Math.random() * 1000) - 500; - sidePositions[i + 1] = Math.floor(Math.random() * 1000) - 500; - sidePositions[i + 2] = Math.floor(Math.random() * 100) - 100; - - sideBiomeColor[i] = (Math.random()); - sideBiomeColor[i + 1] = (Math.random()); - sideBiomeColor[i + 2] = (Math.random()); - for (let j = 1; j <= 6; j++) { - - if (j != 6) { - sidePositions[j * 3 + i] = sidePositions[i] - sidePositions[j * 3 + i + 1] = sidePositions[i + 1] - sidePositions[j * 3 + i + 2] = sidePositions[i + 2] - - sideBiomeColor[j * 3 + i] = sideBiomeColor[i] - sideBiomeColor[j * 3 + i + 1] = sideBiomeColor[i + 1] - sideBiomeColor[j * 3 + i + 2] = sideBiomeColor[i + 2] - } - - sideIndexes[i / 3 + j - 1] = j - 1; - sideTextureIndices[i / 3 + j - 1] = Math.floor(Math.random() * 800); - //sideTextureIndices[i / 3 + j - 1] = 1; - } - - } - - } - let VAO = gl.createVertexArray(); - - - let instanceVBO = gl.createBuffer(); - let instanceTextureID = gl.createBuffer(); - let instanceBiomeColor = gl.createBuffer(); - let instanceCubeSide = gl.createBuffer(); - - gl.bindBuffer(gl.ARRAY_BUFFER, instanceVBO); - gl.bufferData(gl.ARRAY_BUFFER, sidePositions, gl.DYNAMIC_DRAW); - gl.bindBuffer(gl.ARRAY_BUFFER, null); - - gl.bindBuffer(gl.ARRAY_BUFFER, instanceTextureID); - gl.bufferData(gl.ARRAY_BUFFER, sideTextureIndices, gl.DYNAMIC_DRAW); - gl.bindBuffer(gl.ARRAY_BUFFER, null); - - gl.bindBuffer(gl.ARRAY_BUFFER, instanceBiomeColor); - gl.bufferData(gl.ARRAY_BUFFER, sideBiomeColor, gl.DYNAMIC_DRAW); - gl.bindBuffer(gl.ARRAY_BUFFER, null); - - gl.bindBuffer(gl.ARRAY_BUFFER, instanceCubeSide); - gl.bufferData(gl.ARRAY_BUFFER, sideIndexes, gl.DYNAMIC_DRAW); - gl.bindBuffer(gl.ARRAY_BUFFER, null); - VAO = gl.createVertexArray(); - let VBO = gl.createBuffer(); - // let VBO_sides = gl.createBuffer(); - //EBO = gl.createBuffer(); - - gl.bindVertexArray(VAO); - gl.bindBuffer(gl.ARRAY_BUFFER, VBO) - // gl.bindBuffer(gl.ARRAY_BUFFER, VBO_sides) - gl.bufferData(gl.ARRAY_BUFFER, SideMesh, gl.STATIC_DRAW) - - gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 5 * 4, 0) - gl.enableVertexAttribArray(0) - - gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 5 * 4, 3 * 4) - gl.enableVertexAttribArray(1) - - gl.enableVertexAttribArray(2); - gl.bindBuffer(gl.ARRAY_BUFFER, instanceCubeSide); - gl.vertexAttribPointer(2, 1, gl.FLOAT, false, 4, 0); - gl.bindBuffer(gl.ARRAY_BUFFER, null); - gl.vertexAttribDivisor(2, 1); - - gl.enableVertexAttribArray(3); - gl.bindBuffer(gl.ARRAY_BUFFER, instanceVBO); - gl.vertexAttribPointer(3, 3, gl.FLOAT, false, 3 * 4, 0); - gl.bindBuffer(gl.ARRAY_BUFFER, null); - gl.vertexAttribDivisor(3, 1); - - gl.enableVertexAttribArray(4); - gl.bindBuffer(gl.ARRAY_BUFFER, instanceTextureID); - gl.vertexAttribPointer(4, 1, gl.FLOAT, false, 4 * 1, 0); - gl.bindBuffer(gl.ARRAY_BUFFER, null); - gl.vertexAttribDivisor(4, 1); - - gl.enableVertexAttribArray(6); - gl.bindBuffer(gl.ARRAY_BUFFER, instanceBiomeColor); - gl.vertexAttribPointer(6, 3, gl.FLOAT, false, 3 * 4, 0); - gl.bindBuffer(gl.ARRAY_BUFFER, null); - gl.vertexAttribDivisor(6, 1); - - updateCubes = (startIndex, forceUpdate) => { - // up2 - const newSides = allSides.slice(startIndex, lastNotUpdatedArrSize ? startIndex + lastNotUpdatedArrSize : undefined) - newSides.sort((a, b) => { - if (!a || !b) return 0 - const getScore = (b: BlockFaceType) => b.isTransparent ? 1 : 0 - return getScore(a[3]) - getScore(b[3]) - }) - globalThis.allSidesSize = allSides.length - sidePositions = new Float32Array(newSides.length * 3) - sideTextureIndices = new Float32Array(newSides.length * 1); - sideIndexes = new Float32Array(newSides.length * 1); - sideBiomeColor = new Float32Array(newSides.length * 3); - for (let i = 0; i < newSides.length * 3; i += 3) { - const newSide = newSides[i / 3]; - if (!newSide) continue - sidePositions[i] = newSide[0] - sidePositions[i + 1] = newSide[1] - sidePositions[i + 2] = newSide[2] - const block = newSide[3] as BlockFaceType - if (block.tint) { - const [r, g, b] = block.tint - sideBiomeColor[i] = r - sideBiomeColor[i + 1] = g - sideBiomeColor[i + 2] = b - } else { - sideBiomeColor[i] = 1 - sideBiomeColor[i + 1] = 1 - sideBiomeColor[i + 2] = 1 - } - sideTextureIndices[i / 3] = block.textureIndex - sideIndexes[i / 3] = block.face - } - - - // startIndex = 0 // TODO! - console.log('startIndex', startIndex, sidePositions.length, allSides.length) - const prepareBuffersUpdate = allSides.length > NumberOfCube || globalThis.testUpdate - globalThis.testUpdate = false - if (prepareBuffersUpdate) { - NumberOfCube += 1_000_000 - updateCubes(0, true) - return - } - globalThis.NumberOfCube = NumberOfCube - - const supplyData = (data, step) => { - if (forceUpdate) { - globalThis.updatedBufferSize = NumberOfCube - gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(NumberOfCube * step), gl.STATIC_DRAW); - } - gl.bufferSubData(gl.ARRAY_BUFFER, startIndex * 4 * step, data); // update buffer content - const error = gl.getError() - if (error) throw new Error("SUBDATA ERROR") - gl.bindBuffer(gl.ARRAY_BUFFER, null); - } - - gl.bindBuffer(gl.ARRAY_BUFFER, instanceVBO); - supplyData(sidePositions, 3) - - gl.bindBuffer(gl.ARRAY_BUFFER, instanceTextureID); - supplyData(sideTextureIndices, 1) - - gl.bindBuffer(gl.ARRAY_BUFFER, instanceBiomeColor); - supplyData(sideBiomeColor, 3) - - gl.bindBuffer(gl.ARRAY_BUFFER, instanceCubeSide); - supplyData(sideIndexes, 1) - - allSidesAdded = allSides.length - needsSidesUpdate = true - lastNotUpdatedArrSize = undefined - } - - globalThis.updateCubes = updateCubes - globalThis.resetHalfScene = () => { - for (let i = 0; i < allSides.length / 2; i++) { - allSides[i] = undefined - } - lastNotUpdatedIndex = 0 - lastNotUpdatedArrSize = allSides.length / 2 - updateCubes(0) - } - const cleanupFirstChunks = () => { - allSides = [] - gl.bindBuffer(gl.ARRAY_BUFFER, instanceVBO); - // empty the buffer - gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(NumberOfCube * 3), gl.STATIC_DRAW); // todo - gl.bindBuffer(gl.ARRAY_BUFFER, null); - - gl.bindBuffer(gl.ARRAY_BUFFER, instanceTextureID); - gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(NumberOfCube * 3), gl.STATIC_DRAW); // todo - // gl.bufferSubData(gl.ARRAY_BUFFER, startIndex * 4, cubeTextureIndices); // update buffer content - gl.bindBuffer(gl.ARRAY_BUFFER, null); - } - - fullReset = () => { - cleanupFirstChunks() - lastNotUpdatedIndex = undefined - lastNotUpdatedArrSize = undefined - } - - - - //gl.bindBuffer(gl.ARRAY_BUFFER, null); - //gl.bindVertexArray(null) - - // viewer.world.updateTexturesData() - // await new Promise(resolve => { - // // console.log('viewer.world.material.map!.image', viewer.world.material.map!.image) - // // viewer.world.material.map!.image.onload = () => { - // // console.log(this.material.map!.image) - // // resolve() - // // } - // viewer.world.renderUpdateEmitter.once('blockStatesDownloaded', resolve) - // }) - // const names = Object.keys(viewer.world.downloadedBlockStatesData) - - let texture1 = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, texture1); - - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method) - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); - - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, textureWidth, textureHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, textureBitmap); - - gl.useProgram(program) - - gl.uniform1i(gl.getUniformLocation(program, "texture1"), 0); - gl.uniform1i(gl.getUniformLocation(program, "texture2"), 1); - - - gl.enable(gl.DEPTH_TEST) - gl.frontFace(gl.CCW) - gl.enable(gl.CULL_FACE) - gl.enable(gl.BLEND) - gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); - - - //gl.generateMipmap() - //gl.enable(gl) - //gl.clearColor(0, 0, 0, 1) - //gl.clear(gl.COLOR_BUFFER_BIT) - camera.up = new THREE.Vector3(0, 1, 0) - - let ViewUniform = gl.getUniformLocation(program, "view") - let ProjectionUniform = gl.getUniformLocation(program, "projection") - let TickUniform = gl.getUniformLocation(program, "tick") - - gl.cullFace(gl.FRONT) - - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, texture1); - - gl.bindVertexArray(VAO) - gl.useProgram(program) - updateSize(gl.canvas.width, gl.canvas.height) - const renderLoop = (performance) => { - requestAnimationFrame(renderLoop) - if (!rendering && !needsSidesUpdate) return - // gl.canvas.width = window.innerWidth * window.devicePixelRatio - // gl.canvas.height = window.innerHeight * window.devicePixelRatio - if (newWidth || newHeight) { - gl.canvas.width = newWidth ?? gl.canvas.width - gl.canvas.height = newHeight ?? gl.canvas.height - newWidth = undefined - newHeight = undefined - updateSize(gl.canvas.width, gl.canvas.height) - - gl.viewport(0, 0, gl.canvas.width, gl.canvas.height) - } - - - gl.clearColor(0.6784313725490196, 0.8470588235294118, 0.9019607843137255, 1); - gl.clear(gl.COLOR_BUFFER_BIT) - gl.clear(gl.DEPTH_BUFFER_BIT) - - - tweenJs.update() - camera.updateMatrix() - gl.uniformMatrix4fv(ViewUniform, false, camera.matrix.invert().elements); - gl.uniformMatrix4fv(ProjectionUniform, false, camera.projectionMatrix.elements); - gl.uniform1i(TickUniform, animationTick); - - if (!globalThis.stopRendering) { - gl.drawArraysInstanced(gl.TRIANGLE_STRIP, 0, 4, (isPlayground ? NumberOfCube * 6 : allSidesAdded)); - needsSidesUpdate = false - } - - renderedFrames++ - } - requestAnimationFrame(renderLoop) - - // gl.deleteVertexArray(VAO); - // gl.deleteBuffer(VBO) - // gl.deleteBuffer(EBO) - // gl.deleteProgram(program) - - return canvas -} - -let fullReset - -const createProgram = (gl: WebGL2RenderingContext, vertexShader: string, fragmentShader: string) => { - const createShader = (gl: WebGL2RenderingContext, type: number, source: string) => { - const shaderName = type === gl.VERTEX_SHADER ? 'vertex' : 'fragment' - const shader = gl.createShader(type)! - gl.shaderSource(shader, source) - gl.compileShader(shader) - - const success = gl.getShaderParameter(shader, gl.COMPILE_STATUS) - if (!success) { - const info = gl.getShaderInfoLog(shader) - gl.deleteShader(shader) - throw new Error(`Shader ${shaderName} compile error: ` + info) - } - return shader - } - - - - const program = gl.createProgram()! - gl.attachShader(program, createShader(gl, gl.VERTEX_SHADER, vertexShader)!) - gl.attachShader(program, createShader(gl, gl.FRAGMENT_SHADER, fragmentShader)!) - gl.linkProgram(program) - const linkSuccess = gl.getProgramParameter(program, gl.LINK_STATUS) - if (!linkSuccess) { - const info = gl.getProgramInfoLog(program) - gl.deleteProgram(program) - throw new Error('Program link error: ' + info) - } - return program -} - -let started = false -let newWidth: number | undefined -let newHeight: number | undefined -let autoTickUpdate = undefined as number | undefined -onmessage = function (e) { - if (!started) { - started = true - initWebglRenderer(e.data.canvas, e.data.imageBlob, e.data.isPlayground, e.data.FragShaderOverride) - return - } - if (e.data.type === 'startRender') { - rendering = true - } - if (e.data.type === 'stopRender') { - rendering = false - } - if (e.data.type === 'resize') { - newWidth = e.data.newWidth - newHeight = e.data.newHeight - } - if (e.data.type === 'addBlocksSection') { - const currentLength = allSides.length; - // in: object - name, out: [x, y, z, name] - const newData = Object.entries(e.data.data.blocks).flatMap(([key, value]) => { - const [x, y, z] = key.split(',').map(Number) - const block = value as BlockType - return block.sides.map((side) => { - return [x, y, z, side] as [number, number, number, BlockFaceType] - }) - }) - // find freeIndexes if possible - const freeArea = freeArrayIndexes.find(([startIndex, endIndex]) => endIndex - startIndex >= newData.length) - if (freeArea) { - const [startIndex, endIndex] = freeArea - allSides.splice(startIndex, newData.length, ...newData) - lastNotUpdatedIndex ??= startIndex - const freeAreaIndex = freeArrayIndexes.indexOf(freeArea) - freeArrayIndexes[freeAreaIndex] = [startIndex + newData.length, endIndex] - if (freeArrayIndexes[freeAreaIndex][0] >= freeArrayIndexes[freeAreaIndex][1]) { - freeArrayIndexes.splice(freeAreaIndex, 1) - // todo merge - } - lastNotUpdatedArrSize = newData.length - console.log('using free area', freeArea) - } - - chunksArrIndexes[e.data.key] = [currentLength, currentLength + newData.length] - allSides.push(...newData) - lastNotUpdatedIndex ??= currentLength - // updateCubes?.(currentLength) - } - if (e.data.type === 'addBlocksSectionDone') { - updateCubesWhenAvailable(lastNotUpdatedIndex) - lastNotUpdatedIndex = undefined - lastNotUpdatedArrSize = undefined - } - if (e.data.type === 'removeBlocksSection') { - // fill data with 0 - const [startIndex, endIndex] = chunksArrIndexes[e.data.key] - for (let i = startIndex; i < endIndex; i++) { - allSides[i] = undefined - } - lastNotUpdatedArrSize = endIndex - startIndex - updateCubes(startIndex) - - // freeArrayIndexes.push([startIndex, endIndex]) - - // // merge freeArrayIndexes TODO - // if (freeArrayIndexes.at(-1)[0] === freeArrayIndexes.at(-2)?.[1]) { - // const [startIndex, endIndex] = freeArrayIndexes.pop()! - // const [startIndex2, endIndex2] = freeArrayIndexes.pop()! - // freeArrayIndexes.push([startIndex2, endIndex]) - // } - } - if (e.data.type === 'camera') { - camera.rotation.set(e.data.camera.rotation.x, e.data.camera.rotation.y, e.data.camera.rotation.z, 'ZYX') - // camera.position.set(e.data.camera.position.x, e.data.camera.position.y, e.data.camera.position.z) - if (camera.position.x === 0 && camera.position.y === 0 && camera.position.z === 0) { - // initial camera position - camera.position.set(e.data.camera.position.x, e.data.camera.position.y, e.data.camera.position.z) - } else { - new tweenJs.Tween(camera.position).to({ x: e.data.camera.position.x, y: e.data.camera.position.y, z: e.data.camera.position.z }, 50).start() - } - } - if (e.data.type === 'animationTick') { - if (e.data.frames <= 0) { - autoTickUpdate = undefined - animationTick = 0 - return - } - if (e.data.tick === -1) { - autoTickUpdate = e.data.frames - } else { - autoTickUpdate = undefined - animationTick = e.data.tick % 20 // todo update automatically in worker - } - } - if (e.data.type === 'fullReset') { - fullReset() - } - if (e.data.type === 'exportData') { - const exported = exportData(); - postMessage({ type: 'exportData', data: exported }, undefined, [exported.sides.buffer]) - } - if (e.data.type === 'loadFixture') { - // allSides = e.data.json.map(([x, y, z, face, textureIndex]) => { - // return [x, y, z, { face, textureIndex }] as [number, number, number, BlockFaceType] - // }) - const dataSize = e.data.json.length / 5 - for (let i = 0; i < e.data.json.length; i += 5) { - allSides.push([e.data.json[i], e.data.json[i + 1], e.data.json[i + 2], { face: e.data.json[i + 3], textureIndex: e.data.json[i + 4] }]) - } - updateCubesWhenAvailable(0) - } -} - -globalThis.testDuplicates = () => { - const duplicates = allSides.filter((value, index, self) => self.indexOf(value) !== index) - console.log('duplicates', duplicates) -} - -const exportData = () => { - // Calculate the total length of the final array - const totalLength = allSides.length * 5; - - // Create a new Int16Array with the total length - const flatData = new Int16Array(totalLength); - - // Fill the flatData array - for (let i = 0; i < allSides.length; i++) { - const [x, y, z, side] = allSides[i]; - flatData.set([x, y, z, side.face, side.textureIndex], i * 5); - } - - return { sides: flatData }; -} - -setInterval(() => { - if (autoTickUpdate) { - animationTick = (animationTick + 1) % autoTickUpdate; - } -}, 1000 / 20) diff --git a/prismarine-viewer/examples/webgpuRendererWorker.ts b/prismarine-viewer/examples/webgpuRendererWorker.ts index 384a071e..6bd2bc4c 100644 --- a/prismarine-viewer/examples/webgpuRendererWorker.ts +++ b/prismarine-viewer/examples/webgpuRendererWorker.ts @@ -96,7 +96,16 @@ class WebgpuRendererWorker { this.verticesBuffer = verticesBuffer new Float32Array(verticesBuffer.getMappedRange()).set(cubeVertexArray) verticesBuffer.unmap() - let ModelMatrix = new THREE.Matrix4() + + let NumberOfCubes = 3 + //Todo: make this dynamic + const ModelMatrix = new Float32Array([ + 0, 1, 0, + 1, 0, 0, + 0, 0, 1 + ]) + + const InstancedModelBuffer = device.createBuffer({ size: 4 * 4 * 4, @@ -104,7 +113,7 @@ class WebgpuRendererWorker { mappedAtCreation: true, }) this.InstancedModelBuffer = InstancedModelBuffer - new Float32Array(InstancedModelBuffer.getMappedRange()).set(ModelMatrix.elements) + new Float32Array(InstancedModelBuffer.getMappedRange()).set(ModelMatrix) InstancedModelBuffer.unmap() //device.StepM const vertexCode = VertShader @@ -135,13 +144,13 @@ class WebgpuRendererWorker { ], }, { - arrayStride: 4 * 4 * 4, + arrayStride: 3 * 4, attributes: [ { // ModelMatrix shaderLocation: 2, offset: 0, - format: 'float32x4', + format: 'float32x3', } ], stepMode: 'instance', @@ -300,7 +309,7 @@ class WebgpuRendererWorker { passEncoder.setBindGroup(0, uniformBindGroup) passEncoder.setVertexBuffer(0, verticesBuffer) passEncoder.setVertexBuffer(1, this.InstancedModelBuffer) - passEncoder.draw(cubeVertexCount, 1) + passEncoder.draw(cubeVertexCount, 3) passEncoder.end() device.queue.submit([commandEncoder.finish()]) @@ -337,7 +346,7 @@ export const workerProxyType = createWorkerProxy({ newHeight = newHeight updateSize(newWidth, newHeight) }, - addBlocksSection (data, key) { + addBlocksSection (data: { blocks: Record }, key: string) { const currentLength = allSides.length // in: object - name, out: [x, y, z, name] const newData = Object.entries(data.blocks).flatMap(([key, value]) => { From bbe2a6bef1276a785d111a74a8761876cbb3cb0f Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 25 May 2024 01:32:19 +0300 Subject: [PATCH 2/6] blocks adding --- prismarine-viewer/examples/CubeDef.ts | 50 ++++++++++++++ prismarine-viewer/examples/cube.tsx | 51 -------------- prismarine-viewer/examples/playground.ts | 37 +++++++++- .../examples/webgpuRendererWorker.ts | 68 +++++++++++-------- 4 files changed, 127 insertions(+), 79 deletions(-) create mode 100644 prismarine-viewer/examples/CubeDef.ts delete mode 100644 prismarine-viewer/examples/cube.tsx diff --git a/prismarine-viewer/examples/CubeDef.ts b/prismarine-viewer/examples/CubeDef.ts new file mode 100644 index 00000000..0e38f341 --- /dev/null +++ b/prismarine-viewer/examples/CubeDef.ts @@ -0,0 +1,50 @@ +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 + +//@ts-format-ignore-region +export const cubeVertexArray = new Float32Array([ + -0.5, -0.5, -0.5, 0.0, 0.0, 0.0, // Bottom-let + 0.5, -0.5, -0.5, 1.0, 0.0, 0.0, // bottom-right + 0.5, 0.5, -0.5, 1.0, 1.0, 0.0, // top-right + 0.5, 0.5, -0.5, 1.0, 1.0, 0.0, // top-right + -0.5, 0.5, -0.5, 0.0, 1.0, 0.0, // top-let + -0.5, -0.5, -0.5, 0.0, 0.0, 0.0, // bottom-let + // ront ace + -0.5, -0.5, 0.5, 0.0, 0.0, 1.0, // bottom-let + 0.5, 0.5, 0.5, 1.0, 1.0, 1.0, // top-right + 0.5, -0.5, 0.5, 1.0, 0.0, 1.0, // bottom-right + 0.5, 0.5, 0.5, 1.0, 1.0, 1.0,// top-right + -0.5, -0.5, 0.5, 0.0, 0.0, 1.0,// bottom-let + -0.5, 0.5, 0.5, 0.0, 1.0, 1.0,// top-let + // Let ace + -0.5, 0.5, 0.5, 1.0, 0.0, 2.0,// top-right + -0.5, -0.5, -0.5, 0.0, 1.0, 2.0,// bottom-let + -0.5, 0.5, -0.5, 1.0, 1.0, 2.0,// top-let + -0.5, -0.5, -0.5, 0.0, 1.0, 2.0,// bottom-let + -0.5, 0.5, 0.5, 1.0, 0.0, 2.0, // top-right + -0.5, -0.5, 0.5, 0.0, 0.0, 2.0,// bottom-right + // Right ace + 0.5, 0.5, 0.5, 1.0, 0.0, 3.0,// top-let + 0.5, 0.5, -0.5, 1.0, 1.0, 3.0,// top-right + 0.5, -0.5, -0.5, 0.0, 1.0, 3.0,// bottom-right + 0.5, -0.5, -0.5, 0.0, 1.0, 3.0,// bottom-right + 0.5, -0.5, 0.5, 0.0, 0.0, 3.0,// bottom-let + 0.5, 0.5, 0.5, 1.0, 0.0, 3.0, // top-let + // Bottom ace + -0.5, -0.5, -0.5, 0.0, 1.0, 4.0,// top-right + 0.5, -0.5, 0.5, 1.0, 0.0, 4.0,// bottom-let + 0.5, -0.5, -0.5, 1.0, 1.0, 4.0,// top-let + 0.5, -0.5, 0.5, 1.0, 0.0, 4.0, // bottom-let + -0.5, -0.5, -0.5, 0.0, 1.0, 4.0, // top-right + -0.5, -0.5, 0.5, 0.0, 0.0, 4.0, // bottom-right + // Top ace + -0.5, 0.5, -0.5, 0.0, 1.0, 5.0,// top-let + 0.5, 0.5, -0.5, 1.0, 1.0, 5.0,// top-right + 0.5, 0.5, 0.5, 1.0, 0.0, 5.0,// bottom-right + 0.5, 0.5, 0.5, 1.0, 0.0, 5.0,// bottom-right + -0.5, 0.5, 0.5, 0.0, 0.0, 5.0,// bottom-let + -0.5, 0.5, -0.5, 0.0, 1.0, 5.0// top-let˚ +]); diff --git a/prismarine-viewer/examples/cube.tsx b/prismarine-viewer/examples/cube.tsx deleted file mode 100644 index f2a59182..00000000 --- a/prismarine-viewer/examples/cube.tsx +++ /dev/null @@ -1,51 +0,0 @@ -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 - -//@ts-format-ignore-region -export const cubeVertexArray = new Float32Array([ - // float4 position, float4 color, float2 uv, - 1, -1, 1, 1, 1, 0, 1, 1, 0, 1, - -1, -1, 1, 1, 0, 0, 1, 1, 1, 1, - -1, -1, -1, 1, 0, 0, 0, 1, 1, 0, - 1, -1, -1, 1, 1, 0, 0, 1, 0, 0, - 1, -1, 1, 1, 1, 0, 1, 1, 0, 1, - -1, -1, -1, 1, 0, 0, 0, 1, 1, 0, - - 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, - 1, -1, 1, 1, 1, 0, 1, 1, 1, 1, - 1, -1, -1, 1, 1, 0, 0, 1, 1, 0, - 1, 1, -1, 1, 1, 1, 0, 1, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, - 1, -1, -1, 1, 1, 0, 0, 1, 1, 0, - - -1, 1, 1, 1, 0, 1, 1, 1, 0, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, -1, 1, 1, 1, 0, 1, 1, 0, - -1, 1, -1, 1, 0, 1, 0, 1, 0, 0, - -1, 1, 1, 1, 0, 1, 1, 1, 0, 1, - 1, 1, -1, 1, 1, 1, 0, 1, 1, 0, - - -1, -1, 1, 1, 0, 0, 1, 1, 0, 1, - -1, 1, 1, 1, 0, 1, 1, 1, 1, 1, - -1, 1, -1, 1, 0, 1, 0, 1, 1, 0, - -1, -1, -1, 1, 0, 0, 0, 1, 0, 0, - -1, -1, 1, 1, 0, 0, 1, 1, 0, 1, - -1, 1, -1, 1, 0, 1, 0, 1, 1, 0, - - 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, - -1, 1, 1, 1, 0, 1, 1, 1, 1, 1, - -1, -1, 1, 1, 0, 0, 1, 1, 1, 0, - -1, -1, 1, 1, 0, 0, 1, 1, 1, 0, - 1, -1, 1, 1, 1, 0, 1, 1, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, - - 1, -1, -1, 1, 1, 0, 0, 1, 0, 1, - -1, -1, -1, 1, 0, 0, 0, 1, 1, 1, - -1, 1, -1, 1, 0, 1, 0, 1, 1, 0, - 1, 1, -1, 1, 1, 1, 0, 1, 0, 0, - 1, -1, -1, 1, 1, 0, 0, 1, 0, 1, - -1, 1, -1, 1, 0, 1, 0, 1, 1, 0, - ]); diff --git a/prismarine-viewer/examples/playground.ts b/prismarine-viewer/examples/playground.ts index 0c3f97e2..c011244f 100644 --- a/prismarine-viewer/examples/playground.ts +++ b/prismarine-viewer/examples/playground.ts @@ -14,7 +14,7 @@ import { TWEEN_DURATION } from '../viewer/lib/entities' import Entity from '../viewer/lib/entity/Entity' // import * as Mathgl from 'math.gl' import { findTextureInBlockStates } from '../../src/playerWindows' -import { initWebgpuRenderer, loadFixtureSides, setAnimationTick } from './webgpuRendererMain' +import { initWebgpuRenderer, loadFixtureSides, setAnimationTick, webgpuChannel } from './webgpuRendererMain' import { renderToDom } from '@zardoy/react-util' globalThis.THREE = THREE @@ -23,6 +23,7 @@ import { OrbitControls } from 'three/addons/controls/OrbitControls.js' import { renderPlayground } from './TouchControls2' import { WorldRendererWebgpu } from '../viewer/lib/worldrendererWebgpu' import { TextureAnimation } from './TextureAnimation' +import { BlockType } from './shared' const gui = new GUI() @@ -186,6 +187,12 @@ async function main () { } direction.applyQuaternion(viewer.camera.quaternion) direction.y = 0 + + if (pressedKeys.has('ShiftLeft')) { + direction.y *= 2 + direction.x *= 2 + direction.z *= 2 + } // Add the vector to the camera's position to move the camera viewer.camera.position.add(direction) } @@ -246,6 +253,34 @@ async function main () { viewer.camera.position.set(pos[0], pos[1], pos[2]) } + let blocks: Record = {} + let i = 0 + for (let x = 0; x < 100; x++) { + blocks = {} + for (let i = 0; i < 10000; i++) { + const max = 1000 + const pos = new Vec3(Math.floor(Math.random() * max), Math.floor(Math.random() * max), Math.floor(Math.random() * max)) + const getFace = (face: number) => { + return { + face, + textureIndex: Math.floor(Math.random() * 512) + } + } + blocks[`${pos.x},${pos.y},${pos.z}`] = { + sides: [ + getFace(0), + getFace(1), + getFace(2), + getFace(3), + getFace(4), + getFace(5) + ], + } + } + webgpuChannel.addBlocksSection({ blocks }, `0,0,${i++}`) + } + + return // Create viewer diff --git a/prismarine-viewer/examples/webgpuRendererWorker.ts b/prismarine-viewer/examples/webgpuRendererWorker.ts index 6bd2bc4c..9ff0f0ee 100644 --- a/prismarine-viewer/examples/webgpuRendererWorker.ts +++ b/prismarine-viewer/examples/webgpuRendererWorker.ts @@ -2,7 +2,7 @@ import * as THREE from 'three' import { BlockFaceType, BlockType } from './shared' import * as tweenJs from '@tweenjs/tween.js' -import { cubePositionOffset, cubeUVOffset, cubeVertexArray, cubeVertexCount, cubeVertexSize } from './cube' +import { cubePositionOffset, cubeUVOffset, cubeVertexArray, cubeVertexCount, cubeVertexSize } from './CubeDef' //@ts-ignore import VertShader from './Cube.vert.wgsl' //@ts-ignore @@ -17,19 +17,10 @@ let chunksArrIndexes = {} let freeArrayIndexes = [] as [number, number][] let rendering = true let sidePositions -let updateCubes: (startIndex: any, forceUpdate?) => void let lastNotUpdatedIndex let lastNotUpdatedArrSize let animationTick = 0 -const updateCubesWhenAvailable = (pos) => { - if (updateCubes) { - updateCubes(pos) - } else { - setTimeout(updateCubesWhenAvailable, 100) - } -} - const camera = new THREE.PerspectiveCamera(75, 1 / 1, 0.1, 1000) globalThis.camera = camera @@ -47,6 +38,10 @@ const updateSize = (width, height) => { class WebgpuRendererWorker { + static NUMBER_OF_CUBES = 1_000_000 + + ready = false + device: GPUDevice renderPassDescriptor: GPURenderPassDescriptor uniformBindGroup: GPUBindGroup @@ -88,6 +83,7 @@ class WebgpuRendererWorker { alphaMode: 'premultiplied', }) + const verticesBuffer = device.createBuffer({ size: cubeVertexArray.byteLength, usage: GPUBufferUsage.VERTEX, @@ -97,24 +93,17 @@ class WebgpuRendererWorker { new Float32Array(verticesBuffer.getMappedRange()).set(cubeVertexArray) verticesBuffer.unmap() - let NumberOfCubes = 3 - //Todo: make this dynamic - const ModelMatrix = new Float32Array([ - 0, 1, 0, - 1, 0, 0, - 0, 0, 1 - ]) - const InstancedModelBuffer = device.createBuffer({ - size: 4 * 4 * 4, - usage: GPUBufferUsage.VERTEX, + + this.InstancedModelBuffer = device.createBuffer({ + size: WebgpuRendererWorker.NUMBER_OF_CUBES * 4 * 4, + usage: GPUBufferUsage.VERTEX || GPUBufferUsage.MAP_WRITE, mappedAtCreation: true, }) - this.InstancedModelBuffer = InstancedModelBuffer - new Float32Array(InstancedModelBuffer.getMappedRange()).set(ModelMatrix) - InstancedModelBuffer.unmap() + + //device.StepM const vertexCode = VertShader const fragmentCode = FragShader @@ -181,7 +170,7 @@ class WebgpuRendererWorker { }, primitive: { topology: 'triangle-list', - //cullMode: 'back', + cullMode: 'back', }, depthStencil: { @@ -267,10 +256,28 @@ class WebgpuRendererWorker { } this.loop() + this.ready = true return canvas } + updateSides (start) { + const positions = [] as number[] + for (let i = 0; i < allSides.length / 6; i++) { + const side = allSides[i * 6]! + positions.push(...[side[0], side[1], side[2]]) + } + + //Todo: make this dynamic + const ModelMatrix = new Float32Array(positions) + + + + + new Float32Array(this.InstancedModelBuffer.getMappedRange()).set(ModelMatrix) + this.InstancedModelBuffer.unmap() + } + lastCall = performance.now() logged = false @@ -309,7 +316,7 @@ class WebgpuRendererWorker { passEncoder.setBindGroup(0, uniformBindGroup) passEncoder.setVertexBuffer(0, verticesBuffer) passEncoder.setVertexBuffer(1, this.InstancedModelBuffer) - passEncoder.draw(cubeVertexCount, 3) + passEncoder.draw(cubeVertexCount, WebgpuRendererWorker.NUMBER_OF_CUBES) passEncoder.end() device.queue.submit([commandEncoder.finish()]) @@ -325,6 +332,13 @@ let fullReset let webglRendererWorker: WebgpuRendererWorker | undefined +const updateCubesWhenAvailable = (pos) => { + if (webglRendererWorker?.ready) { + webglRendererWorker.updateSides(pos) + } else { + setTimeout(updateCubesWhenAvailable, 100) + } +} let started = false let newWidth: number | undefined @@ -375,7 +389,7 @@ export const workerProxyType = createWorkerProxy({ chunksArrIndexes[key] = [currentLength, currentLength + newData.length] allSides.push(...newData) lastNotUpdatedIndex ??= currentLength - // updateCubes?.(currentLength) + updateCubesWhenAvailable(currentLength) }, addBlocksSectionDone () { updateCubesWhenAvailable(lastNotUpdatedIndex) @@ -389,7 +403,7 @@ export const workerProxyType = createWorkerProxy({ allSides[i] = undefined } lastNotUpdatedArrSize = endIndex - startIndex - updateCubes(startIndex) + updateCubesWhenAvailable(startIndex) // freeArrayIndexes.push([startIndex, endIndex]) From 560d5fb5e3ab8c254be1735fe8d3f4ff0ddab7ca Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 25 May 2024 02:02:50 +0300 Subject: [PATCH 3/6] up cube Co-authored-by: Ilya --- prismarine-viewer/examples/CubeDef.ts | 123 ++++++++++++------ prismarine-viewer/examples/playground.ts | 6 +- .../examples/webgpuRendererWorker.ts | 7 +- 3 files changed, 92 insertions(+), 44 deletions(-) diff --git a/prismarine-viewer/examples/CubeDef.ts b/prismarine-viewer/examples/CubeDef.ts index 0e38f341..d41f9251 100644 --- a/prismarine-viewer/examples/CubeDef.ts +++ b/prismarine-viewer/examples/CubeDef.ts @@ -1,50 +1,95 @@ -export const cubeVertexSize = 4 * 10 // Byte size of one cube vertex. +export const cubeVertexSize = 4 * 5 // 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 cubeColorOffset = 4 * 3 // Byte offset of cube vertex color attribute. +export const cubeUVOffset = 4 * 3 export const cubeVertexCount = 36 //@ts-format-ignore-region export const cubeVertexArray = new Float32Array([ - -0.5, -0.5, -0.5, 0.0, 0.0, 0.0, // Bottom-let - 0.5, -0.5, -0.5, 1.0, 0.0, 0.0, // bottom-right - 0.5, 0.5, -0.5, 1.0, 1.0, 0.0, // top-right - 0.5, 0.5, -0.5, 1.0, 1.0, 0.0, // top-right - -0.5, 0.5, -0.5, 0.0, 1.0, 0.0, // top-let - -0.5, -0.5, -0.5, 0.0, 0.0, 0.0, // bottom-let + -0.5, -0.5, -0.5, 0.0, 0.0, // Bottom-let + 0.5, -0.5, -0.5, 1.0, 0.0, // bottom-right + 0.5, 0.5, -0.5, 1.0, 1.0, // top-right + 0.5, 0.5, -0.5, 1.0, 1.0, // top-right + -0.5, 0.5, -0.5, 0.0, 1.0, // top-let + -0.5, -0.5, -0.5, 0.0, 0.0, // bottom-let // ront ace - -0.5, -0.5, 0.5, 0.0, 0.0, 1.0, // bottom-let - 0.5, 0.5, 0.5, 1.0, 1.0, 1.0, // top-right - 0.5, -0.5, 0.5, 1.0, 0.0, 1.0, // bottom-right - 0.5, 0.5, 0.5, 1.0, 1.0, 1.0,// top-right - -0.5, -0.5, 0.5, 0.0, 0.0, 1.0,// bottom-let - -0.5, 0.5, 0.5, 0.0, 1.0, 1.0,// top-let + -0.5, -0.5, 0.5, 0.0, 0.0, // bottom-let + 0.5, 0.5, 0.5, 1.0, 1.0, // top-right + 0.5, -0.5, 0.5, 1.0, 0.0, // bottom-right + 0.5, 0.5, 0.5, 1.0, 1.0, // top-right + -0.5, -0.5, 0.5, 0.0, 0.0, // bottom-let + -0.5, 0.5, 0.5, 0.0, 1.0, // top-let // Let ace - -0.5, 0.5, 0.5, 1.0, 0.0, 2.0,// top-right - -0.5, -0.5, -0.5, 0.0, 1.0, 2.0,// bottom-let - -0.5, 0.5, -0.5, 1.0, 1.0, 2.0,// top-let - -0.5, -0.5, -0.5, 0.0, 1.0, 2.0,// bottom-let - -0.5, 0.5, 0.5, 1.0, 0.0, 2.0, // top-right - -0.5, -0.5, 0.5, 0.0, 0.0, 2.0,// bottom-right + -0.5, 0.5, 0.5, 1.0, 0.0, // top-right + -0.5, -0.5, -0.5, 0.0, 1.0, // bottom-let + -0.5, 0.5, -0.5, 1.0, 1.0, // top-let + -0.5, -0.5, -0.5, 0.0, 1.0, // bottom-let + -0.5, 0.5, 0.5, 1.0, 0.0, // top-right + -0.5, -0.5, 0.5, 0.0, 0.0, // bottom-right // Right ace - 0.5, 0.5, 0.5, 1.0, 0.0, 3.0,// top-let - 0.5, 0.5, -0.5, 1.0, 1.0, 3.0,// top-right - 0.5, -0.5, -0.5, 0.0, 1.0, 3.0,// bottom-right - 0.5, -0.5, -0.5, 0.0, 1.0, 3.0,// bottom-right - 0.5, -0.5, 0.5, 0.0, 0.0, 3.0,// bottom-let - 0.5, 0.5, 0.5, 1.0, 0.0, 3.0, // top-let + 0.5, 0.5, 0.5, 1.0, 0.0, // top-let + 0.5, 0.5, -0.5, 1.0, 1.0, // top-right + 0.5, -0.5, -0.5, 0.0, 1.0, // bottom-right + 0.5, -0.5, -0.5, 0.0, 1.0, // bottom-right + 0.5, -0.5, 0.5, 0.0, 0.0, // bottom-let + 0.5, 0.5, 0.5, 1.0, 0.0, // top-let // Bottom ace - -0.5, -0.5, -0.5, 0.0, 1.0, 4.0,// top-right - 0.5, -0.5, 0.5, 1.0, 0.0, 4.0,// bottom-let - 0.5, -0.5, -0.5, 1.0, 1.0, 4.0,// top-let - 0.5, -0.5, 0.5, 1.0, 0.0, 4.0, // bottom-let - -0.5, -0.5, -0.5, 0.0, 1.0, 4.0, // top-right - -0.5, -0.5, 0.5, 0.0, 0.0, 4.0, // bottom-right + -0.5, -0.5, -0.5, 0.0, 1.0, // top-right + 0.5, -0.5, 0.5, 1.0, 0.0, // bottom-let + 0.5, -0.5, -0.5, 1.0, 1.0, // top-let + 0.5, -0.5, 0.5, 1.0, 0.0, // bottom-let + -0.5, -0.5, -0.5, 0.0, 1.0, // top-right + -0.5, -0.5, 0.5, 0.0, 0.0, // bottom-right // Top ace - -0.5, 0.5, -0.5, 0.0, 1.0, 5.0,// top-let - 0.5, 0.5, -0.5, 1.0, 1.0, 5.0,// top-right - 0.5, 0.5, 0.5, 1.0, 0.0, 5.0,// bottom-right - 0.5, 0.5, 0.5, 1.0, 0.0, 5.0,// bottom-right - -0.5, 0.5, 0.5, 0.0, 0.0, 5.0,// bottom-let - -0.5, 0.5, -0.5, 0.0, 1.0, 5.0// top-let˚ + -0.5, 0.5, -0.5, 0.0, 1.0, // top-let + 0.5, 0.5, -0.5, 1.0, 1.0, // top-right + 0.5, 0.5, 0.5, 1.0, 0.0, // bottom-right + 0.5, 0.5, 0.5, 1.0, 0.0, // bottom-right + -0.5, 0.5, 0.5, 0.0, 0.0, // bottom-let + -0.5, 0.5, -0.5, 0.0, 1.0// top-let˚ +]); + + +export const cubeVertexArraySub = new Float32Array([ + -0.5, -0.5, -0.5, 0.0, 0.0, // Bottom-let + 0.5, -0.5, -0.5, 1.0, 0.0, // bottom-right + 0.5, 0.5, -0.5, 1.0, 1.0, // top-right + 0.5, 0.5, -0.5, 1.0, 1.0, // top-right + -0.5, 0.5, -0.5, 0.0, 1.0, // top-let + -0.5, -0.5, -0.5, 0.0, 0.0, // bottom-let + // ront ace + -0.5, -0.5, 0.5, 0.0, 0.0, // bottom-let + 0.5, 0.5, 0.5, 1.0, 1.0, // top-right + 0.5, -0.5, 0.5, 1.0, 0.0, // bottom-right + 0.5, 0.5, 0.5, 1.0, 1.0, // top-right + -0.5, -0.5, 0.5, 0.0, 0.0, // bottom-let + -0.5, 0.5, 0.5, 0.0, 1.0, // top-let + // Let ace + -0.5, 0.5, 0.5, 1.0, 0.0, // top-right + -0.5, -0.5, -0.5, 0.0, 1.0, // bottom-let + -0.5, 0.5, -0.5, 1.0, 1.0, // top-let + -0.5, -0.5, -0.5, 0.0, 1.0, // bottom-let + -0.5, 0.5, 0.5, 1.0, 0.0, // top-right + -0.5, -0.5, 0.5, 0.0, 0.0, // bottom-right + // Right ace + 0.5, 0.5, 0.5, 1.0, 0.0, // top-let + 0.5, 0.5, -0.5, 1.0, 1.0, // top-right + 0.5, -0.5, -0.5, 0.0, 1.0, // bottom-right + 0.5, -0.5, -0.5, 0.0, 1.0, // bottom-right + 0.5, -0.5, 0.5, 0.0, 0.0, // bottom-let + 0.5, 0.5, 0.5, 1.0, 0.0, // top-let + // Bottom ace + -0.5, -0.5, -0.5, 0.0, 1.0, // top-right + 0.5, -0.5, 0.5, 1.0, 0.0, // bottom-let + 0.5, -0.5, -0.5, 1.0, 1.0, // top-let + 0.5, -0.5, 0.5, 1.0, 0.0, // bottom-let + -0.5, -0.5, -0.5, 0.0, 1.0, // top-right + -0.5, -0.5, 0.5, 0.0, 0.0, // bottom-right + // Top ace + -0.5, 0.5, -0.5, 0.0, 1.0, // top-let + 0.5, 0.5, -0.5, 1.0, 1.0, // top-right + 0.5, 0.5, 0.5, 1.0, 0.0, // bottom-right + 0.5, 0.5, 0.5, 1.0, 0.0, // bottom-right + -0.5, 0.5, 0.5, 0.0, 0.0, // bottom-let + -0.5, 0.5, -0.5, 0.0, 1.0, 5.0// top-let˚ ]); diff --git a/prismarine-viewer/examples/playground.ts b/prismarine-viewer/examples/playground.ts index c011244f..f9c729f5 100644 --- a/prismarine-viewer/examples/playground.ts +++ b/prismarine-viewer/examples/playground.ts @@ -255,10 +255,10 @@ async function main () { let blocks: Record = {} let i = 0 - for (let x = 0; x < 100; x++) { + for (let x = 0; x < 1; x++) { blocks = {} - for (let i = 0; i < 10000; i++) { - const max = 1000 + for (let i = 0; i < 1000; i++) { + const max = 100 const pos = new Vec3(Math.floor(Math.random() * max), Math.floor(Math.random() * max), Math.floor(Math.random() * max)) const getFace = (face: number) => { return { diff --git a/prismarine-viewer/examples/webgpuRendererWorker.ts b/prismarine-viewer/examples/webgpuRendererWorker.ts index 9ff0f0ee..b5731dc3 100644 --- a/prismarine-viewer/examples/webgpuRendererWorker.ts +++ b/prismarine-viewer/examples/webgpuRendererWorker.ts @@ -122,7 +122,7 @@ class WebgpuRendererWorker { // position shaderLocation: 0, offset: cubePositionOffset, - format: 'float32x4', + format: 'float32x3', }, { // uv @@ -170,7 +170,7 @@ class WebgpuRendererWorker { }, primitive: { topology: 'triangle-list', - cullMode: 'back', + cullMode: 'front', }, depthStencil: { @@ -255,6 +255,9 @@ class WebgpuRendererWorker { }, } + + // always last! + rendering = false this.loop() this.ready = true From 6f0e238409cb47455692ad182143cc4c7395bdba Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 25 May 2024 03:15:54 +0300 Subject: [PATCH 4/6] reduce size Co-authored-by: Ilya --- prismarine-viewer/examples/webgpuRendererWorker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prismarine-viewer/examples/webgpuRendererWorker.ts b/prismarine-viewer/examples/webgpuRendererWorker.ts index b5731dc3..f77e8239 100644 --- a/prismarine-viewer/examples/webgpuRendererWorker.ts +++ b/prismarine-viewer/examples/webgpuRendererWorker.ts @@ -38,7 +38,7 @@ const updateSize = (width, height) => { class WebgpuRendererWorker { - static NUMBER_OF_CUBES = 1_000_000 + NUMBER_OF_CUBES = 1000 ready = false From 6d375d83e9566ae02cd73e86402233f6a8241566 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 25 May 2024 03:17:57 +0300 Subject: [PATCH 5/6] Refactor shader code for cube rendering --- prismarine-viewer/examples/Cube.frag.wgsl | 1 - prismarine-viewer/examples/Cube.vert.wgsl | 11 +--- .../examples/webgpuRendererWorker.ts | 51 ++++++++++++------- 3 files changed, 35 insertions(+), 28 deletions(-) diff --git a/prismarine-viewer/examples/Cube.frag.wgsl b/prismarine-viewer/examples/Cube.frag.wgsl index 0d936ae7..87074904 100644 --- a/prismarine-viewer/examples/Cube.frag.wgsl +++ b/prismarine-viewer/examples/Cube.frag.wgsl @@ -4,7 +4,6 @@ @fragment fn main( @location(0) fragUV: vec2f, - @location(1) fragPosition: vec4f ) -> @location(0) vec4f { return textureSample(myTexture, mySampler, fragUV/64); } diff --git a/prismarine-viewer/examples/Cube.vert.wgsl b/prismarine-viewer/examples/Cube.vert.wgsl index bce33581..713b32a0 100644 --- a/prismarine-viewer/examples/Cube.vert.wgsl +++ b/prismarine-viewer/examples/Cube.vert.wgsl @@ -1,28 +1,21 @@ struct Uniforms { - modelViewProjectionMatrix : mat4x4f, - //modelViewProjectionMatrix : array, - //ProjectionMatrix : mat4x4f, - // ViewMatrix: mat4x4f + ViewProjectionMatrix : mat4x4f, } @binding(0) @group(0) var uniforms : Uniforms; struct VertexOutput { @builtin(position) Position : vec4f, @location(0) fragUV : vec2f, - @location(1) fragPosition: vec4f, } @vertex fn main( - //@builtin(instance_index) instanceIdx : u32, @location(0) position : vec4f, @location(1) uv : vec2f, @location(2) ModelMatrix : vec3f, ) -> VertexOutput { var output : VertexOutput; - output.Position = uniforms.modelViewProjectionMatrix * (position +vec4f(ModelMatrix, 0.0)); - //output.Position = uniforms.modelViewProjectionMatrix[instanceIdx] * position; + output.Position = uniforms.ViewProjectionMatrix * (position +vec4f(ModelMatrix, 0.0)); output.fragUV = uv; - output.fragPosition = 0.5 * (position + vec4(1.0, 1.0, 1.0, 1.0)); return output; } diff --git a/prismarine-viewer/examples/webgpuRendererWorker.ts b/prismarine-viewer/examples/webgpuRendererWorker.ts index f77e8239..e3f3b1c1 100644 --- a/prismarine-viewer/examples/webgpuRendererWorker.ts +++ b/prismarine-viewer/examples/webgpuRendererWorker.ts @@ -95,10 +95,8 @@ class WebgpuRendererWorker { - - this.InstancedModelBuffer = device.createBuffer({ - size: WebgpuRendererWorker.NUMBER_OF_CUBES * 4 * 4, + size: this.NUMBER_OF_CUBES * 4 * 4, usage: GPUBufferUsage.VERTEX || GPUBufferUsage.MAP_WRITE, mappedAtCreation: true, }) @@ -143,7 +141,20 @@ class WebgpuRendererWorker { } ], stepMode: 'instance', - } + }, + // { + // arrayStride: 1 * 4, + // attributes: [ + // { + // // ModelMatrix + // shaderLocation: 3, + // offset: 0, + // format: 'float32x1', + // } + // ], + // stepMode: 'instance', + // } + ], }, fragment: { @@ -260,11 +271,11 @@ class WebgpuRendererWorker { rendering = false this.loop() this.ready = true - return canvas } updateSides (start) { + rendering = true const positions = [] as number[] for (let i = 0; i < allSides.length / 6; i++) { const side = allSides[i * 6]! @@ -276,9 +287,9 @@ class WebgpuRendererWorker { - new Float32Array(this.InstancedModelBuffer.getMappedRange()).set(ModelMatrix) this.InstancedModelBuffer.unmap() + // this.NUMBER_OF_CUBES = positions.length } @@ -295,31 +306,35 @@ class WebgpuRendererWorker { const now = Date.now() tweenJs.update() - const modelViewProjectionMat4 = new THREE.Matrix4() + const ViewProjectionMat4 = new THREE.Matrix4() camera.updateMatrix() const projectionMatrix = camera.projectionMatrix - modelViewProjectionMat4.multiplyMatrices(projectionMatrix, camera.matrix.invert()) - const modelViewProjection = new Float32Array(modelViewProjectionMat4.elements) - // globalThis.modelViewProjection = modelViewProjection + ViewProjectionMat4.multiplyMatrices(projectionMatrix, camera.matrix.invert()) + const ViewProjection = new Float32Array(ViewProjectionMat4.elements) + // globalThis.ViewProjection = ViewProjection device.queue.writeBuffer( uniformBuffer, 0, - modelViewProjection.buffer, - modelViewProjection.byteOffset, - modelViewProjection.byteLength + ViewProjection.buffer, + ViewProjection.byteOffset, + ViewProjection.byteLength ) + + + renderPassDescriptor.colorAttachments[0].view = ctx .getCurrentTexture() .createView() const commandEncoder = device.createCommandEncoder() - const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor) - + const passEncoder = commandEncoder.beginRenderPass(this.renderPassDescriptor) passEncoder.setPipeline(pipeline) - passEncoder.setBindGroup(0, uniformBindGroup) + passEncoder.setBindGroup(0, this.uniformBindGroup) passEncoder.setVertexBuffer(0, verticesBuffer) passEncoder.setVertexBuffer(1, this.InstancedModelBuffer) - passEncoder.draw(cubeVertexCount, WebgpuRendererWorker.NUMBER_OF_CUBES) + + + passEncoder.draw(cubeVertexCount, this.NUMBER_OF_CUBES) passEncoder.end() device.queue.submit([commandEncoder.finish()]) @@ -390,7 +405,7 @@ export const workerProxyType = createWorkerProxy({ } chunksArrIndexes[key] = [currentLength, currentLength + newData.length] - allSides.push(...newData) + allSides.splice(currentLength, 0, ...newData) lastNotUpdatedIndex ??= currentLength updateCubesWhenAvailable(currentLength) }, From 02a84b83abae55a2a521c203940597f5e6a556f8 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sat, 25 May 2024 03:41:00 +0300 Subject: [PATCH 6/6] add textures --- prismarine-viewer/examples/Cube.frag.wgsl | 3 +- prismarine-viewer/examples/Cube.vert.wgsl | 3 ++ .../examples/webgpuRendererWorker.ts | 41 +++++++++++++------ 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/prismarine-viewer/examples/Cube.frag.wgsl b/prismarine-viewer/examples/Cube.frag.wgsl index 87074904..1974feca 100644 --- a/prismarine-viewer/examples/Cube.frag.wgsl +++ b/prismarine-viewer/examples/Cube.frag.wgsl @@ -4,6 +4,7 @@ @fragment fn main( @location(0) fragUV: vec2f, + @location(1) TextueIndex: f32 ) -> @location(0) vec4f { - return textureSample(myTexture, mySampler, fragUV/64); + return textureSample(myTexture, mySampler, fragUV/64.0 + vec2f(TextueIndex%32,TextueIndex/32.0 )/32.0); } diff --git a/prismarine-viewer/examples/Cube.vert.wgsl b/prismarine-viewer/examples/Cube.vert.wgsl index 713b32a0..7898c88f 100644 --- a/prismarine-viewer/examples/Cube.vert.wgsl +++ b/prismarine-viewer/examples/Cube.vert.wgsl @@ -6,6 +6,7 @@ struct Uniforms { struct VertexOutput { @builtin(position) Position : vec4f, @location(0) fragUV : vec2f, + @location(1) TextueIndex: f32 } @vertex @@ -13,9 +14,11 @@ fn main( @location(0) position : vec4f, @location(1) uv : vec2f, @location(2) ModelMatrix : vec3f, + @location(3) TextureIndex : f32 ) -> VertexOutput { var output : VertexOutput; output.Position = uniforms.ViewProjectionMatrix * (position +vec4f(ModelMatrix, 0.0)); output.fragUV = uv; + output.TextueIndex = TextureIndex; return output; } diff --git a/prismarine-viewer/examples/webgpuRendererWorker.ts b/prismarine-viewer/examples/webgpuRendererWorker.ts index e3f3b1c1..f066cbb9 100644 --- a/prismarine-viewer/examples/webgpuRendererWorker.ts +++ b/prismarine-viewer/examples/webgpuRendererWorker.ts @@ -52,6 +52,7 @@ class WebgpuRendererWorker { verticesBuffer: GPUBuffer InstancedModelBuffer: GPUBuffer pipeline: GPURenderPipeline + InstancedTextureIndexBuffer: GPUBuffer constructor(public canvas: HTMLCanvasElement, public imageBlob: ImageBitmapSource, public isPlayground: boolean, public FragShaderOverride?) { this.init() @@ -96,7 +97,13 @@ class WebgpuRendererWorker { this.InstancedModelBuffer = device.createBuffer({ - size: this.NUMBER_OF_CUBES * 4 * 4, + size: this.NUMBER_OF_CUBES * 4 * 3, + usage: GPUBufferUsage.VERTEX || GPUBufferUsage.MAP_WRITE, + mappedAtCreation: true, + }) + + this.InstancedTextureIndexBuffer = device.createBuffer({ + size: this.NUMBER_OF_CUBES * 4 * 1, usage: GPUBufferUsage.VERTEX || GPUBufferUsage.MAP_WRITE, mappedAtCreation: true, }) @@ -142,18 +149,18 @@ class WebgpuRendererWorker { ], stepMode: 'instance', }, - // { - // arrayStride: 1 * 4, - // attributes: [ - // { - // // ModelMatrix - // shaderLocation: 3, - // offset: 0, - // format: 'float32x1', - // } - // ], - // stepMode: 'instance', - // } + { + arrayStride: 1 * 4, + attributes: [ + { + // ModelMatrix + shaderLocation: 3, + offset: 0, + format: 'float32', + } + ], + stepMode: 'instance', + } ], }, @@ -277,9 +284,11 @@ class WebgpuRendererWorker { updateSides (start) { rendering = true const positions = [] as number[] + let textureIndexes = [] as number[] for (let i = 0; i < allSides.length / 6; i++) { const side = allSides[i * 6]! positions.push(...[side[0], side[1], side[2]]) + textureIndexes.push(side[3].textureIndex) } //Todo: make this dynamic @@ -289,6 +298,11 @@ class WebgpuRendererWorker { new Float32Array(this.InstancedModelBuffer.getMappedRange()).set(ModelMatrix) this.InstancedModelBuffer.unmap() + + // same index with length = allSides.length / 6 + new Float32Array(this.InstancedTextureIndexBuffer.getMappedRange()).set(new Float32Array(textureIndexes)) + this.InstancedTextureIndexBuffer.unmap() + // this.NUMBER_OF_CUBES = positions.length } @@ -332,6 +346,7 @@ class WebgpuRendererWorker { passEncoder.setBindGroup(0, this.uniformBindGroup) passEncoder.setVertexBuffer(0, verticesBuffer) passEncoder.setVertexBuffer(1, this.InstancedModelBuffer) + passEncoder.setVertexBuffer(2, this.InstancedTextureIndexBuffer) passEncoder.draw(cubeVertexCount, this.NUMBER_OF_CUBES)