9. WebGPU 平移变换

news2024/11/18 10:26:07

我们将开始编写与顶点缓冲区文章中的示例类似的代码,但这次将绘制单个 F 而不是一堆圆,并使用索引缓冲区来保持数据更小。

让我们在像素空间而不是裁剪空间中工作,就像 Canvas 2D API 我们将制作一个 F,将从 6 个三角形构建它
在这里插入图片描述

这是 F 的数据

function createFVertices() {
  const vertexData = new Float32Array([
    // left column
    0 ,   0, //0
    30,   0, //1
    0 , 150, //2
    30, 150, //3
 
    // top rung
    30 ,  0, //4
    100,  0, //5
    30 , 30, //6
    100, 30, //7
 
    // middle rung
    30, 60,  //8
    70, 60,  //9
    30, 90,  //10
    70, 90,  //11
  ]);
 
  const indexData = new Uint32Array([
    0,  1,  2,    2,  1,  3,  // left column
    4,  5,  6,    6,  5,  7,  // top run
    8,  9, 10,   10,  9, 11,  // middle run
  ]);
 
  return {
    vertexData,
    indexData,
    numVertices: indexData.length,
  };
}

上面的顶点数据在像素空间中,因此需要将其转换为裁剪空间。可以通过将分辨率传递给着色器并进行一些数学运算来做到这一点。下边是操作步骤。

struct Uniforms {
  color: vec4f,
  resolution: vec2f,
};
 
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;
  
  let position = vert.position;
 
  // 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;
}

使用顶点位置并将其除以分辨率。这给了一个在画布上从 0 到 1 的值。然后乘以 2 以获得画布上从 0 到 2 的值。然后减去 1。现在我们的值在裁剪空间中,但它被翻转了,因为裁剪空间向上 Y 正向,而画布 2d 向下 Y 正向。所以将 Y 乘以 -1 来翻转它。现在有了所需的裁剪空间值,可以从着色器中输出它。

现在只有一个属性,所以渲染管线看起来像这样

  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 }],
    },
  });

需要为uniforms设置一个缓冲区

  // color, resolution, padding
  const uniformBufferSize = (4 + 2) * 4 + 8;
  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 colorValue = uniformValues.subarray(kColorOffset, kColorOffset + 4);
  const resolutionValue = uniformValues.subarray(kResolutionOffset, kResolutionOffset + 2);
 
  // The color will not change so let's set it once at init time
  colorValue.set([Math.random(), Math.random(), Math.random(), 1]);

在渲染时需要设置分辨率

  function render() {
    ...
 
    // Set the uniform values in our JavaScript side Float32Array
    resolutionValue.set([canvas.width, canvas.height]);
 
    // upload the uniform values to the uniform buffer
    device.queue.writeBuffer(uniformBuffer, 0, uniformValues);

Before we run it lets make the background of the canvas look like graph paper. We’ll set it’s scale so each grid cell of the graph paper is 10x10 pixels and every 100x100 pixels we’ll draw a bolder line.

在运行它之前,需要让画布的背景看起来像方格纸。将设置它的比例,使方格纸的每个网格单元为 10x10 像素,且每 100x100 像素我们将绘制一条粗线。效果图如下
在这里插入图片描述

:root {
  --bg-color: #fff;
  --line-color-1: #AAA;
  --line-color-2: #DDD;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg-color: #000;
    --line-color-1: #666;
    --line-color-2: #333;
  }
}
canvas {
  display: block;  /* make the canvas act like a block   */
  width: 100%;     /* make the canvas fill its container */
  height: 100%;
  background-color: var(--bg-color);
  background-image: linear-gradient(var(--line-color-1) 1.5px, transparent 1.5px),
      linear-gradient(90deg, var(--line-color-1) 1.5px, transparent 1.5px),
      linear-gradient(var(--line-color-2) 1px, transparent 1px),
      linear-gradient(90deg, var(--line-color-2) 1px, transparent 1px);
  background-position: -1.5px -1.5px, -1.5px -1.5px, -1px -1px, -1px -1px;
  background-size: 100px 100px, 100px 100px, 10px 10px, 10px 10px;  
}

上面的 CSS 应该处理浅色和深色情况。

到目前为止,所有的示例都使用了不透明的画布。为了使其透明,以便可以看到刚刚设置的背景,需要进行一些更改。

首先需要在配置画布为 ‘premultiplied’ 时设置 alphaMode 。它默认为 ‘opaque’ 。

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

然后需要在 GPURenderPassDescriptor 中将画布清除为 0, 0, 0, 0。因为默认的 clearValue 是 0, 0, 0, 0 可以删除将它设置为其他内容。

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

有了这个,这是F的显示结果

在这里插入图片描述

注意 F 相对于它后面的网格的大小。 F 数据的顶点位置使 F 宽 100 像素,高 150 像素,与我们显示的相匹配。 F 从 0,0 开始,向右延伸到 100,0,向下延伸到 0,150

现在已经有了基础,让我们添加平移变换。

Translation is just the process of moving things so all we need to do is add translation to our uniforms and add that to our position
平移变换只是移动事物的过程,所以需要做的就是将平移添加到我们的uniforms 并将其与位置相加

struct Uniforms {
  color: vec4f,
  resolution: vec2f,
  translation: vec2f, //here
};
 
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;
  
  // Add in the translation
  //let position = vert.position;
  let position = vert.position + uni.translation;
 
  // 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;
}

需要为uniforms 缓冲区增加空间

  // color, resolution, padding
  //const uniformBufferSize = (4 + 2) * 4 + 8;
  // color, resolution, translation
  const uniformBufferSize = (4 + 2 + 2) * 4; //here
  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 kTranslationOffset = 6; //here
 
  const colorValue = uniformValues.subarray(kColorOffset, kColorOffset + 4);
  const resolutionValue = uniformValues.subarray(kResolutionOffset, kResolutionOffset + 2);
  const translationValue = uniformValues.subarray(kTranslationOffset, kTranslationOffset + 2); //here

然后需要在渲染时设置平移

  const settings = {
    translation: [0, 0],
  };
 
  function render() {
    ...
 
    // Set the uniform values in our JavaScript side Float32Array
    resolutionValue.set([canvas.width, canvas.height]);
    translationValue.set(settings.translation);//here
 
    // upload the uniform values to the uniform buffer
    device.queue.writeBuffer(uniformBuffer, 0, uniformValues);

最后添加一个 UI,这样就可以调整平移距离

import GUI from '/3rdparty/muigui-0.x.module.js';
 
...
  const settings = {
    translation: [0, 0],
  };
 
  const gui = new GUI();
  gui.onChange(render);
  gui.add(settings.translation, '0', 0, 1000).name('translation.x');
  gui.add(settings.translation, '1', 0, 1000).name('translation.y');

现在添加了平移

在这里插入图片描述

请注意它与我们的像素网格相匹配。如果我们将平移设置为 200,300,则绘制 F 时其 0,0 左上角顶点位于 200,300。

这篇文章可能看起来非常简单。尽管我们将其命名为“offset”,但之前已经在几个示例中使用了平移。本文是系列文章的一部分。虽然它很简单,但希望它的要点在我们继续本系列的上下文中有意义。

接下来是旋转。

原文地址

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/641777.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

高级 IO(select poll epoll)

目录 五种IO模型 阻塞IO 非阻塞IO 信号驱动IO IO多路转接 ​异步IO 小结 同步通信 vs 异步通信(synchronous communication/ asynchronous communication) 同步和异步关注的是消息通信机制 阻塞 vs 非阻塞 其他高级IO 非阻塞IO fcntl 实现函数SetNoBlock I/O…

Windows Server AD域控服务器升级/迁移(AD域控的五大角色转移)

Windows Server AD域控服务器升级/迁移&#xff08;AD域控的五大角色转移&#xff09; 新域控服务器安装配置域控服务器&#xff0c;加入现有域域控角色迁移到新域控服务器原域控服务器降级退域 本文主要介绍在现有域环境下如何进行域控服务器的迁移/升级操作。对于域结构的网络…

python自动化测试框架:unittest测试用例编写及执行

本文将介绍 unittest 自动化测试用例编写及执行的相关内容&#xff0c;包括测试用例编写、测试用例执行、测试报告等内容。 官方文档&#xff1a; https://docs.python.org/zh-cn/3/library/unittest.mock.html 1. 测试用例编写 在 unittest 中&#xff0c;一个测试用例通常…

【二等奖方案】系统访问风险识别「QDU」团队解题思路

第十届CCF大数据与计算智能大赛&#xff08;2022 CCF BDCI&#xff09;已圆满结束。大赛官方竞赛平台DataFountain&#xff08;简称DF平台,官号统称DataFountain 或DataFountain数据科学&#xff09;正在陆续释出各赛题获奖队伍的方案思路。 本方案为【系统访问风险识别】赛题…

精选个人创业计划

精选个人创业计划精选篇1 一、企业概况 以突出“新鲜”“精致”为主要特色。坐落于河北区昆纬路的一个小店&#xff0c;主营鲜花与礼品的零售。它没有亮丽的装潢设计&#xff0c;而是着重朴实的风格&#xff0c;突出了产品的“精”与“美”&#xff0c;成为人们五彩斑斓生活中不…

五年磨一剑——Sealos 云操作系统正式发布!

这是个宏伟的计划 这是一个宏伟的计划&#xff0c;漫长且有趣。 2018 年的某个夜晚&#xff0c;夜深人静&#xff0c;我挥舞键盘&#xff0c;敲下了 Sealos 的第一行代码。当时仓库命名为 “kubeinit”&#xff0c;后来觉得格局太小&#xff0c;我不可能只做一个安装 Kuberne…

2023.6.8-TS-yum update集群后奔溃故障(已解决)

2023.6.8-TS-yum update集群后奔溃故障(已解决) 1、故障背景 自己在安装falco软件时&#xff0c;使用yum update升级了系统后&#xff0c;就出现这个情况了。。。 2、报错现象 kubeclt无法查看pod kubectl get poE0608 09:38:49.094714 2268 memcache.go:265] couldnt ge…

【沐风老师】3dMax一键多边形门(PolyDoor)、窗(PolyWindow)插件使用方法详解

3dMax一键多边形门、窗插件使用教程 3dMax一键多边形门&#xff08;PolyDoor&#xff09;、窗&#xff08;PolyWindow&#xff09;插件&#xff0c;将选择的多边形面一键转化为门、窗模型。你可以通过编辑多边形的线框&#xff08;边&#xff09;来定义门、窗的样式&#xff0…

【备战秋招】每日一题:4月23日美团春招:题面+题目思路 + C++/python/js/Go/java带注释

2023大厂笔试模拟练习网站&#xff08;含题解&#xff09; www.codefun2000.com 最近我们一直在将收集到的各种大厂笔试的解题思路还原成题目并制作数据&#xff0c;挂载到我们的OJ上&#xff0c;供大家学习交流&#xff0c;体会笔试难度。现已录入200道互联网大厂模拟练习题&a…

Stable Diffusion WebUI 环境

Stable Diffusion 是热门的文本到图像的生成扩散模型&#xff0c;本文介绍了如何准备其 WebUI 环境。 Stability AI Stability API Extension for Automatic1111 WebUI Stable Diffusion web UI 环境基础 OS: Ubuntu 22.04.2 LTSKernel: 5.19.0CPU: AMD Ryzen 7 3700XGPU: N…

Docker六脉神剑 - Mac极速体验

说到Docker, 现在可是"家喻户晓"。但是随着Docker的生态越来越强大, 资料越来越多, 反而对新手越来越不友好, 好多人准备学习一下, 但是又不知从哪入手&#xff1f; 想要玩Docker, 首先要先明白, Docker是干嘛的&#xff1f;可以解决什么问题&#xff1f;使用Docker可…

Linux中的用户和组的分类

目录 Linux中的用户和组的分类 用户分类 超级用户 系统用户 普通用户 组的分类 基本组&#xff08;私有组&#xff09; 附加组&#xff08;公有组&#xff09; 系统组 Linux中用户和用户组的配置文件 在Linux中&#xff0c;用户账号、密码、用户组信息和用户组密码均…

【滤波】无迹卡尔曼滤波

本文主要翻译自rlabbe/Kalman-and-Bayesian-Filters-in-Python的第10章节10-Unscented-Kalman-Filter&#xff08;无迹卡尔曼滤波&#xff09;。 %matplotlib inline# format the book import book_format book_format.set_style()前文 在上一章中&#xff0c;我们讨论了非线…

Elasticsearch:使用 ELSER 进行语义搜索

Elastic Learned Sparse EncodeR&#xff08;或 ELSER&#xff09;是一种由 Elastic 训练的 NLP 模型&#xff0c;使你能够使用稀疏向量表示来执行语义搜索。 语义搜索不是根据搜索词进行字面匹配&#xff0c;而是根据搜索查询的意图和上下文含义检索结果。 本教程中的说明向你…

【QQ界面展示-设置背景图拉伸方式 Objective-C语言】

一、接下来,我们就给大家设一下这个正文的背景图 1.因为我们现在,我们现在看一下, 在我们这个示例程序里面,正文,根据时你发的消息,还是对方发的消息,正文这个背景图,是不一样的, 所以说,这个正文的背景图,也要根据数据来判断, 判断数据里面那个类型是对方,还是…

端口隔离是什么?为什么需要端口隔离、如何实现端口隔离?

目录 一. 什么是端口隔离 二. 为什么需要端口隔离 三. 端口隔离的原理 1. 硬件隔离 2. 软件隔离 四. 端口隔离的实现方法 1. VLAN 2. 网络隔离 3. 防火墙 五. VLAN端口隔离 1. VLAN端口隔离方式 2. VLAN端口隔离配置案例 3. VLAN 端口隔离的注意事项 六. 端口隔离…

【数据库】Mysql数据库初体验

文章目录 一、数据库基本概念1. 数据 (Data)的概念2. 表的概念3. 数据库的概念4. 数据库管理系统5. 数据库系统 二、 数据库的发展1. 第一代数据库2. 第二代数据库3. 第三代数据库 三、主流的数据库介绍1. SQL Server&#xff08;微软公司产品&#xff09;2. Oracle &#xff0…

35. QT中执行linux命令或者shell脚本

1. 说明 Qt在linux系统中进行软件开发时,有时需要通过qt调用命令行终端执行一些命令,可以比较快速方便的实现某些功能。在qt中调用命令行终端,相当于启动了另外一个应用程序,此时可以借助Qt提供的辅助类QProcess来实现,当然也有其它的实现方式,因为QProcess使用有很多优…

pytest自动化测试框架基础篇

目录 前言&#xff1a; 一、单元测试框架 二、pytest简介以及常用插件安装 三、pytest默认测试用例的规则以及基础应用 四、pytest跳过测试用例 五、pytest测试用例的前后置&#xff0c;固件 前言&#xff1a; pytest是一个基于Python语言的自动化测试框架&#xff0c;它…

声网云市场 —— 实时互动开发者的 API 商店

声网云市场是面向实时互动开发者的 API 商店&#xff0c;让开发者在使用声网 RTC 的同时&#xff0c;可以快速集成实时互动扩展能力&#xff0c;比如美颜、变声、语音转文字、实时翻译、视频审核、语音审核等等&#xff0c;让开发者专注在业务逻辑和用户体验上&#xff0c;免去…