In this tutorial, we'll work through how to do instanced drawing with luma.gl's mid-level APIs. This will involve using luma.gl's WebGL wrappers to do the drawing instead of the higher-level Model
. We'll start from the high-level app we created. First we need to install the shadertools
module so we can compose shaders without the Model
class:
npm i @luma.gl/shadertools
Now we can update the imports:
import {AnimationLoop} from '@luma.gl/engine';
import {Program, VertexArray, Buffer, clear} from '@luma.gl/webgl';
import {assembleShaders} from '@luma.gl/shadertools';
Most of the initialization is similar, but we'll replace the creation of Model
with its individual parts: shader composition, a vertex array, and a program. Shader composition is handled by assembleShaders
const assembled = assembleShaders(gl, {
vs,
fs,
modules: [colorShaderModule]
});
We can then use the assembled shaders to create a Program
:
const program = new Program(gl, assembled);
The attributes for the draw are managed by a VertexArray
:
const vertexArray = new VertexArray(gl, {
program,
attributes: {
position: positionBuffer,
color: [colorBuffer, {divisor: 1}],
offset: [offsetBuffer, {divisor: 1}]
}
});
The VertexArray
takes the program
as an argument to infer attribute parameters.
The vertexArray
and program
are required for drawing, so we'll return them from onInitialize
, and then use them in onRender
:
onInitialize({gl}) {
// Setup...
return {program, vertexArray};
}
onRender({gl, program, vertexArray}) {
clear(gl, {color: [0, 0, 0, 1]});
program.draw({
vertexArray,
vertexCount: 3,
instanceCount: 4
});
}
The scene should be identical to the one draw with the high-level API. See the live demo here.
The complete app is as follows:
import {AnimationLoop} from '@luma.gl/engine';
import {Program, VertexArray, Buffer, clear} from '@luma.gl/webgl';
import {assembleShaders} from '@luma.gl/shadertools';
const colorShaderModule = {
name: 'color',
vs: `
varying vec3 color_vColor;
void color_setColor(vec3 color) {
color_vColor = color;
}
`,
fs: `
varying vec3 color_vColor;
vec3 color_getColor() {
return color_vColor;
}
`
};
const loop = new AnimationLoop({
onInitialize({gl}) {
const positionBuffer = new Buffer(gl, new Float32Array([-0.2, -0.2, 0.2, -0.2, 0.0, 0.2]));
const colorBuffer = new Buffer(
gl,
new Float32Array([1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0])
);
const offsetBuffer = new Buffer(
gl,
new Float32Array([0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5])
);
const vs = `
attribute vec2 position;
attribute vec3 color;
attribute vec2 offset;
void main() {
color_setColor(color);
gl_Position = vec4(position + offset, 0.0, 1.0);
}
`;
const fs = `
void main() {
gl_FragColor = vec4(color_getColor(), 1.0);
}
`;
const assembled = assembleShaders(gl, {
vs,
fs,
modules: [colorShaderModule]
});
const program = new Program(gl, assembled);
const vertexArray = new VertexArray(gl, {
program,
attributes: {
position: positionBuffer,
color: [colorBuffer, {divisor: 1}],
offset: [offsetBuffer, {divisor: 1}]
}
});
return {program, vertexArray};
},
onRender({gl, program, vertexArray}) {
clear(gl, {color: [0, 0, 0, 1]});
program.draw({
vertexArray,
vertexCount: 3,
instanceCount: 4
});
}
});
loop.start();