新闻中心
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 来传递三角形索引,从而在片元着色器中根据索引设置不同的颜色。
<!DOCTYPE html>
<html>
<head>
<style>
body{ background-color: #000 }
canvas{ display: block; width: 600px; height: 400px; outline: 1px solid #666 }
</style>
</head>
<body>
<canvas width=900 height=600></canvas>
<script type="module">
let C = document.querySelector('canvas').getContext(`webgpu`),
code=`
struct VSOut {
@builtin(position) pos: vec4f,
@location(0) @interpolate(flat) fi: i32,
};
@vertex
fn 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, 3>( 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;
}
@fragment
fn 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 n*igator.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()
</script>
</body>
</html>代码解释:
定义结构体 VSOut: 该结构体包含了顶点位置 pos 和三角形索引 fi。@builtin(position) 声明 pos 为内置变量,用于指定顶点位置。@location(0) 声明 fi 变量位于 location 0,用于和片元着色器对应。@interpolate(flat) 关闭了插值,保证每个三角形的 fi 值是固定的。
顶点着色器 vs: 根据顶点索引 vi 设置 fi 的值。vi
片元着色器 fs: 根据接收到的 vsOut.fi 值,选择不同的颜色。如果 vsOut.fi 为 1,则返回红色,否则返回绿色。
九个不同动作和表情的柠檬矢量素材(EPS)
这张图片展示了一组活泼的柠檬卡通形象,每一个柠檬都表现出不同的情感和动作。从欢乐的微笑、自信的挥手,到忧郁的落泪、愤怒的表情,这些柠檬形象为我们带来了丰富多彩的情感表达。它们的身体都绘有简单的黑色手臂和腿,还穿着小白鞋,增加了趣味性。每个柠檬的形状和颜色保持了一致,但通过不同的面部表情和身体语言,为我们展现了它们独特的个性。这些柠檬角色可爱又充满活力,非常适合用作插图或设计元素。素材格式为 EPS
15
查看详情
插值模式
默认情况下,Inter-Stage Variables 会在三角形内部进行插值。这意味着片元着色器接收到的值是三角形顶点值的加权平均。为了避免颜色在三角形内部渐变,我们需要关闭插值。可以使用 @interpolate(flat) 装饰器来实现。加上这个装饰器后,片元着色器接收到的值将是三角形第一个顶点的值。
注意事项:
- triangle-strip 的顶点顺序非常重要。每个三角形的第一个顶点决定了 @interpolate(flat) 装饰器传递的值。
- 确保顶点着色器和片元着色器中的 @location 值匹配,否则数据将无法正确传递。
添加 Blend 设置
如果需要实现透明效果,可以添加 blend 设置。
<!DOCTYPE html>
<html>
<head>
<style>
body{ background-color: #000 }
canvas{ display: block; width: 600px; height: 400px; outline: 1px solid #666 }
</style>
</head>
<body>
<canvas width=900 height=600></canvas>
<script type="module">
let C = document.querySelector('canvas').getContext(`webgpu`),
code=`
struct VSOut {
@builtin(position) pos: vec4f,
@location(0) @interpolate(flat) fi: i32,
};
@vertex
fn 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, 3>( 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;
}
@fragment
fn fs(vsOut: VSOut) -> @location(0) vec4f {
if(vsOut.fi == 1){ return vec4f(.7,.2,.2,.5); }; // co
lor for 1st triangle ?
return vec4f(.3,.6,.4,.5); // color for 2nd triangle
}`,
format = `bgra8unorm`,
adapter = await n*igator.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()
</script>
</body>
</html>在 createRenderPipeline 中,对 fragment 的 target 添加 blend 属性,可以实现混合效果。
总结:
通过使用 Inter-Stage Variables 和 flat 插值模式,我们可以在 WebGPU 中轻松地为 triangle-strip 的每个三角形赋予不同的颜色。这种方法为实现更复杂的渲染效果提供了基础。同时,需要理解顶点顺序和插值模式,才能正确地控制每个三角形的颜色。
以上就是WebGPU:使用 Triangle Strip 为每个三角形绘制不同颜色的详细内容,更多请关注其它相关文章!
# 拖拽
# 丽水专业的网站建设推广
# 观山湖新城网站建设
# 微商营销推广平台有哪些
# 韶关英文seo
# 淄博高端网站建设
# 盘锦网站建设优化推广
# 宝坻网站seo推广哪家便宜
# 短视频营销推广方式的特点
# 店铺seo查询
# seo金融是啥
# 情况下
# html
# 如何实现
# 服务端
# 来实现
# 第一个
# 器中
# 插值
# 着色器
# 角形
# blend
# canva
# ai
相关栏目:
【
科技资讯46185 】
【
网络学院92790 】
相关推荐:
魅族17怎样用浏览器译外语网页_iPhone魅族17浏览器译外语网页【即时翻译】
Go与Ruby之间实现AES加密互通:CFB模式下的密钥长度匹配策略
Typer应用中灵活处理命令行参数的令牌化与解析
在J*a中如何开发简易仓库管理与库存统计_仓库管理库存统计项目实战解析
海量存储:机器视觉智能化的核心基石
12306选座怎么选到商务座_12306商务座选择与配置说明
React/Next.js中实现列表项的动态选择与移动
Bing引擎入口最新2025 Bing搜索免费官方登录
Yandex官方入口网址 Yandex俄罗斯搜索引擎最新在线地址
Win11怎么查看电脑配置_Win11硬件配置检测工具使用
PowerPoint如何制作滚动字幕结尾彩蛋_PowerPoint路径动画实现平滑滚动字幕效果
Go语言JSON解析深度指南:动态访问与结构体映射实践
如何仅使用CSS更改登录界面背景图像图标的颜色
腾讯QQ邮箱登录入口_QQ邮箱官方网站使用地址
React Router v6 教程:构建认证保护的私有路由与重定向策略
J*a应用集成GitHub CLI与API认证指南
在Go开发中优雅管理ListenAndServe进程:GoSublime集成方案
Vue.js 图片显示异常排查:理解应用挂载范围与DOM ID唯一性
sublime怎么进行远程开发编辑_配置rsub/rmate实现sublime编辑服务器文件
如何使用spryker/configurable-bundles-products-resource-relationship模块解决复杂产品捆绑关系难题
拼多多赚钱渠道_拼多多收益来源
Linux如何构建多环境配置管理_Linux多环境配置方案
理解J*aScript Promise的微任务队列与执行顺序
Yandex搜索引擎官方地址 俄罗斯网络世界的主要入口
Yandex免登录官网入口_俄罗斯Yandex搜索引擎直达链接
微信客户端如何收红包_微信客户端接收红包使用教程
KFC早餐时段怎么领特惠代码_KFC早餐订餐优惠代码获取与使用说明
C++如何实现一个装饰器模式_C++设计模式之动态地给对象添加额外职责
192.168.1.1管理中心入口 192.168.1.1路由器网页设置平台
sublime如何配置Go语言开发环境_sublime搭建Golang编译运行系统
深入理解J*a链表中的IPosition接口与使用
React中useState与局部变量:理解组件状态管理与渲染机制
Golang如何优化内存分配与垃圾回收_Golang内存管理与GC优化实践
fishbowl官网免费版 fishbowl养鱼网站入口
纯CSS与HTML网格布局的HTML精简策略:SVG与JS方案解析
抖音隐秘迷城小游戏入口_ 抖音冒险解谜小游戏秒玩
Golang如何使用const iota_Go iota常量计数器讲解
AngularJS $http POST请求数据传递与Go后端接收实践
聚水潭ERP登录页面入口 聚水潭ERP官网登录界面
Python多版本共存与虚拟环境管理深度指南
汽水音乐车机版8.9下载 汽水音乐车机版8.9版本安装入口
c++如何使用TBB库进行任务并行_c++ Intel线程构建模块
火狐浏览器占用内存高卡顿怎么办 火狐浏览器性能优化设置技巧
百度浏览器字体显示异常偏小_百度浏览器字体渲染修复方案
怎么在html里运行vbs脚本_html中运行vbs脚本方法【教程】
NetBeans Ant项目:自动化将资源文件复制到dist目录的教程
如何创建独立于主系统的J*a运行环境_隔离式环境搭建策略
铁路12306官网网页端快速入口 铁路12306官方首页登录教程
Win11截图该按哪些键 Win11截屏完整流程解析【教程】
vivo手机参数配置怎么增强信号_vivo手机参数配置信号增强方法


2025-10-13
浏览次数:次
返回列表
lor for 1st triangle ?
return vec4f(.3,.6,.4,.5); // color for 2nd triangle
}`,
format = `bgra8unorm`,
adapter = await n*igator.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()
</script>
</body>
</html>