import { Camera, Color, Geometry, GLTFLoader, Mesh, Program, Renderer, Transform } from 'ogl'; import { rand, randMinMax } from "./random"; import fragment from "./Leaf.frag"; import vertex from "./Leaf.vert"; let rotation = 0; export function setRotation(r: number) { rotation = r; } export function createLeaves({ canvas, num = 20, color, minZ = -1, maxZ = 1 }: { canvas: HTMLCanvasElement, num?: number, color?: Color, minZ?: number, maxZ?: number }) { const renderer = new Renderer({ dpr: 1, canvas, alpha: true }); const gl = renderer.gl; const camera = new Camera(gl, { fov: 15 }); camera.position.z = 5; function resize() { renderer.setSize(window.innerWidth, window.innerHeight); camera.perspective({ aspect: gl.canvas.width / gl.canvas.height }); } window.addEventListener('resize', resize, false); resize(); const scene = new Transform(); const program = new Program(gl, { vertex, fragment, cullFace: gl.NONE, depthTest: true, uniforms: { uTime: { value: 0 }, uRot: { value: 0 }, uBackground: { value: color }, }, }); let mesh: Mesh; loadModel(); async function loadModel() { const model = await GLTFLoader.load(gl, "/models/leaf.glb"); // @ts-ignore const data = model.nodes[0].children[0].geometry.attributes; let offset = new Float32Array(num * 3); let random = new Float32Array(num * 3); for (let i = 0; i < num; i++) { offset.set([rand(8), rand(4), randMinMax(minZ, maxZ)], 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(gl, { ...data, // simply add the 'instanced' property to flag as an instanced attribute. // set the value as the divisor number offset: { instanced: 1, size: 3, data: offset }, random: { instanced: 1, size: 3, data: random }, }); mesh = new Mesh(gl, { geometry, program }); mesh.scale.set(0.2, 0.2, 0.2) mesh.setParent(scene); } requestAnimationFrame(update); function update(t: number) { requestAnimationFrame(update); program.uniforms.uTime.value = t * 0.001; program.uniforms.uRot.value = rotation; renderer.render({ scene, camera }); } }