webgpu实现粒子颗粒化飘动动画效果代码

代码语言:html

所属分类:粒子

代码描述:webgpu实现粒子颗粒化飘动动画效果代码

代码标签: webgpu 粒子 颗粒化 飘动 动画

下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开

<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">

  
  
  
<style>
html,body {
  margin: 0;
  overflow: hidden;
}
canvas {
  width: 100%;
}
</style>


  
  
</head>

<body translate="no">
  <canvas></canvas>
  
      <script >
console.clear();

if (!navigator.gpu) {
  console.error("WebGPU not supported in this browser.");
  throw new Error("WebGPU not supported.");
}

async function initWebGPU() {
  const canvas = document.querySelector('canvas');
  const adapter = await navigator.gpu.requestAdapter();
  const device = await adapter.requestDevice();
  const context = canvas.getContext('webgpu');

  // Resize canvas to fit the window
  const dpi = 2;
  const resizeCanvas = () => {
    canvas.width = window.innerWidth * dpi;
    canvas.height = window.innerHeight * dpi;
  };
  resizeCanvas();
  window.addEventListener('resize', resizeCanvas);

  // Configure the canvas context
  const format = navigator.gpu.getPreferredCanvasFormat();
  context.configure({
    device: device,
    format: format,
    alphaMode: 'premultiplied' });


  return { device, context, format };
}
function createRenderLoop(device, context, positionBuffer, velocityBuffer, timeBuffer) {
  const shaderModule = createShaderModule(device);
  const pipeline = createRenderPipeline(device, shaderModule);

  const { computePipeline, bindGroup } = initComputePass(device, positionBuffer, velocityBuffer, timeBuffer);

  const renderBindGroupLayout = pipeline.getBindGroupLayout(0);
  const renderBindGroup = device.createBindGroup({
    layout: renderBindGroupLayout,
    entries: [{ binding: 0, resource: { buffer: positionBuffer } }] });


  let startTime = performance.now();

  const render = () => {
    const elapsedTime = (performance.now() - startTime) * .0001;
    device.queue.writeBuffer(timeBuffer, 0, new Float32Array([elapsedTime]));

    const commandEncoder = device.createCommandEncoder();

    // Compute Pass
    const computePass = commandEncoder.beginComputePass();
    computePass.setPipeline(computePipeline);
    computePass.setBindGroup(0, bindGroup);
    computePass.dispatchWorkgroups(Math.ceil(NUM_PARTICLES / 64));
    computePass.end();

    // Render Pass
    const textureView = context.getCurrentTexture().createView();
    const renderPassDescriptor = {
      colorAttachments: [{
        view: textureView,
        clearValue: { r: 0, g: 0, b: 0, a: 1 },
        loadOp: 'clear',
        storeOp: 'store' }] };



    const renderPass = commandEncoder.beginRenderPass(renderPassDescriptor);
    renderPass.setPipeline(pipeline);
    renderPass.setBindGroup(0, renderBindGroup);
    renderPass.draw(NUM_PARTICLES);
    renderPass.end();

    device.queue.submit([commandEncoder.finish()]);
    requestAnimationFrame(render);
  };

  render();
}


const NUM_PARTICLES = 2000000;
function generateParticleData() {
  const positions = new Float32Array(NUM_PARTICLES * 3);
  const velocities = new Float32Array(NUM_PARTICLES * 3);

  for (let i = 0; i < NUM_PARTICLES; i++) {
    // Random position in a cube [-1, 1]
    positions[i * 3 + 0] = Math.random() * 1 - .5; // x
    positions[i * 3 + 1] = Math.random() * 1 - .5; // y
    positions[i * 3 + 2] = Math.random() * 1 - .5; // z

    // Random velocity in range [-0.1, 0.1]
    velocities[i * 3 + 0] = Math.random() * 0.2 - 0.1; // vx
    velocities[i * 3 + 1] = Math.random() * 0.2 - 0.1; // vy
    velocities[i * 3 + 2] = Math.random() * 0.2 - 0.1; // vz
  }

  return { positions, velocities };
}
function createParticleBuffers(device, positions, velocities) {
  // Create position buffer
  const positionBuffer = device.createBuffer({
    size: positions.byteLength,
    usage: GPUBufferUsage.VERTEX | GPUBufferUsage.STORAGE,
    mappedAtCreation: true });

  new Float32Array(positionBuffer.getMappedRange()).set(positions);
  positionBuffer.unmap();

  // Create velocity buffer
  const velocityBuffer = device.createBuffer({
    size: velocities.byteLength,
    usage: GPUBufferUsage.STORAGE,
    mappedAtCreation: true });

  new Float32Array(velocityBuffer.getMappedRange()).set(velocities);
  velocityBuffer.unmap();

  return { positionBuffer, velocityBuffer };
}
async function initParticleSystem(device) {
  const { positions, velocities } = generateParticleData();
  const buffers = createParticleBuffers(device, positions, velocities);
  return buffers;
}

const shaderCode = `
    @group(0) @binding(0) var<storage, read> particlePositions: array<vec3<f32>>;
    
    struct VertexOutput {
      @builtin(position) position: vec4<f32>,
      @location(0) pos: vec3<f32>
    }

    @vertex
    fn vmain(@builtin(vertex_index) vertexIndex: u32) -> VertexOutput {
      var opt: VertexOutput;
        let position = particlePositions[vertexIndex];
        opt.position = vec4<f32>(position, 1.0);
        opt.pos = position;
        return opt;
    }

    @fragment
    fn fmain(input: VertexOutput) -> @location(0) vec4<f32> {
        return vec4<f32>(1, 1, 1, .5+.5*input.pos.z);
    }
`;
function createShaderModule(device) {
  return device.createShaderModule({
    code: shaderCode });

}
function createRenderPipeline(device, shaderModule) {
  return device.createRenderPipeline({
    layout: 'auto',
    vertex: {
      module: shaderModule,
      entryPoint: 'vmain' // Vertex shader entry point
    },
    fragment: {
      module: shaderModule,
      entryPoint: 'fmain', // Fragment shader entry point
      targets: [{
        format: 'bgra8unorm',
        blend: {
          color: {
            srcFactor: 'src-alpha',
            dstFactor: 'one-minus-src-alpha',
            operations: 'add' },

          alpha: {
            srcFactor: 'one',
            dstFactor: 'one-minus-src-alpha',
            operations: 'add' } } }] },




    primitive: {
      topology: 'point-list' // Render particles as points
    } });

}

const computeShaderCode = `
    @group(0) @binding(0) var<storage, read_write> particlePositions: array<vec3<f32>>;
    @group(0) @binding(1) var<storage, read_write> particleVelocities: array<vec3<f32>>;
    @group(0) @binding(2) var<uniform> time: f32;
    
    
    // https://www.pcg-random.org/
fn pcg(n: u32) -> u32 {
    var h = n * 747796405u + 2891336453u;
    h = ((h >> ((h >> 28u) + 4u)) ^ h) * 277803737u;
    return (h >> 22u) ^ .........完整代码请登录后点击上方下载按钮下载查看

网友评论0