线框着色器:如何显示四边形而不是三角形?

use*_*493 5 shader wireframe unity-game-engine geometry-shader

我有一个线框着色器,可以在左侧立方体上显示三角形,并希望对其进行更新,使其仅显示四边形,例如在右侧立方体上。

三角形 VS 四边形

这是代码:

Shader "Custom/Wireframe"
{
    Properties
    {
        _WireColor("WireColor", Color) = (1,0,0,1)
        _Color("Color", Color) = (1,1,1,1)
    }
SubShader
{
    Pass
    {
        CGPROGRAM
        #include "UnityCG.cginc"
        #pragma target 5.0
        #pragma vertex vert
        #pragma geometry geom
        #pragma fragment frag

        half4 _WireColor, _Color;

        struct v2g
        {
            float4  pos : SV_POSITION;
            float2  uv : TEXCOORD0;
        };

        struct g2f
        {
            float4  pos : SV_POSITION;
            float2  uv : TEXCOORD0;
            float3 dist : TEXCOORD1;
        };

        v2g vert(appdata_base v)
        {
            v2g OUT;
            OUT.pos = mul(UNITY_MATRIX_MVP, v.vertex);
            OUT.uv = v.texcoord;
            return OUT;
        }

        [maxvertexcount(3)]
        void geom(triangle v2g IN[3], inout TriangleStream<g2f> triStream)
        {

            float2 WIN_SCALE = float2(_ScreenParams.x/2.0, _ScreenParams.y/2.0);

            //frag position
            float2 p0 = WIN_SCALE * IN[0].pos.xy / IN[0].pos.w;
            float2 p1 = WIN_SCALE * IN[1].pos.xy / IN[1].pos.w;
            float2 p2 = WIN_SCALE * IN[2].pos.xy / IN[2].pos.w;

            //barycentric position
            float2 v0 = p2-p1;
            float2 v1 = p2-p0;
            float2 v2 = p1-p0;
            //triangles area
            float area = abs(v1.x*v2.y - v1.y * v2.x);

            g2f OUT;
            OUT.pos = IN[0].pos;
            OUT.uv = IN[0].uv;
            OUT.dist = float3(area/length(v0),0,0);
            triStream.Append(OUT);

            OUT.pos = IN[1].pos;
            OUT.uv = IN[1].uv;
            OUT.dist = float3(0,area/length(v1),0);
            triStream.Append(OUT);

            OUT.pos = IN[2].pos;
            OUT.uv = IN[2].uv;
            OUT.dist = float3(0,0,area/length(v2));
            triStream.Append(OUT);

        }

        half4 frag(g2f IN) : COLOR
        {
            //distance of frag from triangles center
            float d = min(IN.dist.x, min(IN.dist.y, IN.dist.z));
            //fade based on dist from center
             float I = exp2(-4.0*d*d);

             return lerp(_Color, _WireColor, I);              
        }
        ENDCG
    }
}
Run Code Online (Sandbox Code Playgroud)

有人提到,一种方法是比较相邻三角形的法线。如果两条法线的点积接近1,则可以跳过边缘。但我不知道如何实现它,因为我对几何着色器一无所知。

你能帮我编辑这个着色器吗?

谢谢。

zam*_*ari 1

Unity 和一般图形引擎 (OpenGL/D3D) 不在四边形上运行,这对它们来说是一个陌生的术语。我不是一个只会为你拿出一个片段的着色器忍者,但你可以尝试通过法线不连续性过滤你的几何体 - 只在具有不同法线的三角形之间绘制边缘(或者更具体地说,足够不同,因为这是浮点数学和东西)很少精确相等) - 这会隐藏平坦表面上的边缘。

一种方法是对深度图进行采样,并检查我们和邻居之间的差异在片段着色器中是否相对恒定。

也许你可以通过顶点颜色传递信息

虽然与问题没有直接关系,但阅读 Keijiro 的代码总是很有启发性,他写了一些关于他如何修改蒙皮几何体的文章。他的方法涉及缓存 3D 纹理中的法线(您也可以使用备用 UV 坐标)以向着色器公开其他几何信息。

https://github.com/keijiro/SkinnedVertexModifier

着色器无法访问除自身以外的其他点的任何数据,但如果将该数据放入纹理或 UV 中,则可以为其提供一些有关如何进行的指导。一般来说,有一种简单的方法可以从着色器级别了解您与几何体其余部分的关系,您需要提前在 CPU 上生成该数据并将其提供给着色器,以便在着色器时它已经是计算机了开始。我希望这有帮助