Draw instance
这个实例主要展示了引擎实例化渲染如何使用。
一个简单的示例
Result
Loading...
Live Editor
function render(props) { const drawModelVertex = ` attribute vec2 uv; attribute vec3 position; // Add instanced attributes just like any attribute attribute vec3 offset; attribute vec3 random; uniform mat4 modelViewMatrix; uniform mat4 projectionMatrix; uniform float uTime; varying vec2 vUv; varying vec3 vNormal; void rotate2d(inout vec2 v, float a){ mat2 m = mat2(cos(a), -sin(a), sin(a), cos(a)); v = m * v; } void main() { vUv = uv; // copy position so that we can modify the instances vec3 pos = position; // scale first pos *= 0.9 + random.y * 0.2; // rotate around y axis rotate2d(pos.xz, random.x * 6.28 + 4.0 * uTime * (random.y - 0.5)); // rotate around x axis just to add some extra variation rotate2d(pos.zy, random.z * 0.5 * sin(uTime * random.x + random.z * 3.14)); pos += offset; gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0); } `; const drawModelFragment = ` precision highp float; uniform float uTime; uniform sampler2D tMap; varying vec2 vUv; void main() { vec3 tex = texture2D(tMap, vUv).rgb; gl_FragColor.rgb = tex; gl_FragColor.a = 1.0; } `; const refDom = useRef(null); const store = leva.useCreateStore(); const fov = 15; const nearZ = 0.1; const farZ = 100; // const { name, aNumber } = leva.useControls({ name: 'World1', aNumber: 2 }, { store }); const image = useBaseUrl('/assets/acorn.jpg'); const json = useBaseUrl('/assets/acorn.json'); const init = () => { const canvas = refDom.current; canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; const renderer = new Renderer(canvas, { alpha: true, }); const camera = new PerspectiveCamera(fov, canvas.width / canvas.height, nearZ, farZ); camera.position.z = 15; function resize(target) { const { width, height } = target.getBoundingClientRect(); renderer.setSize(width, height); camera.aspect = width / height; } const scene = new Scene(); const texture = new Texture(renderer, { flipY: true, }); texture.fromSrc(image); const program = new Program(renderer, { vertexShader: drawModelVertex, fragmentShader: drawModelFragment, uniforms: { uTime: { value: 0 }, tMap: { value: texture }, }, cullFace: renderer.gl.BACK, }); const num = 60; fetch(json).then(res => res.json()).then((data) => { let offset = new Float32Array(num * 3); let random = new Float32Array(num * 3); for (let i = 0; i < num; i++) { offset.set([Math.random() * 2 - 1, Math.random() * 2 - 1, Math.random() * 2 - 1], i * 3); // unique random values are always handy for instances. // Here they will be used for rotation, scale and movement. random.set([Math.random(), Math.random(), Math.random()], i * 3); } const geometry = new Geometry(renderer, { position: { size: 3, data: new Float32Array(data.position) }, uv: { size: 2, data: new Float32Array(data.uv) }, normal: { size: 3, data: new Float32Array(data.normal) }, // simply add the 'instanced' property to flag as an instanced attribute. // set the value as the divisor number offset: { divisor: 1, size: 3, data: offset }, random: { divisor: 1, size: 3, data: random }, }); const mesh = new Mesh(renderer, { mode: renderer.gl.TRIANGLES, geometry, program }); mesh.setParent(scene); const raf = new Raf((t) => { if (mesh) mesh.rotation.y -= 0.005; program.setUniform('uTime', t) renderer.render({ scene, camera }); }); }); return { canvas, resize, } } useEffect(() => { const { canvas, resize } = init(); observe(canvas, resize); return () => { unobserve(canvas, resize); }; }, []); return ( <div className="live-wrap"> <div className="leva-wrap"> <Leva fill ></Leva> <LevaPanel store={store} fill></LevaPanel> </div> <canvas className="scene-canvas" ref={refDom}></canvas> </div> ); }