WebGPU:使用 Triangle Strip 为每个三角形绘制不同颜色

webgpu:使用 triangle strip 为每个三角形绘制不同颜色

本文介绍了如何在 WebGPU 中使用 `triangle-strip` 拓扑结构为每个三角形绘制不同的颜色。核心在于理解顶点着色器和片元着色器之间的数据传递,并使用 Inter-Stage Variables 以及 `flat` 插值模式来实现对每个三角形颜色控制。通过修改顶点着色器和片元着色器,并结合 blend 设置,最终实现为每个三角形赋予不同颜色的效果。

在 WebGPU 中,要实现 triangle-strip 模式下每个三角形拥有不同颜色,关键在于理解顶点着色器和片元着色器之间的数据传递机制。默认情况下,顶点着色器和片元着色器是相互独立的,它们之间的变量不能直接共享。为了解决这个问题,我们需要使用 Inter-Stage Variables。

Inter-Stage Variables

Inter-Stage Variables 允许我们从顶点着色器向片元着色器传递数据。这些变量需要在顶点着色器中定义,并通过一个结构体返回。同时,在片元着色器中,该结构体作为输入参数接收。@location 装饰器用于指定变量的位置,建立顶点着色器和片元着色器之间的数据通道。

示例代码:

以下代码展示了如何使用 Inter-Stage Variables 来传递三角形索引,从而在片元着色器中根据索引设置不同的颜色。

body{ background-color: #000 }canvas{ display: block; width: 600px; height: 400px; outline: 1px solid #666 }let C = document.querySelector('canvas').getContext(`webgpu`),code=`struct VSOut {  @builtin(position) pos: vec4f,  @location(0) @interpolate(flat) fi: i32,};@vertexfn vs( @builtin(vertex_index) vi: u32 ) -> VSOut {  // inter-stage variables are interpolated. In flat interpolation mode,  // the values passed to the fragment shader are from the "provoking vertex"  // which is the value set on the 1st vertex of the triangle  var vsOut: VSOut;  vsOut.fi = 1;  if (vi > 0) {    vsOut.fi = 2;  }  if(vi<3){    var T = array( vec2f(0,0), vec2f(.4,.7), vec2f(.8,0) );    vsOut.pos = vec4f(T[vi],0,1);    return vsOut;  };  vsOut.pos = vec4f(.6,-.5,0,1);  return vsOut;}@fragmentfn fs(vsOut: VSOut) -> @location(0) vec4f {  if(vsOut.fi == 1){ return vec4f(.7,.2,.2,.5); }; // color for 1st triangle ?  return vec4f(.3,.6,.4,.5);                 // color for 2nd triangle}`, format = `bgra8unorm`,adapter = await navigator.gpu.requestAdapter(), device = await adapter.requestDevice(),      Q = device.queue,      A = {loadOp: `clear`, storeOp: `store`}, // Attachments      O = {colorAttachments: [ A ]},           // Render Pass Descriptor      E, R, module = device.createShaderModule({ code }),      P = device.createRenderPipeline({ layout: `auto`, primitive: { topology: `triangle-strip` },             vertex: { module, entryPoint: `vs`, },           fragment: { module, entryPoint: `fs`, targets: [{ format }] }          });C.configure({ device, format });function F(){  A.view = C.getCurrentTexture().createView();  E = device.createCommandEncoder();  R = E.beginRenderPass(O);  R.setPipeline(P);  R.draw(4);  R.end();  Q.submit([E.finish()]);  requestAnimationFrame(F)}F()

代码解释:

定义结构体 VSOut: 该结构体包含了顶点位置 pos 和三角形索引 fi。@builtin(position) 声明 pos 为内置变量,用于指定顶点位置。@location(0) 声明 fi 变量位于 location 0,用于和片元着色器对应。@interpolate(flat) 关闭了插值,保证每个三角形的 fi 值是固定的。

顶点着色器 vs: 根据顶点索引 vi 设置 fi 的值。vi

片元着色器 fs: 根据接收到的 vsOut.fi 值,选择不同的颜色。如果 vsOut.fi 为 1,则返回红色,否则返回绿色。

插值模式

默认情况下,Inter-Stage Variables 会在三角形内部进行插值。这意味着片元着色器接收到的值是三角形顶点值的加权平均。为了避免颜色在三角形内部渐变,我们需要关闭插值。可以使用 @interpolate(flat) 装饰器来实现。加上这个装饰器后,片元着色器接收到的值将是三角形第一个顶点的值。

注意事项:

triangle-strip 的顶点顺序非常重要。每个三角形的第一个顶点决定了 @interpolate(flat) 装饰器传递的值。确保顶点着色器和片元着色器中的 @location 值匹配,否则数据将无法正确传递。

添加 Blend 设置

如果需要实现透明效果,可以添加 blend 设置。

body{ background-color: #000 }canvas{ display: block; width: 600px; height: 400px; outline: 1px solid #666 }let C = document.querySelector('canvas').getContext(`webgpu`),code=`struct VSOut {  @builtin(position) pos: vec4f,  @location(0) @interpolate(flat) fi: i32,};@vertexfn vs( @builtin(vertex_index) vi: u32 ) -> VSOut {  // inter-stage variables are interpolated. In flat interpolation mode,  // the values passed to the fragment shader are from the "provoking vertex"  // which is the value set on the 1st vertex of the triangle  var vsOut: VSOut;  vsOut.fi = 1;  if (vi > 0) {    vsOut.fi = 2;  }  if(vi<3){    var T = array( vec2f(0,0), vec2f(.4,.7), vec2f(.8,0) );    vsOut.pos = vec4f(T[vi],0,1);    return vsOut;  };  vsOut.pos = vec4f(.6,-.5,0,1);  return vsOut;}@fragmentfn fs(vsOut: VSOut) -> @location(0) vec4f {  if(vsOut.fi == 1){ return vec4f(.7,.2,.2,.5); }; // color for 1st triangle ?  return vec4f(.3,.6,.4,.5);                 // color for 2nd triangle}`, format = `bgra8unorm`,adapter = await navigator.gpu.requestAdapter(), device = await adapter.requestDevice(),      Q = device.queue,      A = {loadOp: `clear`, storeOp: `store`}, // Attachments      O = {colorAttachments: [ A ]},           // Render Pass Descriptor      E, R, module = device.createShaderModule({ code }),      P = device.createRenderPipeline({ layout: `auto`, primitive: { topology: `triangle-strip` },             vertex: { module, entryPoint: `vs`, },           fragment: { module, entryPoint: `fs`, targets: [{ format,           blend: {            color: {              srcFactor: 'one',              dstFactor: 'one-minus-src-alpha',              operation: 'add',            },            alpha: {              srcFactor: 'one',              dstFactor: 'one-minus-src-alpha',              operation: 'add',            },          }, }] }          });C.configure({ device, format });function F(){  A.view = C.getCurrentTexture().createView();  E = device.createCommandEncoder();  R = E.beginRenderPass(O);  R.setPipeline(P);  R.draw(4);  R.end();  Q.submit([E.finish()]);  requestAnimationFrame(F)}F()

在 createRenderPipeline 中,对 fragment 的 target 添加 blend 属性,可以实现混合效果。

总结:

通过使用 Inter-Stage Variables 和 flat 插值模式,我们可以在 WebGPU 中轻松地为 triangle-strip 的每个三角形赋予不同的颜色。这种方法为实现更复杂的渲染效果提供了基础。同时,需要理解顶点顺序和插值模式,才能正确地控制每个三角形的颜色。

以上就是WebGPU:使用 Triangle Strip 为每个三角形绘制不同颜色的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1529052.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月20日 20:47:33
下一篇 2025年12月20日 20:47:44

相关推荐

  • Web前端:解决 focusin 重复触发与构建基础焦点陷阱

    本文探讨了 `focusin` 事件在焦点陷阱场景中可能遇到的重复触发问题。通过介绍如何利用 `tabindex=”-1″` 限制元素的键盘可聚焦性,并结合 `keydown` 事件阻止默认行为,实现对容器内焦点流的精确控制。教程提供了实际代码示例,帮助开发者构建基础的无障碍…

    2025年12月20日
    000
  • 如何实现一个前端项目的持续集成与部署?

    实现前端CI/CD需通过自动化流程提升效率,核心是代码提交、测试、构建与部署的无缝衔接。首选GitHub Actions等主流工具,利用YAML配置工作流,推送代码后自动安装依赖、执行测试、构建产物并校验代码质量。构建成功后可部署至阿里云OSS、Netlify等平台,结合分支策略区分测试、预发和生产…

    2025年12月20日
    000
  • Fancybox事件处理:如何获取触发灯箱的DOM元素

    本教程详细阐述了在fancybox事件回调中获取触发灯箱的dom元素的方法。当`this`指向fancybox实例时,通过利用`done`或`loading`等事件的第二个参数`slide`,开发者可以访问`slide.triggerel`属性来获取原始的dom元素。这对于根据触发元素进行动态操作、…

    2025年12月20日
    000
  • GraphQL 嵌套突变中的输入结构解析与常见错误规避

    本文旨在解决在graphql中使用嵌套突变(nested mutation)同时创建主实体及其关联实体时,因输入结构不匹配而导致的“字段未提供”错误。我们将深入探讨graphql输入类型定义与prisma等orm的内部嵌套写入机制之间的差异,并提供正确的graphql客户端突变输入示例,以确保数据能…

    2025年12月20日
    000
  • 解决Remix会话持久化问题:深入理解Cookie的secure选项

    本文深入探讨remix应用中会话(session)数据无法跨页面持久化的问题,特别是开发环境下常见的陷阱。我们将重点分析`createcookiesessionstorage`配置中`secure`选项的作用及其对会话行为的影响,并提供正确的配置方法,确保会话数据在不同环境中正常工作。 Remix会…

    2025年12月20日
    000
  • 使用React Hook Form动态生成并管理表单输入

    本文探讨了在react hook form中动态创建并获取具有唯一`register`名称和`id`的表单输入值的有效方法。针对直接字符串拼接访问对象属性的常见误区,文章详细介绍了使用方括号表示法进行动态属性访问的解决方案,并强调了react hook form官方推荐的`usefieldarray…

    2025年12月20日
    000
  • 如何编写可测试且易于维护的JavaScript单元测试?

    答案:编写可测试的JavaScript代码需遵循纯函数、避免全局状态、依赖注入和单一职责原则。例如,将时间等外部依赖作为参数传入,使函数输出可预测,便于断言和隔离测试。 编写可测试且易于维护的JavaScript单元测试,关键在于代码结构清晰、职责分离、依赖可控以及测试用例简洁明确。以下是一些实用策…

    2025年12月20日
    000
  • JavaScript中的模板字面量如何赋能DSL创建?

    模板字面量通过内嵌表达式和标签函数让JavaScript构建DSL更直观,支持自定义解析逻辑、动态插值与多行结构,适用于SQL生成、样式定义等场景,提升可读性与维护性。 模板字面量让JavaScript中创建领域特定语言(DSL)变得更直观和简洁。它通过提供一种内嵌表达式的字符串语法,使得开发者能以…

    2025年12月20日
    000
  • 如何构建一个微前端(Micro-Frontends)架构的JavaScript应用?

    微前端架构通过拆分大型应用为独立子应用实现团队自治,需选择合适集成方式(如路由分发或模块联邦),设计主控与子应用的协作机制,解决依赖共享与样式冲突,建立通信系统,并强化错误隔离与监控,适用于中大型团队协作。 构建微前端架构的核心是将一个大型前端应用拆分为多个独立、可自治的小型应用,每个小应用可以由不…

    2025年12月20日
    000
  • 如何设计一个支持多级缓存的前端数据获取策略?

    多级缓存策略通过分层设计提升前端数据获取效率:优先从内存缓存读取,未命中则依次查找本地存储、IndexedDB或触发网络请求;配合TTL过期、事件更新、版本控制等机制管理生命周期,并支持按场景灵活配置缓存层级与key规则,在保证性能的同时兼顾数据一致性。 前端数据获取中引入多级缓存,能显著提升响应速…

    2025年12月20日
    000
  • 解决Electron-vite预览空白屏问题:HashRouter的应用

    electron-vite项目在构建成功后,执行预览命令时可能出现空白屏幕。本文深入探讨了这一常见问题,指出其根源在于前端路由模式的选择。通过将react应用中的browserrouter替换为hashrouter,可以有效解决此问题,确保electron-vite项目在预览和生产环境中正常显示内容…

    2025年12月20日
    000
  • Bootstrap 栅格系统:解决小屏幕按钮排列问题

    本文旨在解决Bootstrap栅格系统在小屏幕设备上按钮排列错乱的问题。通过修改HTML结构,利用Bootstrap提供的响应式列类,并移除按钮的绝对定位样式,使得按钮在小屏幕上垂直排列,在大屏幕上水平排列。同时,建议使用“标签代替`button`标签,以提升语义化和用户体验。 在使用B…

    2025年12月20日
    000
  • 在 React 中渲染 HTML 片段响应:更佳实践指南

    本文旨在指导开发者如何在 React 应用中渲染从后端接口获取的 HTML 片段响应,并着重强调避免直接操作 DOM 的最佳实践。我们将探讨使用 iframe 的方法,以及更推荐的 API 设计模式,即后端返回 JSON 数据而非 HTML,并在前端使用 React 组件进行渲染。 在 React …

    2025年12月20日
    000
  • 实现JavaScript动态列表拖放功能

    在现代Web应用中,动态生成和管理列表元素是常见的需求。当这些列表需要支持用户通过拖放来重新排序时,开发者可能会遇到一个挑战:如何让动态创建的元素响应拖放事件?特别是当使用insertAdjacentHTML()这类方法批量插入HTML字符串时,直接为每个新元素添加事件监听器会变得复杂且效率低下。 …

    2025年12月20日
    000
  • JavaScript动态更新元素内容:一个逐步教程

    本文详细讲解了如何使用 JavaScript 动态更新 HTML 元素的内容,重点是如何正确获取输入框的值并将其添加到新创建的元素中。同时,也介绍如何利用表单简化代码,以及如何使用 localStorage 持久化存储数据,并提供相应的代码示例和最佳实践。 动态更新元素内容的基础方法 核心问题在于如…

    2025年12月20日
    000
  • JavaScript中的ArrayBuffer与TypedArray有何作用?

    ArrayBuffer是二进制数据存储容器,TypedArray提供按类型访问该数据的视图接口,二者结合实现高效操作二进制数据。1. ArrayBuffer通过new ArrayBuffer(length)创建固定长度内存空间。2. TypedArray如Uint8Array、Float32Arra…

    2025年12月20日
    000
  • 如何通过JavaScript控制无人机或物联网设备?

    JavaScript可通过WebSocket或HTTP与物联网设备通信,实现无人机控制;2. Node.js结合serialport、MQTT等库可直接与硬件交互;3. 前端可利用Web Bluetooth或WebUSB实验性API连接蓝牙或USB设备;4. 典型架构为前端发指令、Node.js中转…

    2025年12月20日
    000
  • 使用 JavaScript 和 ApexCharts 实现数据动态追加与实时更新

    本文将介绍如何使用 JavaScript 和 ApexCharts 库,实现每隔固定时间向图表中动态追加数据的功能。通过 `setInterval` 函数,我们可以定时更新图表数据,从而实现数据的实时展示。文章将提供详细的代码示例和步骤说明,帮助开发者快速掌握该技术。 需求分析 我们的目标是创建一个…

    2025年12月20日
    000
  • Chrome 扩展无法在某些 URL 上重定向的解决方案

    本教程旨在解决 Chrome 扩展在特定 URL 上无法进行重定向的问题。通过检查 manifest.json 文件中的匹配规则,并使用通配符进行更广泛的 URL 匹配,可以确保扩展程序在目标网站上正常工作。本文将提供详细的步骤和示例代码,帮助开发者解决类似问题,并确保扩展程序的预期行为。 在使用 …

    2025年12月20日
    000
  • 使用 JavaScript 更新输入值到元素

    本文档旨在指导开发者如何使用 JavaScript 将输入框中的值动态更新到页面元素中,并提供代码示例和最佳实践。我们将探讨如何获取输入值、创建和更新元素,以及如何利用表单和本地存储优化用户体验。 动态更新元素内容 在网页开发中,经常需要根据用户的输入动态更新页面上的元素。以下是一个基础示例,演示了…

    2025年12月20日
    000

发表回复

登录后才能评论
关注微信