diff --git a/examples/multi-draw.js b/examples/multi-draw.js index abef364..45be89f 100644 --- a/examples/multi-draw.js +++ b/examples/multi-draw.js @@ -2,27 +2,13 @@ import createContext from "../index.js"; import { perspective as createCamera, orbiter as createOrbiter } from "pex-cam"; -import { cube, sphere, torus } from "primitive-geometry"; +import { plane, cube, sphere, torus } from "primitive-geometry"; import merge from "geom-merge"; +import splitVertices from "geom-split-vertices"; import basicFrag from "./shaders/basic.frag.js"; -const ctx = createContext({ pixelRatio: devicePixelRatio }); - -const CellsConstructor = Uint16Array; - -const sphereGeometry = sphere(); -sphereGeometry.positions = sphereGeometry.positions.map((value, i) => - i % 3 === 0 ? value - 1.25 : value -); -const cubeGeometry = cube(); - -const torusGeometry = torus(); -torusGeometry.positions = torusGeometry.positions.map((value, i) => - i % 3 === 0 ? value + 1.25 : value -); -const geometries = [sphereGeometry, cubeGeometry, torusGeometry]; -const geometry = merge(geometries); +const ctx = (window.ctx = createContext({ pixelRatio: devicePixelRatio })); const camera = createCamera({ position: [0, 0, 3], @@ -36,24 +22,69 @@ const clearCmd = { }), }; +const unindexed = true; + +// Create geometries +const planeGeometry = plane(); +const planeGeometry2 = plane(); +planeGeometry2.positions = planeGeometry2.positions.map((value, i) => + i % 3 === 0 ? value - 1.25 : value +); +const sphereGeometry = sphere(); +sphereGeometry.positions = sphereGeometry.positions.map((value, i) => + i % 3 === 0 ? value - 1.25 : value +); +const torusGeometry = torus(); +const cubeGeometry = cube(); +cubeGeometry.positions = cubeGeometry.positions.map((value, i) => + i % 3 === 0 ? value + 1.25 : value +); +const geometries = [ + planeGeometry, + sphereGeometry, + torusGeometry, + cubeGeometry, +].map((geometry) => + unindexed ? splitVertices(geometry.positions, geometry.cells) : geometry +); + +const geometry = merge(geometries); + +// Create multidraw const counts = new Int32Array(geometries.length); const offsets = new Int32Array(geometries.length); +const firsts = new Int32Array(geometries.length); -for (let i = 0; i < geometries.length; i++) { - counts[i] = geometries[i].cells.length; +if (unindexed) { + for (let i = 0; i < geometries.length; i++) { + counts[i] = geometries[i].positions.length / 3; - if (i > 0) { - offsets[i] = - offsets[i - 1] + - geometries[i - 1].cells.length * CellsConstructor.BYTES_PER_ELEMENT; + if (i > 0) firsts[i] = firsts[i - 1] + counts[i - 1]; + } +} else { + for (let i = 0; i < geometries.length; i++) { + counts[i] = geometries[i].cells.length; + + if (i > 0) { + offsets[i] = + offsets[i - 1] + + counts[i - 1] * geometry.cells.constructor.BYTES_PER_ELEMENT; + } } } +console.log("geometry", geometry); +console.log("counts", counts); +console.log("offsets", offsets); +console.log("firsts", firsts); const drawCmd = { pipeline: ctx.pipeline({ depthTest: true, vert: /* glsl */ ` -#extension GL_ANGLE_multi_draw: require +${ctx.capabilities.multiDraw ? "#define USE_MULTI_DRAW" : ""} +#ifdef USE_MULTI_DRAW + #extension GL_ANGLE_multi_draw: require +#endif attribute vec3 aPosition; @@ -63,15 +94,19 @@ uniform mat4 uViewMatrix; varying vec4 vColor; void main () { - if (gl_DrawID == 0) { - vColor = vec4(1.0, 0.0, 0.0, 1.0); - } else if (gl_DrawID == 1) { - vColor = vec4(0.0, 1.0, 0.0, 1.0); - } else if (gl_DrawID == 2) { - vColor = vec4(0.0, 0.0, 1.0, 1.0); - } else { - vColor = vec4(1.0, 1.0, 0.0, 1.0); - } + #ifdef USE_MULTI_DRAW + if (gl_DrawID == 0) { + vColor = vec4(1.0, 0.0, 0.0, 1.0); + } else if (gl_DrawID == 1) { + vColor = vec4(0.0, 1.0, 0.0, 1.0); + } else if (gl_DrawID == 2) { + vColor = vec4(0.0, 0.0, 1.0, 1.0); + } else { + vColor = vec4(1.0, 1.0, 0.0, 1.0); + } + #else + vColor = vec4(1.0, 1.0, 1.0, 1.0); + #endif gl_Position = uProjectionMatrix * uViewMatrix * vec4(aPosition, 1.0); }`, @@ -80,11 +115,31 @@ void main () { attributes: { aPosition: ctx.vertexBuffer(geometry.positions), }, - indices: ctx.indexBuffer(geometry.cells), - multiDraw: { - counts, - offsets, - }, + // ...(unindexed + // ? { count: geometry.positions.length / 3 } + // : { indices: ctx.indexBuffer(geometry.cells) }), + + ...(unindexed + ? { + multiDraw: { + firsts, + counts, + firstsOffset: 1, + countsOffset: 1, + drawCount: geometries.length - 1, + }, + } + : { + indices: ctx.indexBuffer(geometry.cells), + multiDraw: { + counts, + offsets, + // Ignore first geometry to test offsets + countsOffset: 1, + offsetsOffset: 1, + drawCount: geometries.length - 1, + }, + }), uniforms: { uProjectionMatrix: camera.projectionMatrix, uViewMatrix: camera.viewMatrix, diff --git a/index.js b/index.js index 483ef9b..0df274d 100644 --- a/index.js +++ b/index.js @@ -1171,22 +1171,37 @@ function createContext(options = {}) { } } } else { - if (cmd.multiDraw && ctx.capabilities.multiDraw) { - const ext = gl.getExtension("WEBGL_multi_draw"); - ext.multiDrawElementsWEBGL( - primitive, - cmd.multiDraw.counts, - cmd.multiDraw.countsOffset || 0, - type, - cmd.multiDraw.offsets, - cmd.multiDraw.offsetsOffset || 0, - cmd.multiDraw.counts.length - ); + if (cmd.multiDraw) { + if (ctx.capabilities.multiDraw) { + const ext = gl.getExtension("WEBGL_multi_draw"); + ext.multiDrawElementsWEBGL( + primitive, + cmd.multiDraw.counts, + cmd.multiDraw.countsOffset || 0, + type, + cmd.multiDraw.offsets, + cmd.multiDraw.offsetsOffset || 0, + cmd.multiDraw.drawCount || cmd.multiDraw.counts.length + ); + } else { + const countsOffset = cmd.multiDraw.countsOffset || 0; + const offsetsOffset = cmd.multiDraw.offsetsOffset || 0; + const drawCount = + cmd.multiDraw.drawCount || cmd.multiDraw.counts.length; + for (let i = 0; i < drawCount; i++) { + gl.drawElements( + primitive, + cmd.multiDraw.counts[i + countsOffset], + type, + cmd.multiDraw.offsets[i + offsetsOffset] + ); + } + } } else { gl.drawElements(primitive, count, type, offset); } } - } else if (cmd.count) { + } else if (cmd.count || cmd.multiDraw?.counts) { const first = 0; if (instanced) { if (cmd.multiDraw && ctx.capabilities.multiDraw) { @@ -1248,16 +1263,31 @@ function createContext(options = {}) { } } } else { - if (cmd.multiDraw && ctx.capabilities.multiDraw) { - const ext = gl.getExtension("WEBGL_multi_draw"); - ext.multiDrawArraysWEBGL( - primitive, - cmd.multiDraw.firsts, - cmd.multiDraw.firstsOffset || 0, - cmd.multiDraw.counts, - cmd.multiDraw.countsOffset || 0, - cmd.multiDraw.firsts.length - ); + if (cmd.multiDraw) { + if (ctx.capabilities.multiDraw) { + // console.log(cmd.multiDraw); + const ext = gl.getExtension("WEBGL_multi_draw"); + ext.multiDrawArraysWEBGL( + primitive, + cmd.multiDraw.firsts, + cmd.multiDraw.firstsOffset || 0, + cmd.multiDraw.counts, + cmd.multiDraw.countsOffset || 0, + cmd.multiDraw.drawCount || cmd.multiDraw.firsts.length + ); + } else { + const firstsOffset = cmd.multiDraw.firstsOffset || 0; + const countsOffset = cmd.multiDraw.countsOffset || 0; + const drawCount = + cmd.multiDraw.drawCount || cmd.multiDraw.firsts.length; + for (let i = 0; i < drawCount; i++) { + gl.drawArrays( + primitive, + cmd.multiDraw.firsts[i + firstsOffset], + cmd.multiDraw.counts[i + countsOffset] + ); + } + } } else { gl.drawArrays(primitive, first, cmd.count); }