|
| 1 | +// https://github.com/mrdoob/three.js/blob/master/examples/webgl_gpgpu_birds.html |
| 2 | +// http://web.engr.oregonstate.edu/~mjb/cs575/Handouts/opencl.opengl.vbo.1pp.pdf |
| 3 | +// https://developer.download.nvidia.com/compute/DevZone/docs/html/OpenCL/doc/OpenCL_Best_Practices_Guide.pdf |
| 4 | + |
| 5 | +import { readFileSync } from 'node:fs'; |
| 6 | +import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'; |
| 7 | +import cl from 'opencl-raub'; |
| 8 | +import { initCommon } from './utils/init-common.ts'; |
| 9 | +import { loopCommon } from './utils/loop-common.ts'; |
| 10 | +import { BirdMeshCl } from './cl/bird-mesh-cl.ts'; |
| 11 | +import { fillPositionAndPhase, fillVelocity } from './utils/fill-data.ts'; |
| 12 | + |
| 13 | +const BIRDS: number = 128 * 128; |
| 14 | +const BOUNDS: number = 800; |
| 15 | +const IS_PERF_MODE: boolean = true; |
| 16 | + |
| 17 | +const boidsSrc: string = readFileSync('cl/boids.cl').toString(); |
| 18 | +const { screen, doc, gl } = initCommon(IS_PERF_MODE, 'Boids CL'); |
| 19 | +const { platform, device } = cl.quickStart(!true); |
| 20 | + |
| 21 | +const context = cl.createContext( |
| 22 | + [ |
| 23 | + cl.GL_CONTEXT_KHR, doc.platformContext, |
| 24 | + cl.WGL_HDC_KHR, doc.platformDevice, |
| 25 | + cl.CONTEXT_PLATFORM, platform, |
| 26 | + ], |
| 27 | + [device], |
| 28 | +); |
| 29 | +const queue = cl.createCommandQueue(context, device); |
| 30 | + |
| 31 | +const birdMesh = new BirdMeshCl(BIRDS); |
| 32 | +screen.scene.add(birdMesh); |
| 33 | + |
| 34 | +const controls = new OrbitControls(screen.camera, doc as unknown as HTMLElement); |
| 35 | +controls.update(); |
| 36 | + |
| 37 | +const { offsets, velocity } = birdMesh.vbos; |
| 38 | +fillPositionAndPhase(offsets.array, BOUNDS); |
| 39 | +gl.bindBuffer(gl.ARRAY_BUFFER, offsets.vbo); |
| 40 | +gl.bufferData(gl.ARRAY_BUFFER, offsets.array, gl.STATIC_DRAW); |
| 41 | + |
| 42 | +fillVelocity(velocity.array); |
| 43 | +gl.bindBuffer(gl.ARRAY_BUFFER, velocity.vbo); |
| 44 | +gl.bufferData(gl.ARRAY_BUFFER, velocity.array, gl.STATIC_DRAW); |
| 45 | + |
| 46 | +const memPos = cl.createFromGLBuffer(context, cl.MEM_READ_WRITE, offsets.vbo._); |
| 47 | +const memVel = cl.createFromGLBuffer(context, cl.MEM_READ_WRITE, velocity.vbo._); |
| 48 | + |
| 49 | +cl.enqueueAcquireGLObjects(queue, memPos); |
| 50 | +cl.enqueueAcquireGLObjects(queue, memVel); |
| 51 | +cl.finish(queue); |
| 52 | + |
| 53 | +// Create a program object |
| 54 | +const program = cl.createProgramWithSource(context, boidsSrc); |
| 55 | +cl.buildProgram(program, [device], `-cl-fast-relaxed-math -cl-mad-enable`); |
| 56 | + |
| 57 | +const kernelUpdate = cl.createKernel(program, 'update'); |
| 58 | + |
| 59 | +const separation = 20.0; |
| 60 | +const alignment = 20.0; |
| 61 | +const cohesion = 20.0; |
| 62 | + |
| 63 | +cl.setKernelArg(kernelUpdate, 0, 'uint', BIRDS); |
| 64 | +cl.setKernelArg(kernelUpdate, 1, 'float', 0.016); // dynamic |
| 65 | +cl.setKernelArg(kernelUpdate, 2, 'float', BOUNDS); |
| 66 | +cl.setKernelArg(kernelUpdate, 3, 'float', -10000); // dynamic |
| 67 | +cl.setKernelArg(kernelUpdate, 4, 'float', -10000); // dynamic |
| 68 | +cl.setKernelArg(kernelUpdate, 5, 'float', separation); |
| 69 | +cl.setKernelArg(kernelUpdate, 6, 'float', alignment); |
| 70 | +cl.setKernelArg(kernelUpdate, 7, 'float', cohesion); |
| 71 | +cl.setKernelArg(kernelUpdate, 8, 'float*', memPos); |
| 72 | +cl.setKernelArg(kernelUpdate, 9, 'float*', memVel); |
| 73 | + |
| 74 | + |
| 75 | +loopCommon(IS_PERF_MODE, (_now, delta, mouse) => { |
| 76 | + controls.update(); |
| 77 | + |
| 78 | + cl.setKernelArg(kernelUpdate, 1, 'float', delta); |
| 79 | + cl.setKernelArg(kernelUpdate, 3, 'float', mouse[0] * BOUNDS); |
| 80 | + cl.setKernelArg(kernelUpdate, 4, 'float', mouse[1] * BOUNDS); |
| 81 | + |
| 82 | + gl.finish(); |
| 83 | + |
| 84 | + cl.enqueueNDRangeKernel(queue, kernelUpdate, 1, null, [BIRDS], [256]); |
| 85 | + |
| 86 | + cl.finish(queue); |
| 87 | + |
| 88 | + screen.draw(); |
| 89 | +}); |
0 commit comments