欢迎光临散文网 会员登陆 & 注册

通过逆重心坐标插值 传递多个顶点信息到片段

2023-08-16 14:59 作者:Dreamtowards  | 我要投稿

"Passing whole triangle Vertices Data to a Fragment, via Inverse Barycentric Coordnate Interpolation."

问题描述

这个问题/需要出自于一个体素系统,体素系统构建网格时 每个顶点给出一个`int MtlId`材质id数据。而在渲染片段时,片段为了混合材质,需要获取当前三角形3个顶点的 MtlId 和顶点对应的BaryCoord重心坐标。

然而,三角形3个顶点的 MtlId 和 BaryCoord 该怎么传递给片段着色器呢?

Method 1: +Dummy VertexData | 方法1:通过添加额外的 冗余的顶点数据

BaryCoord: 

每个顶点添加一个 `vec3 VertBaryCoord` 的顶点数据,并且对于每个三角形,其中3个顶点的该条数据应分别为 `{1, 0, 0}, {0, 1, 0}, {0, 0, 1}`。

由于 顶点着色器varying out传数据给片段着色器时会进行重心坐标插值,因此这些数据被传入片段着色器时 就已经是这3个顶点的重心坐标了。

MtlIds

同样地,在CPU生成网格时,将每个顶点之前的 `int MtlId` 顶点数据变为 `ivec3 MtlIds`,其中3个分量分别是当前三角形3个顶点的 MtlId,三角形内3个顶点的该条数据均一致。

随后在顶点着色器中 flat out 传递给片段着色器(将会随机从3个顶点中选一个出来给片段着色器,但由于3个顶点的该数据是一致的 因此数据无差别),或者默认地 varying out 传递(由于三个顶点数据一致,因此插值前后无区别)

e.g.


优缺点:

这种方法的跨平台性很强,因为唯一的变数只是添加顶点数据 - 这是每个平台都基本支持的。

但是,会带来额外的性能损耗(内存开销增加了很多,同时也会影响到内存效率 以降低时间效率)。并且,会影响到‘纯粹性’,也就是非常困扰我的 我难以忍受这种不够纯粹的方法 存在于我核心系统上。这些冗余重复的,有点傻的数据。

Method 2: Geometry Shader / Tessellation Shader

我曾在独立游戏 Ethertia 中实现过这种方法,分别是opengl3 geom shader和vulkan tess shader对该方法的实现。

通过geom shader 或 tess shader,你可以控制 如何插值图元内的顶点的数据。

Geometry Shader (incase OpenGL 3)

图中的 TriMtlId 则是我们的 MtlIds。而TriMtlWeight则是我们的 BaryCoord。

这种方法相比于上面的“额外顶点数据方法” 更neat整洁些。

然而,由于Geomrtry Shader的早期不够成熟的设计和过大的灵活性,它的性能存在隐患,已在现代图形渲染中 不推荐使用。

Tessellation Shader (Control& Evaluation, incase Vulkan)

上面分别是 TessControl 和 TessEval shader。而插值控制在后者。

虽然Tess shader相对晦涩复杂,但是相比geom shader,具有更好的性能表现,和更现代的渲染理念。


Method 3: Ethertia Method

你可能意识到了,这些方法很繁琐,也比较困扰我。但是由于tess shader方法可用,我也不再继续追究。然而我最近在用Unity URP ShaderGraph去做一个shader,在这种情况下 不能用到 geom shader 或 tess shader,我因此感到深深的绝望。在查询全网无果后,借助 OpenAI ChatGPT 早年的启示,我突然想到了这种方法:真是极为简单和简洁和强大。

假设在顶点着色器中,系统对每个顶点给出一个 VertexID 值,即顶点序数。那么:

只需要几行,无什么外部/系统依赖。极简的方法。但很救命。

通过逆重心坐标插值 传递多个顶点信息到片段的评论 (共 条)

分享到微博请遵守国家法律