Skip to content

Commit

Permalink
feat: add fallback for unsupported multidraw extension
Browse files Browse the repository at this point in the history
- simple multi draw, no instance fallback yet

#132
  • Loading branch information
dmnsgn committed Sep 5, 2023
1 parent a392002 commit 4505d45
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 60 deletions.
131 changes: 93 additions & 38 deletions examples/multi-draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand All @@ -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;
Expand All @@ -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);
}`,
Expand All @@ -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,
Expand Down
74 changes: 52 additions & 22 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
}
Expand Down

0 comments on commit 4505d45

Please sign in to comment.