【发布时间】:2018-12-21 05:11:42
【问题描述】:
我在 Unity3D 的着色器实验室中创建了一个简单的轮廓着色器,其中包含两个通道:第一个通道通过沿顶点法线乘以顶点信息来放大对象,第二个通道绘制对象的常规(基本通道)版本。问题出在大纲传递的代码中:
Pass {
Name "OUTLINE"
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha // Normal
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f {
float4 position : POSITION;
float3 normal : NORMAL;
};
uniform float _OutlineWidth;
uniform float4 _OutlineColor;
v2f vert(appdata v) {
v.vertex.xyz *= _OutlineWidth;
v2f o;
o.position = UnityObjectToClipPos(v.vertex);
return o;
}
half4 frag(v2f i) : COLOR {
return _OutlineColor;
}
ENDCG
}
_OutlineWidth 和 _OutlineColor 分别属于 Range 和 Color 类型。我已将此着色器应用于以编程方式创建的几个“类似四联牌”的网格。结果是这样的(点击链接):
如您所见,创建了一个轮廓,但该轮廓沿对象的外边缘宽度不均匀。沿着其中一个面,轮廓较大 - 沿着距离形状中心最远的面较大。并且对于非凸形状,问题被放大了;轮廓甚至可能根本不包含形状:
我知道这是由于顶点位置相对于形状的中心,而线 v.vertex.xyz *= _OutlineWidth 只是将该位置乘以一个常数(使其远离对象的中心)。如何修改我的代码,以便轮廓像素的计算独立于形状的中心并与对象的真实轮廓保持完整性?
【问题讨论】:
-
正如您已经写的那样,您应该推动顶点
along a vertex normal而不是直接乘以它们的位置,因为这会从对象中心缩放它们。所以你应该考虑法线v.vertex.xyz += v.normal * _OutlineWidth;重要的是法线应该对同一位置的所有顶点进行平均,否则面会相互断开。 -
如何对同一位置的所有顶点的法线进行平均? @Gnietschow
-
我从未在着色器实验室环境中与您合作过,所以我只能给您提示我是如何做到的。您需要在创建模型时计算它们。当我需要一个边框着色器时,我在加载时为所有网格添加了第二个法线。因此,我将具有相同位置的所有顶点聚集在一起,平均它们的法线并将其存储为每个顶点中的第二个法线,稍后我可以在着色器中将其用作输入。
标签: unity3d shader hlsl cg shaderlab