在 twgl.js 中使用实例扩展
Use instancing extension in twgl.js
我是 twgl.js 的新手。我想知道如何使用扩展,尤其是实例化
它对我们来说是一种简单的方法还是我必须在其中使用纯 webgl?
在 v3.6.0 中添加了实例化。
要在 twgl 调用中使用实例化,请在 FullArraySpec
或 AttribInfo
上设置一个 divisor
如果您自己创建了 WebGL 上下文,请调用 twgl.addExtensionsOnContext
建议您使用顶点数组对象,因为 twgl 不会自动重置先前已设置除数的属性的除数。
示例:
const vs = `
uniform mat4 u_viewProjection;
attribute vec4 instanceColor;
attribute mat4 instanceWorld;
attribute vec4 position;
attribute vec3 normal;
varying vec4 v_position;
varying vec3 v_normal;
varying vec4 v_color;
void main() {
gl_Position = u_viewProjection * instanceWorld * position;
v_color = instanceColor;
v_normal = (instanceWorld * vec4(normal, 0)).xyz;
}
`;
const fs = `
precision mediump float;
varying vec3 v_normal;
varying vec4 v_color;
uniform vec3 u_lightDir;
void main() {
vec3 a_normal = normalize(v_normal);
float light = dot(u_lightDir, a_normal) * .5 + .5;
gl_FragColor = vec4(v_color.rgb * light, v_color.a);
}
`;
"use strict";
function main() {
const m4 = twgl.m4;
const v3 = twgl.v3;
const gl = document.querySelector("canvas").getContext("webgl");
twgl.addExtensionsToContext(gl);
if (!gl.drawArraysInstanced || !gl.createVertexArray) {
alert("need drawArraysInstanced and createVertexArray"); // eslint-disable-line
return;
}
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
function rand(min, max) {
if (max === undefined) {
max = min;
min = 0;
}
return min + Math.random() * (max - min);
}
const numInstances = 100000;
const instanceWorlds = new Float32Array(numInstances * 16);
const instanceColors = [];
const r = 100;
for (let i = 0; i < numInstances; ++i) {
const mat = new Float32Array(instanceWorlds.buffer, i * 16 * 4, 16);
m4.translation([rand(-r, r), rand(-r, r), rand(-r, r)], mat);
m4.rotateZ(mat, rand(0, Math.PI * 2), mat);
m4.rotateX(mat, rand(0, Math.PI * 2), mat);
instanceColors.push(rand(1), rand(1), rand(1));
}
const arrays = twgl.primitives.createCubeVertices();
Object.assign(arrays, {
instanceWorld: {
numComponents: 16,
data: instanceWorlds,
divisor: 1,
},
instanceColor: {
numComponents: 3,
data: instanceColors,
divisor: 1,
},
});
const bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
const vertexArrayInfo = twgl.createVertexArrayInfo(gl, programInfo, bufferInfo);
const uniforms = {
u_lightDir: v3.normalize([1, 8, -30]),
};
function render(time) {
time *= 0.001;
twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
const fov = 30 * Math.PI / 180;
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const zNear = 0.5;
const zFar = 500;
const projection = m4.perspective(fov, aspect, zNear, zFar);
const radius = 25;
const speed = time * .1;
const eye = [
Math.sin(speed) * radius,
Math.sin(speed * .7) * 10,
Math.cos(speed) * radius,
];
const target = [0, 0, 0];
const up = [0, 1, 0];
const camera = m4.lookAt(eye, target, up);
const view = m4.inverse(camera);
const viewProjection = m4.multiply(projection, view);
const world = m4.rotationY(time);
uniforms.u_viewProjection = viewProjection;
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, vertexArrayInfo);
twgl.setUniforms(programInfo, uniforms);
gl.drawElementsInstanced(gl.TRIANGLES, vertexArrayInfo.numElements, gl.UNSIGNED_SHORT, 0, numInstances);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://twgljs.org/dist/3.x/twgl-full.min.js"></script>
<canvas></canvas>
我是 twgl.js 的新手。我想知道如何使用扩展,尤其是实例化 它对我们来说是一种简单的方法还是我必须在其中使用纯 webgl?
在 v3.6.0 中添加了实例化。
要在 twgl 调用中使用实例化,请在 FullArraySpec
或 AttribInfo
上设置一个 divisor
如果您自己创建了 WebGL 上下文,请调用 twgl.addExtensionsOnContext
建议您使用顶点数组对象,因为 twgl 不会自动重置先前已设置除数的属性的除数。
示例:
const vs = `
uniform mat4 u_viewProjection;
attribute vec4 instanceColor;
attribute mat4 instanceWorld;
attribute vec4 position;
attribute vec3 normal;
varying vec4 v_position;
varying vec3 v_normal;
varying vec4 v_color;
void main() {
gl_Position = u_viewProjection * instanceWorld * position;
v_color = instanceColor;
v_normal = (instanceWorld * vec4(normal, 0)).xyz;
}
`;
const fs = `
precision mediump float;
varying vec3 v_normal;
varying vec4 v_color;
uniform vec3 u_lightDir;
void main() {
vec3 a_normal = normalize(v_normal);
float light = dot(u_lightDir, a_normal) * .5 + .5;
gl_FragColor = vec4(v_color.rgb * light, v_color.a);
}
`;
"use strict";
function main() {
const m4 = twgl.m4;
const v3 = twgl.v3;
const gl = document.querySelector("canvas").getContext("webgl");
twgl.addExtensionsToContext(gl);
if (!gl.drawArraysInstanced || !gl.createVertexArray) {
alert("need drawArraysInstanced and createVertexArray"); // eslint-disable-line
return;
}
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
function rand(min, max) {
if (max === undefined) {
max = min;
min = 0;
}
return min + Math.random() * (max - min);
}
const numInstances = 100000;
const instanceWorlds = new Float32Array(numInstances * 16);
const instanceColors = [];
const r = 100;
for (let i = 0; i < numInstances; ++i) {
const mat = new Float32Array(instanceWorlds.buffer, i * 16 * 4, 16);
m4.translation([rand(-r, r), rand(-r, r), rand(-r, r)], mat);
m4.rotateZ(mat, rand(0, Math.PI * 2), mat);
m4.rotateX(mat, rand(0, Math.PI * 2), mat);
instanceColors.push(rand(1), rand(1), rand(1));
}
const arrays = twgl.primitives.createCubeVertices();
Object.assign(arrays, {
instanceWorld: {
numComponents: 16,
data: instanceWorlds,
divisor: 1,
},
instanceColor: {
numComponents: 3,
data: instanceColors,
divisor: 1,
},
});
const bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
const vertexArrayInfo = twgl.createVertexArrayInfo(gl, programInfo, bufferInfo);
const uniforms = {
u_lightDir: v3.normalize([1, 8, -30]),
};
function render(time) {
time *= 0.001;
twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
const fov = 30 * Math.PI / 180;
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const zNear = 0.5;
const zFar = 500;
const projection = m4.perspective(fov, aspect, zNear, zFar);
const radius = 25;
const speed = time * .1;
const eye = [
Math.sin(speed) * radius,
Math.sin(speed * .7) * 10,
Math.cos(speed) * radius,
];
const target = [0, 0, 0];
const up = [0, 1, 0];
const camera = m4.lookAt(eye, target, up);
const view = m4.inverse(camera);
const viewProjection = m4.multiply(projection, view);
const world = m4.rotationY(time);
uniforms.u_viewProjection = viewProjection;
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, vertexArrayInfo);
twgl.setUniforms(programInfo, uniforms);
gl.drawElementsInstanced(gl.TRIANGLES, vertexArrayInfo.numElements, gl.UNSIGNED_SHORT, 0, numInstances);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://twgljs.org/dist/3.x/twgl-full.min.js"></script>
<canvas></canvas>