我有一个Goldberg多面体,在程序上生成。我想画一个轮廓效果周围的一组“脸”(让我们称之为瓷砖)类似于下面的图像,最好不产生两个网格,在顶点着色器进行缩放。有人能帮忙吗?
我的假设是使用一个缩放版本的瓷砖写入一个模板缓冲区,然后重新绘制那些比较模板的瓷砖来绘制轮廓(对于这种效果来说通常是这样),但是我不能想出一个优雅的解决方案来缩放这些瓷砖。
到目前为止,我最好的想法是得到每个边缘顶点(蓝色)的相邻瓷砖的中心点(以下绿色),并将顶点按有多少个的权重向它们移动,这将使内部的顶点保持不变,外部的顶点向内移动。我认为这在原则上是可行的,但我需要生成两个网格,因为我无法在顶点着色器中这样缩放(据我所知)。
如果是相关的,这就是多面体的构造方式。每个瓷砖是一个独立的物体,表面用一个中心点进行三角剖分,在多面体的原点上还有另一个点(也是瓷砖的原点)。这样,瓷砖就可以在多面体上均匀地缩放和凸出,而不会产生空隙或重叠。
提前感谢您的帮助!
编辑:
jsb的回答是一个简单而优雅的解决这个问题的方法。我只是想添加一些额外的信息,以防其他人有同样的问题。
首先,下面是我用来计算这些UV的C#代码:
// Use duplicate vertex count (over 4)
var vertices = mesh.vertices;
var uvs = new Vector2[vertices.Length];
for(int i = 0; i < vertices.Length; i++)
{
var duplicateCount = vertices.Count(s => s == vertices[i]);
var isInterior = duplicateCount > 4;
uvs[i] = isInterior ? Vector2.zero : Vector2.one;
}
请注意,这是因为我没有焊接任何顶点在我的原始网格,所以我可以计数相邻的三角形,只需寻找重复的顶点。
您也可以这样计算三角形(这将适用于合并的顶点,至少可以使用Unity数据的布局方式):
// Use triangle count using this vertex (over 4)
var triangles = mesh.triangles;
var uvs = new Vector2[mesh.vertices.Length];
for(int i = 0; i < triangles.Length; i++)
{
var triCount = triangles.Count(s => mesh.vertices[s] == mesh.vertices[triangles[i]]);
var isInterior = triCount > 4;
uvs[i] = isInterior ? Vector2.zero : Vector2.one;
}
接下来是下面的问题。在我的用例中,我还需要生成不规则瓷砖模式的轮廓,如下所示:
我忘了在最初的文章中提到这一点。Jsb的答案仍然有效,但是上面的代码不会像现在这样工作。正如你所看到的,当我们有一个只有一个边连接的瓷砖时,连接的顶点只能“共享”两个内部三角形,所以我们得到了一个“外部”边。作为解决这个问题的方法,我沿着瓷砖的外部边缘创建了额外的顶点,如下所示:
我这样做是通过计算原始外部平铺顶点(a + (b - a) * 0.5)之间的向量中间点,然后在那里插入一个点。但是,正如您所看到的,简单的“重复顶点> 4”不再适用于确定外观上的瓷砖。
我的解决方案是按特定的顺序对顶点进行缠绕,这样我就知道,每第三个顶点都是我插入的沿边缘的顶点,如下所示:
Vector3 a = vertex;
Vector3 b = nextVertex;
Vector3 c = (vertex + (nextVertex - vertex) * 0.5f);
Vector3 d = tileCenter;
CreateTriangle(c, d, a);
CreateTriangle(c, b, d);
然后修改UV代码以测试这些顶点的重复值>2(从0开始的每三个顶点):
// Use duplicate vertex count
var vertices = mesh.vertices;
var uvs = new Vector2[vertices.Length];
for(int i = 0; i < vertices.Length; i++)
{
var duplicateCount = vertices.Count(s => s == vertices[i]);
var isMidPoint = i % 3 == 0;
var isInterior = duplicateCount > (isMidPoint ? 2 : 4);
uvs[i] = isInterior ? Vector2.zero : Vector2.one;
}
这是最后的结果:
谢谢jsb!
发布于 2022-01-23 14:24:06
避免第二个网格的一个选择是纹理化:假设您在三角形顶点上定义了1D纹理坐标,如下所示:
在渲染网格时,使用这些坐标在定义内部和边框颜色的一维纹理中查找:
当然,与其使用纹理,不如在片段着色器中实现这种行为,方法是从概念上对纹理坐标进行阈值化:
if (u > 0.9)
fragColor = white;
else
fragColor = gray;
要更新大纲,您只需要上传一组新的tex和弦,它们仅适用于大纲上的顶点1和其他任何地方的0。
根据您想要的轮廓只延伸到所选区域的内部,还是对称地延伸到边界的两侧,您需要分别指定每个角或每个顶点的tex和弦。
https://stackoverflow.com/questions/70815072
复制相似问题