• Geometry Shader 实现 Wireframe 绘制边线的Shader


    最终效果:

    参考了一个免费插件

    基础思路======================================
    在几何阶段计算每个顶点到第三边的距离,在片元中就可以插值得到每个点到顶点的距离
    根据最小的距离只计算是否需要显示,结果就是只绘制边线

    基础知识======================================
    Geometry 在 Vertex 和 Fragment 之间 可选步骤
    根据Vertex传入的顶点参数做一些调整,生成改动后的顶点结构,再调用Fragment着色器

    //声明使用的几何着色器函数,类似声明 vertex 和 fragment
    #pragma geometry geom

    //限制GS输出的最大顶点数
    [maxvertexcount(3)]
    //第一个时入参  第二个是调整以后的数据
    void geom(triangle v2g p[3], inout TriangleStream<g2f> triStream)
    {
        UCLAGL_geom( p, triStream);
    }

    入参格式 像fragment类似,传入的是vertex的计算结果 例如
    struct  v2g
    {
        float4  pos    : POSITION;         // vertex position
        float2  uv      : TEXCOORD0;    // vertex uv coordinate
    };
    不一样的是一次可以处理多个结果
    point v2g p[1]
    line v2g p[2]
    triangle v2g p[3]

    返回参数 inout 必须
    可以返回3中数据流 PointStream, LineStream, TriangleStream
    流中的具体数据类似f2v的数据格式
    struct g2f
    {
        float4  pos   : POSITION;         // fragment position
        float2  uv     : TEXCOORD0;    // fragment uv coordinate
        float3  dist   : TEXCOORD1;    // distance to each edge of the triangle
    };
    也是可以返回多个的
    inout PointStream<
    g2f> poiStream
    inout LineStream<
    g2f> linStream
    inout TriangleStream<g2f> triStream

    Shader==================================================
    Shader "Unlit/WithWireframeShder"
    {
        Properties
        {
            _MainColor ("Main Color", Color) = (1,1,1,1)
            _LineColor ("Line Color", Color) = (0,0,0,1)
            _Thickness ("Thickness", Float) = 1
        }
        SubShader
        {
            Tags { "RenderType"="Opaque" }
            LOD 100

            //绘制基础颜色
            Pass
            {           
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
               
                #include "UnityCG.cginc"

                float4 _MainColor;

                struct appdata
                {
                    float4 vertex : POSITION;
                };

                struct v2f
                {
                    float4 pos : SV_POSITION;
                };
               
                v2f vert (appdata v)
                {
                    v2f o;
                    o.pos = UnityObjectToClipPos(v.vertex);
                    return o;
                }
               
                fixed4 frag (v2f i) : SV_Target
                {   
                    return _MainColor;
                }
                ENDCG
            }

            //绘制线框
            Pass
            {
                CGPROGRAM
                #pragma vertex vert
                #pragma geometry geom
                #pragma fragment frag
               
                #include "UnityCG.cginc"

                float4 _LineColor;
                float _Thickness;

                struct appdata
                {
                    float4 vertex : POSITION;
                };

                struct v2g
                {
                    float4 pos : SV_POSITION;
                };

                struct g2f
                {
                    float4    pos        : POSITION;        // fragment position
                    float3  dist    : TEXCOORD1;    // distance to each edge of the triangle
                };
               
                v2g vert (appdata v)
                {
                    v2g o;
                    o.pos = UnityObjectToClipPos(v.vertex);
                    return o;
                }

                [maxvertexcount(3)]
                void geom(triangle v2g p[3], inout TriangleStream<g2f> triStream)
                {
                    //points in screen space
                    float2 p0 = _ScreenParams.xy * p[0].pos.xy / p[0].pos.w;
                    float2 p1 = _ScreenParams.xy * p[1].pos.xy / p[1].pos.w;
                    float2 p2 = _ScreenParams.xy * p[2].pos.xy / p[2].pos.w;
                   
                    //edge vectors
                    float2 v0 = p2 - p1;
                    float2 v1 = p2 - p0;
                    float2 v2 = p1 - p0;

                    //area of the triangle
                    float area = abs(v1.x*v2.y - v1.y * v2.x);

                    //values based on distance to the edges
                    float dist0 = area / length(v0);
                    float dist1 = area / length(v1);
                    float dist2 = area / length(v2);
                   
                    g2f pIn;
                   
                    //add the first point
                    pIn.pos = p[0].pos;
                    pIn.dist = float3(dist0,0,0);
                    triStream.Append(pIn);

                    //add the second point
                    pIn.pos =  p[1].pos;
                    pIn.dist = float3(0,dist1,0);
                    triStream.Append(pIn);
                   
                    //add the third point
                    pIn.pos = p[2].pos;
                    pIn.dist = float3(0,0,dist2);
                    triStream.Append(pIn);
                }
               
                fixed4 frag (g2f input) : SV_Target
                {           
                    //find the smallest distance
                    float val = min( input.dist.x, min( input.dist.y, input.dist.z));
                   
                    //calculate power to 2 to thin the line
                    val = exp2( -1/_Thickness * val * val );

                    //丢弃不在边线上的
                    if (val < 0.5f) discard;       

                    return _LineColor;
                }
                ENDCG
            }
        }
    }




  • 相关阅读:
    Genealogical tree(拓扑结构+邻接表+优先队列)
    确定比赛名次(map+邻接表 邻接表 拓扑结构 队列+邻接表)
    Agri-Net
    Network()
    Conscription
    Matrix(类似kruskal)
    Highways(求最小生成树的最大边)
    Shell学习之Shell特性(一)
    Linux学习之用户管理命令与用户组管理命令(十五)
    Linux学习之用户配置文件详解(十四)
  • 原文地址:https://www.cnblogs.com/Hichy/p/8399502.html
Copyright © 2020-2023  润新知