2d拖动寻转,平移,缩放

本文介绍了如何在HTML中利用WebGPUAPI创建一个可交互的示例,通过输入控制图形的平移、旋转和缩放,展示了WebGPU在浏览器中的图形性能和实时渲染能力。
摘要由CSDN通过智能技术生成

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

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>てst</title>
</head>

<body>
  <!-- canvas:用来展示WebGPU渲染的结果 -->
  <canvas id="webgpu" width="500" height="500"></canvas>
  translationx:<input type="range" min="0" max="500" step="0.1" name="translationx" value="230.2" /><br>
  translationy:<input type="range" min="0" max="500" step="0.1" name="translationy" value="230.2" /><br>
  rotation:<input type="range" min="0" max="360" step="0.1" name="rotation" value="0" /><br>
  scalex:<input type="range" min="-5" max="5" step="0.1" name="scalex" value="1.1" /><br>
  scaley:<input type="range" min="-5" max="5" step="0.1" name="scaley" value="1.1" /><br>

  <script type="module">
    //"C:\Program Files\Google\Chrome\Application\chrome.exe" --disable-web-security --user-data-dir="D:\angular\webgpu\n" --disable-site-isolation-trials

    import * as glMatrix from './dist/esm/index.js';

    function createTranVertices() {
      const vertexData = new Float32Array([
        100.0, 50, 0.0,
        50, 50, 0.0,
        50, 50, 0.0
      ]);

      return {
        vertexData,
        numVertices: 3,
      };
    }

    async function main() {
      const adapter = await navigator.gpu?.requestAdapter();
      const device = await adapter?.requestDevice();
      if (!device) {
        fail('need a browser that supports WebGPU');
        return;
      }

      // Get a WebGPU context from the canvas and configure it
      const canvas = document.querySelector('canvas');
      const context = canvas.getContext('webgpu');
      const presentationFormat = navigator.gpu.getPreferredCanvasFormat();

      context.configure({
        device,
        format: presentationFormat,
        alphaMode: 'premultiplied',
      });

      const module = device.createShaderModule({
        code: `
      struct Uniforms {
        color: vec4f,
        resolution: vec2f,
        matrix: mat3x3f,
      };

      struct Vertex {
        @location(0) position: vec2f,
      };

      struct VSOutput {
        @builtin(position) position: vec4f,
      };

      @group(0) @binding(0) var<uniform> uni: Uniforms;

      @vertex fn vs(vert: Vertex) -> VSOutput {
        var vsOut: VSOutput;

        // Multiply by a matrix
        let position = (uni.matrix * vec3f(vert.position, 1)).xy;

        // convert the position from pixels to a 0.0 to 1.0 value
        let zeroToOne = position / uni.resolution;

        // convert from 0 <-> 1 to 0 <-> 2
        let zeroToTwo = zeroToOne * 2.0;

        // covert from 0 <-> 2 to -1 <-> +1 (clip space)
        let flippedClipSpace = zeroToTwo - 1.0;

        // flip Y
        let clipSpace = flippedClipSpace * vec2f(1, -1);

        vsOut.position = vec4f(clipSpace, 0.0, 1.0);
        return vsOut;
      }

      @fragment fn fs(vsOut: VSOutput) -> @location(0) vec4f {
        return uni.color;
      }
    `
      });

      const pipeline = device.createRenderPipeline({
        label: 'just 2d position',
        layout: 'auto',
        vertex: {
          module,
          entryPoint: 'vs',
          buffers: [
            {
              arrayStride: (2) * 4, // (2) floats, 4 bytes each
              attributes: [
                { shaderLocation: 0, offset: 0, format: 'float32x2' },  // position
              ],
            },
          ],
        },
        fragment: {
          module,
          entryPoint: 'fs',
          targets: [{ format: presentationFormat }],
        },
      });

      // color, resolution, padding, matrix
      const uniformBufferSize = (4 + 2 + 2 + 12) * 4;
      const uniformBuffer = device.createBuffer({
        label: 'uniforms',
        size: uniformBufferSize,
        usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
      });

      const uniformValues = new Float32Array(uniformBufferSize / 4);

      // offsets to the various uniform values in float32 indices
      const kColorOffset = 0;
      const kResolutionOffset = 4;
      const kMatrixOffset = 8;

      const colorValue = uniformValues.subarray(kColorOffset, kColorOffset + 4);
      const resolutionValue = uniformValues.subarray(kResolutionOffset, kResolutionOffset + 2);
      const matrixValue = uniformValues.subarray(kMatrixOffset, kMatrixOffset + 12);

      // The color will not change so let's set it once at init time
      colorValue.set([Math.random(), Math.random(), Math.random(), 1]);

      const { vertexData, numVertices } = createTranVertices();
      const vertexBuffer = device.createBuffer({
        label: 'vertex buffer vertices',
        size: vertexData.byteLength,
        usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
      });
      device.queue.writeBuffer(vertexBuffer, 0, vertexData);

      const bindGroup = device.createBindGroup({
        label: 'bind group for object',
        layout: pipeline.getBindGroupLayout(0),
        entries: [
          { binding: 0, resource: { buffer: uniformBuffer } },
        ],
      });

      const renderPassDescriptor = {
        label: 'our basic canvas renderPass',
        colorAttachments: [
          {
            // view: <- to be filled out when we render
            loadOp: 'clear',
            storeOp: 'store',
          },
        ],
      };

      function render() {

        // Get the current texture from the canvas context and
        // set it as the texture to render to.
        renderPassDescriptor.colorAttachments[0].view =
          context.getCurrentTexture().createView();

        const encoder = device.createCommandEncoder();
        const pass = encoder.beginRenderPass(renderPassDescriptor);
        pass.setPipeline(pipeline);
        pass.setVertexBuffer(0, vertexBuffer);

        let translationx = document
          .querySelector('input[name="translationx"]')
          .value;
        let translationy = document
          .querySelector('input[name="translationy"]')
          .value;
        let rotation = document
          .querySelector('input[name="rotation"]')
          .value;
        rotation = rotation * Math.PI / 180;

        let scalex = document
          .querySelector('input[name="scalex"]')
          .value;
        let scaley = document
          .querySelector('input[name="scaley"]')
          .value;

        let translationMatrix = glMatrix.mat3.create();
        glMatrix.mat3.translate(translationMatrix, translationMatrix, glMatrix.vec2.fromValues(translationx, translationy));

        let rotationMatrix = glMatrix.mat3.create();
        //glMatrix.mat3.rotate(rotationMatrix, rotationMatrix, 1, glMatrix.vec3.fromValues(Math.sin(rotation), Math.cos(rotation), 0));
        glMatrix.mat3.rotate(rotationMatrix, rotationMatrix, rotation);

        let scaleMatrix = glMatrix.mat3.create();
        glMatrix.mat3.scale(scaleMatrix, scaleMatrix, [scalex, scaley, 1]);

        // make a matrix that will move the origin of the 'F' to its center.
        // const moveOriginMatrix = mat3.translation([-50, -75]);
        let moveOriginMatrix = glMatrix.mat3.create();
        glMatrix.mat3.translate(moveOriginMatrix, moveOriginMatrix, glMatrix.vec2.fromValues(-50, -70));

        let matrix = glMatrix.mat3.create();
        glMatrix.mat3.multiply(matrix, translationMatrix, rotationMatrix);

        glMatrix.mat3.multiply(matrix, matrix, scaleMatrix);

        // matrix = mat3.multiply(matrix, moveOriginMatrix);
        glMatrix.mat3.multiply(matrix, matrix, moveOriginMatrix);

        console.log('matrix:' + matrix);
        console.log('matrix0-3:' + matrix.slice(0, 3));
        console.log('matrixValue:' + matrixValue);

        // Set the uniform values in our JavaScript side Float32Array
        resolutionValue.set([canvas.width, canvas.height]);
        
        matrixValue.set([
          ...matrix.slice(0, 3), 0,
          ...matrix.slice(3, 6), 0,
          ...matrix.slice(6, 9), 0,
        ]);

        // upload the uniform values to the uniform buffer
        device.queue.writeBuffer(uniformBuffer, 0, uniformValues);

        pass.setBindGroup(0, bindGroup);
        // pass.drawIndexed(numVertices);
        pass.draw(3);
        pass.end();

        const commandBuffer = encoder.finish();
        device.queue.submit([commandBuffer]);
      }

      //-----------------
      document
        .querySelector('input[name="translationx"]')
        .addEventListener("input", (e) => {
          render();
        });

      document
        .querySelector('input[name="translationy"]')
        .addEventListener("input", (e) => {
          render();
        });
      document
        .querySelector('input[name="rotation"]')
        .addEventListener("input", (e) => {
          render();
        });
      document
        .querySelector('input[name="scalex"]')
        .addEventListener("input", (e) => {
          render();
        });
      document
        .querySelector('input[name="scaley"]')
        .addEventListener("input", (e) => {
          render();
        });

      const observer = new ResizeObserver(entries => {
        for (const entry of entries) {
          const canvas = entry.target;
          const width = entry.contentBoxSize[0].inlineSize;
          const height = entry.contentBoxSize[0].blockSize;
          canvas.width = Math.max(1, Math.min(width, device.limits.maxTextureDimension2D));
          canvas.height = Math.max(1, Math.min(height, device.limits.maxTextureDimension2D));
          // re-render
          render();
        }
      });
      observer.observe(canvas);
    }

    function fail(msg) {
      alert(msg);
    }

    main();
  </script>
</body>

</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值