搜索
首页web前端js教程网络上的三角形 抓取一些东西

本系列介绍 WebGPU 和一般计算机图形学。

首先让我们看看我们要构建什么,

生命游戏

Triangles On Web Chraw Something

3D 渲染

Triangles On Web Chraw Something

3D 渲染,但有灯光

Triangles On Web Chraw Something

渲染 3D 模型

Triangles On Web Chraw Something

除了JS基础知识外,不需要任何基础知识。

教程已经在我的 github 上完成,附有源代码。

WebGPU 是一个相对较新的 GPU API。尽管名为 WebGPU,但它实际上可以被视为 Vulkan、DirectX 12、Metal、OpenGL 和 WebGL 之上的一层。它被设计为低级 API,旨在用于高性能应用程序,例如游戏和模拟。

在本章中,我们将在屏幕上绘制一些东西。第一部分将参考 Google Codelabs 教程。我们将在屏幕上创建一个生活游戏。

起点

我们将在启用 typescript 的 vite 中创建一个空的普通 JS 项目。然后清除所有多余的代码,只留下main.ts。

const main = async () => {
    console.log('Hello, world!')
}

main()

在实际编码之前,请检查您的浏览器是否启用了 WebGPU。您可以在 WebGPU Samples 上查看它。

Chrome 现在默认处于启用状态。在 Safari 上,您应该转到开发者设置、标记设置并启用 WebGPU。

我们还需要为 WebGPU 启用这些类型,安装 @webgpu/types,并在 tsc 编译器选项中添加 "types": ["@webgpu/types"]。

此外,我们替换了

画一个三角形

WebGPU 有很多样板代码,如下所示。

请求设备

首先我们需要访问 GPU。在WebGPU中,是通过适配器的概念来完成的,适配器是GPU和浏览器之间的桥梁。

const adapter = await navigator.gpu.requestAdapter();

然后我们需要向适配器请求一个设备。

const device = await adapter.requestDevice();
console.log(device);

配置画布

我们在画布上绘制三角形。我们需要获取canvas元素并配置它。

const canvas = document.getElementById('app') as HTMLCanvasElement;
const context = canvas.getContext("webgpu")!;
const canvasFormat = navigator.gpu.getPreferredCanvasFormat();
context.configure({
    device: device,
    format: canvasFormat,
});

这里,我们使用 getContext 来获取画布的相关信息。通过指定 webgpu,我们将获得一个负责使用 WebGPU 进行渲染的上下文。

CanvasFormat其实就是颜色模式,例如srgb。我们通常只使用首选格式。

最后,我们使用设备和格式配置上下文。

了解 GPU 渲染管线

在深入研究工程细节之前,我们首先必须了解 GPU 如何处理渲染。

GPU 渲染管道是 GPU 渲染图像所采取的一系列步骤。

在 GPU 上运行的应用程序称为着色器。着色器是运行在GPU上的程序。着色器有一种特殊的编程语言,我们稍后会讨论。

渲染管道有以下步骤,

  1. CPU 将数据加载到 GPU 中。 CPU可能会移除一些不可见的物体以节省GPU资源。
  2. CPU 设置 GPU 渲染场景所需的所有颜色、纹理和其他数据。
  3. CPU 触发对 GPU 的绘制调用。
  4. GPU从CPU获取数据并开始渲染场景。
  5. GPU 运行到几何进程,该进程处理场景的顶点。
  6. 在几何过程中,第一步是顶点着色器,它处理场景的顶点。它可能会变换顶点,改变顶点的颜色,或者对顶点做其他事情。
  7. 下一步是曲面细分着色器,它处理场景的顶点。它对顶点进行细分,其目的是增加场景的细节。它的程序也很多,但是太复杂了,无法在这里解释。
  8. 下一步是几何着色器,它处理场景的顶点。与顶点着色器相比,开发人员只能定义如何变换一个顶点,而几何着色器可以定义如何变换多个顶点。它还可以创建新的顶点,新的顶点可用于创建新的几何体。
  9. 几何处理的最后一步包括裁剪,去除超出屏幕的多余部分,以及剔除,去除相机不可见的不可见部分。
  10. 下一步是光栅化过程,将顶点转换为片段。片段是将要在屏幕上渲染的像素。
  11. 下一步是三角形迭代,即迭代场景的三角形。
  12. 下一步是片段着色器,它处理场景的片段。它可能会改变片段的颜色,改变片段的纹理,或者对片段做其他事情。在这一部分中,还进行了深度测试和模板测试。深度测试是指为每个片段赋予深度值,深度值最小的片段将被渲染。 Stencil测试是指为每个fragment赋予stencil值,通过stencil测试的fragment将被渲染。模板值由开发者决定。
  13. 下一步是混合过程,混合场景的片段。例如,如果两个片段重叠,则混合过程会将两个片段混合在一起。
  14. 最后一步是输出过程,将碎片输出到交换链。交换链是用于渲染场景的图像链。更简单地说,它是一个缓冲区,用于保存将要在屏幕上显示的图像。

根据图元(GPU 可以渲染的最小单位)的不同,管道可能有不同的步骤。通常,我们使用三角形,它通知 GPU 将每 3 组顶点视为一个三角形。

创建渲染通道

Render Pass 是完整 GPU 渲染的一个步骤。创建渲染通道后,GPU 将开始渲染场景,完成后反之亦然。

要创建渲染通道,我们需要创建一个编码器,负责将渲染通道编译为 GPU 代码。

const main = async () => {
    console.log('Hello, world!')
}

main()

然后我们创建一个渲染通道。

const adapter = await navigator.gpu.requestAdapter();

在这里,我们创建一个带有颜色附件的渲染通道。附件是 GPU 中的一个概念,表示将要渲染的图像。一张图像可能有很多个方面需要 GPU 处理,每个方面都是一个附件。

这里我们只有一个附件,就是颜色附件。视图是 GPU 将在其上渲染的面板,这里我们将其设置为画布的纹理。

loadOp是GPU在渲染通道之前执行的操作,clear表示GPU将首先清除最后一帧之前的所有数据,storeOp是GPU在渲染通道之后执行的操作,store表示GPU将把数据存储到纹理中。

loadOp可以是load,它保留最后一帧的数据,也可以是clear,它清除最后一帧的数据。 storeOp可以是store,将数据存储到纹理,也可以是discard,丢弃数据。

现在,只需调用 pass.end() 即可结束渲染通道。现在,该命令已保存在 GPU 的命令缓冲区中。

要获取编译后的命令,请使用以下代码,

const device = await adapter.requestDevice();
console.log(device);

最后,将命令提交到 GPU 的渲染队列。

const canvas = document.getElementById('app') as HTMLCanvasElement;
const context = canvas.getContext("webgpu")!;
const canvasFormat = navigator.gpu.getPreferredCanvasFormat();
context.configure({
    device: device,
    format: canvasFormat,
});

现在,您应该看到一个丑陋的黑色画布。

根据我们对 3D 的刻板印象,我们期望空白空间是蓝色的。我们可以通过设置透明颜色来做到这一点。

const encoder = device.createCommandEncoder();

使用着色器绘制三角形

现在,我们将在画布上绘制一个三角形。我们将使用着色器来做到这一点。着色器语言将是 wgsl,WebGPU 着色语言。

现在,假设我们要绘制一个具有以下坐标的三角形,

const pass = encoder.beginRenderPass({
  colorAttachments: [{
     view: context.getCurrentTexture().createView(),
     loadOp: "clear",
     storeOp: "store",
  }]
});

正如我们之前所说,要完成渲染管道,我们需要一个顶点着色器和一个片段着色器。

顶点着色器

使用以下代码创建着色器模块。

const commandBuffer = encoder.finish();

这里的label只是一个名称,用于调试。 code 是实际的着色器代码。

顶点着色器是一个接受任意参数并返回顶点位置的函数。然而,与我们的预期相反,顶点着色器返回一个四维向量,而不是一个三维向量。第四个维度是w维度,用于透视划分。我们稍后再讨论。

现在,您可以简单地将四维向量 (x, y, z, w) 视为三维向量 (x / w, y / w, z / w)。

但是,还有一个问题——如何将数据传递给着色器,以及如何从着色器中取出数据。

为了将数据传递给着色器,我们使用 vertexBuffer,一个包含顶点数据的缓冲区。我们可以使用以下代码创建一个缓冲区,

const main = async () => {
    console.log('Hello, world!')
}

main()

这里我们创建了一个缓冲区,大小为24字节,6个浮点数,这是顶点的大小。

usage是缓冲区的使用情况,对于顶点数据来说就是VERTEX。 GPUBufferUsage.COPY_DST 表示该缓冲区可作为复制目标。对于所有由CPU写入数据的缓冲区,我们需要设置这个标志。

这里的map是指将buffer映射到CPU,也就是说CPU可以对buffer进行读写操作。 unmap的意思是取消缓冲区的映射,这意味着CPU不能再读写缓冲区,因此内容可供GPU使用。

现在,我们可以将数据写入缓冲区。

const adapter = await navigator.gpu.requestAdapter();

这里,我们将缓冲区映射到CPU,并将数据写入缓冲区。然后我们取消映射缓冲区。

vertexBuffer.getMappedRange() 将返回映射到 CPU 的缓冲区范围。我们可以用它来将数据写入缓冲区。

但是,这些只是原始数据,GPU 不知道如何解释它们。我们需要定义缓冲区的布局。

const device = await adapter.requestDevice();
console.log(device);

这里,arrayStride是GPU在寻找下一个输入时需要在缓冲区中向前跳过的字节数。例如,如果 arrayStride 为 8,GPU 将跳过 8 个字节来获取下一个输入。

由于这里我们使用float32x2,步幅是8个字节,每个float 4个字节,每个顶点2个float。

现在我们可以编写顶点着色器了。

const canvas = document.getElementById('app') as HTMLCanvasElement;
const context = canvas.getContext("webgpu")!;
const canvasFormat = navigator.gpu.getPreferredCanvasFormat();
context.configure({
    device: device,
    format: canvasFormat,
});

这里,@vertex 表示这是一个顶点着色器。 @location(0) 表示属性的位置,如前面定义的那样,为 0。请注意,在着色器语言中,您正在处理缓冲区的布局,因此每当您传递一个值时,您需要传递一个结构体,其字段已定义@location,或者仅传递一个带有@location的值。

vec2f 是二维浮点向量,vec4f 是四维浮点向量。由于顶点着色器需要返回 vec4f 位置,因此我们需要使用 @builtin(position) 对其进行注释。

片段着色器

片段着色器,类似地,是获取插值顶点输出并输出附件(在本例中为颜色)的东西。插值意味着虽然只有顶点上的某些像素具有确定的值,但对于每隔一个像素,这些值都会被插值,可以是线性的、平均的或其他方式。 fragment的颜色是一个四维向量,即fragment的颜色,分别是红、绿、蓝、alpha。

请注意,颜色的范围是0到1,而不是0到255。此外,片段着色器定义的是每个顶点的颜色,而不是三角形的颜色。三角形的颜色由顶点的颜色通过插值确定。

由于我们目前不想控制片段的颜色,所以我们可以简单地返回一个常量颜色。

const main = async () => {
    console.log('Hello, world!')
}

main()

渲染管线

然后我们通过替换顶点和片段着色器来定义自定义渲染管道。

const adapter = await navigator.gpu.requestAdapter();

注意,在片段着色器中,我们需要指定目标的格式,也就是画布的格式。

抽奖

在渲染过程结束之前,我们添加绘制调用。

const device = await adapter.requestDevice();
console.log(device);

这里,在setVertexBuffer中,第一个参数是缓冲区的索引,在管道定义字段buffers中,第二个参数是缓冲区本身。

调用draw时,参数是要绘制的顶点数。由于我们有 3 个顶点,因此我们绘制 3 个。

现在,您应该在画布上看到一个黄色三角形。

绘制生命游戏细胞

现在我们稍微调整一下代码 - 因为我们想要构建一个生活游戏,所以我们需要绘制正方形而不是三角形。

正方形实际上是两个三角形,所以我们需要画6个顶点。这里的改动很简单,不需要详细解释。

const canvas = document.getElementById('app') as HTMLCanvasElement;
const context = canvas.getContext("webgpu")!;
const canvasFormat = navigator.gpu.getPreferredCanvasFormat();
context.configure({
    device: device,
    format: canvasFormat,
});

现在,您应该在画布上看到一个黄色方块。

坐标系

我们没有讨论GPU的坐标系。嗯,这相当简单。 GPU实际的坐标系是右手坐标系,即x轴指向右侧,y轴指向上方,z轴指向屏幕外。

坐标系的范围是-1到1。原点位于屏幕中心。 z轴从0到1,0是近平面,1是远平面。然而,z 轴代表深度。当你做3D渲染时,你不能仅仅使用z轴来确定物体的位置,你需要使用透视划分。这称为 NDC,标准化设备坐标。

例如,要在屏幕左上角画一个正方形,顶点为 (-1, 1), (-1, 0), (0, 1), (0, 0) ,尽管你需要使用两个三角形来绘制它。

以上是网络上的三角形 抓取一些东西的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
JavaScript应用程序:从前端到后端JavaScript应用程序:从前端到后端May 04, 2025 am 12:12 AM

JavaScript可用于前端和后端开发。前端通过DOM操作增强用户体验,后端通过Node.js处理服务器任务。1.前端示例:改变网页文本内容。2.后端示例:创建Node.js服务器。

Python vs. JavaScript:您应该学到哪种语言?Python vs. JavaScript:您应该学到哪种语言?May 03, 2025 am 12:10 AM

选择Python还是JavaScript应基于职业发展、学习曲线和生态系统:1)职业发展:Python适合数据科学和后端开发,JavaScript适合前端和全栈开发。2)学习曲线:Python语法简洁,适合初学者;JavaScript语法灵活。3)生态系统:Python有丰富的科学计算库,JavaScript有强大的前端框架。

JavaScript框架:为现代网络开发提供动力JavaScript框架:为现代网络开发提供动力May 02, 2025 am 12:04 AM

JavaScript框架的强大之处在于简化开发、提升用户体验和应用性能。选择框架时应考虑:1.项目规模和复杂度,2.团队经验,3.生态系统和社区支持。

JavaScript,C和浏览器之间的关系JavaScript,C和浏览器之间的关系May 01, 2025 am 12:06 AM

引言我知道你可能会觉得奇怪,JavaScript、C 和浏览器之间到底有什么关系?它们之间看似毫无关联,但实际上,它们在现代网络开发中扮演着非常重要的角色。今天我们就来深入探讨一下这三者之间的紧密联系。通过这篇文章,你将了解到JavaScript如何在浏览器中运行,C 在浏览器引擎中的作用,以及它们如何共同推动网页的渲染和交互。JavaScript与浏览器的关系我们都知道,JavaScript是前端开发的核心语言,它直接在浏览器中运行,让网页变得生动有趣。你是否曾经想过,为什么JavaScr

node.js流带打字稿node.js流带打字稿Apr 30, 2025 am 08:22 AM

Node.js擅长于高效I/O,这在很大程度上要归功于流。 流媒体汇总处理数据,避免内存过载 - 大型文件,网络任务和实时应用程序的理想。将流与打字稿的类型安全结合起来创建POWE

Python vs. JavaScript:性能和效率注意事项Python vs. JavaScript:性能和效率注意事项Apr 30, 2025 am 12:08 AM

Python和JavaScript在性能和效率方面的差异主要体现在:1)Python作为解释型语言,运行速度较慢,但开发效率高,适合快速原型开发;2)JavaScript在浏览器中受限于单线程,但在Node.js中可利用多线程和异步I/O提升性能,两者在实际项目中各有优势。

JavaScript的起源:探索其实施语言JavaScript的起源:探索其实施语言Apr 29, 2025 am 12:51 AM

JavaScript起源于1995年,由布兰登·艾克创造,实现语言为C语言。1.C语言为JavaScript提供了高性能和系统级编程能力。2.JavaScript的内存管理和性能优化依赖于C语言。3.C语言的跨平台特性帮助JavaScript在不同操作系统上高效运行。

幕后:什么语言能力JavaScript?幕后:什么语言能力JavaScript?Apr 28, 2025 am 12:01 AM

JavaScript在浏览器和Node.js环境中运行,依赖JavaScript引擎解析和执行代码。1)解析阶段生成抽象语法树(AST);2)编译阶段将AST转换为字节码或机器码;3)执行阶段执行编译后的代码。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具

SublimeText3 英文版

SublimeText3 英文版

推荐:为Win版本,支持代码提示!

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版