【问题标题】:Vertex gradient shader rotation?顶点渐变着色器旋转?
【发布时间】:2018-11-13 16:37:59
【问题描述】:

我有一个着色器,可让我创建和旋转 2 或 3 色渐变。我的问题是它在 GPU 上很重,所以我将这部分代码从片段着色器移到了顶点着色器:

 fixed4 frag (v2f i) : SV_Target
            {   
                //STARTS HERE
                float2 uv =  - (i.screenPos.xy / i.screenPos.w - 0.5)*2;

                fixed3 c;                        
                #if _BG_COLOR_GRADIENT2
                    c = lerp(_BgColor1,_BgColor3,clampValue(rotateUV(uv.xy,_BgColorRotation*PI).y,_BgColorPosition));                                            
                #elif _BG_COLOR_GRADIENT3
                    c = lerp3(_BgColor1,_BgColor2,_BgColor3,clampValue(rotateUV(uv.xy,_BgColorRotation*PI).y,_BgColorPosition),_BgColorPosition3);
                #endif 
                //ENDS HERE         

                return fixed4(c, i.color.a);
            }

现在我的着色器看起来像这样:

Shader "Custom/Gradient"
{
    Properties
    {
        [KeywordEnum(Gradient2, Gradient3)] _BG_COLOR ("Color Type", Float) = 1
        _Color("Color", Color) = (1, 1, 1, 1)
        _BgColor1 ("Start Color",Color) = (0.667,0.851,0.937,1)
        _BgColor2 ("Middle Color",Color) = (0.29, 0.8, 0.2,1)
        _BgColor3 ("End Color",Color) = (0.29, 0.8, 0.2,1)
        [GradientPositionSliderDrawer]
        _BgColorPosition ("Gradient Position",Vector) = (0,1,0)
        _BgColorRotation ("Gradient Rotation",Range(0,2)) = 0
        _BgColorPosition3 ("Middle Size",Range(0,1)) = 0

    }

    SubShader
    {
        Tags{ "Queue" = "Background" "IgnoreProjectors"="True" }

        Blend SrcAlpha OneMinusSrcAlpha
        AlphaTest Greater .01
        ColorMask RGB
        Cull Off Lighting Off ZWrite Off
        BindChannels {
        Bind "Color", color
        Bind "Vertex", vertex
        Bind "TexCoord", texcoord
    }

    Pass
    {
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag

        #pragma shader_feature _BG_COLOR_GRADIENT2 _BG_COLOR_GRADIENT3

        #include "UnityCG.cginc"
        #include "GradientHelper.cginc"

        struct appdata
        {
           float4 vertex : POSITION;
           fixed4 color : COLOR;
        };

        struct v2f
        {                
            float4 pos : SV_POSITION;
            float4 screenPos : TEXCOORD4;
            fixed4 color : COLOR;
        };

        fixed4 _BgColor1;
        fixed4 _BgColor2;
        fixed4 _BgColor3;
        float _BgColorRotation;
        float2 _BgColorPosition;
        float _BgColorPosition3;
        float4 _Color;

        v2f vert (appdata v)
        {
            v2f o;
            o.pos = UnityObjectToClipPos(v.vertex);
            o.screenPos = ComputeScreenPos(o.pos);

            float2 uv =  - (o.screenPos.xy / o.screenPos.w - 0.5)*2;                         

            #if _BG_COLOR_GRADIENT2
                o.color = lerp(_BgColor1,_BgColor3,clampValue(rotateUV(uv.xy,_BgColorRotation*PI).y,_BgColorPosition)) * v.color;                                            
            #elif _BG_COLOR_GRADIENT3
                o.color = lerp3(_BgColor1,_BgColor2,_BgColor3,clampValue(rotateUV(uv.xy,_BgColorRotation*PI).y,_BgColorPosition),_BgColorPosition3) * v.color;
            #endif

            return o;
        }

        fixed4 frag (v2f i) : COLOR {
            return i.color;
        }
        ENDCG
        }
    }
    CustomEditor "Background.Editor.BackgroundGradientEditor"
}

(这是我的着色器助手):

#ifndef PI
#define PI 3.141592653589793
#endif
#ifndef HALF_PI
#define HALF_PI 1.5707963267948966
#endif

// Helper Funtions

inline float clampValue(float input, float2 limit) 
{
    float minValue = 1-limit.y;
    float maxValue = 1-limit.x;
    if(input<=minValue){
        return 0;
    } else if(input>=maxValue){
        return 1;
    } else {
        return (input - minValue )/(maxValue-minValue);
    }                       
}

inline float2 rotateUV(fixed2 uv, float rotation) 
{
    float sinX = sin (rotation);
    float cosX = cos (rotation);
    float2x2 rotationMatrix = float2x2(cosX, -sinX, sinX, cosX);
    return mul ( uv, rotationMatrix )/2 + 0.5;
}

inline fixed4 lerp3(fixed4 a, fixed4 b, fixed4 c, float pos, float size){

    float ratio2 = 0.5+size*0.5;
    float ratio1 = 1-ratio2;
    if(pos<ratio1)
        return lerp(a,b,pos/ratio1);
    else if(pos>ratio2)
        return lerp(b,c,(pos-ratio2)/ratio1);               
    else
        return b;
}    
#endif

现在性能很好,但旋转完全混乱(在 3 色渐变上最明显),我似乎无法弄清楚原因。

【问题讨论】:

  • 片段着色器 (FS) 输出像素的颜色。顶点着色器 (VS) 输出顶点的值。 OpenGL 引擎使用 VS 的输出插入值(对于 FS),作为您的 lerped 变量。你有一个旋转屏幕坐标的插值。
  • 你能帮我吗,那我该怎么办?提前谢谢!
  • 传递给颜色三角形顶点的VS坐标和颜色。 OGL 将为三角形内的每个点传递给 FS 内插值(如使用“lerp”)。不需要'lerp'。 FS 中不需要计算。如果你想要一个旋转的三角形,只需旋转 VS 中的顶点,这也需要你传递,至少一个角度。不要将“三角形旋转”与“颜色旋转”(渐变)混淆。
  • 很抱歉,我对着色器真的很陌生,而且我也不是以英语为母语的人。如果你能帮我写下代码,我很乐意接受它作为答案。
  • 我不会写代码,我对unity3d一无所知。我建议学习一些 OpenGL 教程(版本 >= 3.2),即使它是用 C++ 编写的。您将了解 OpenGL 的工作原理,特别是关于在 VS 和 FS 之间完成的自动插值。

标签: unity3d opengl shader fragment-shader vertex-shader


【解决方案1】:

我一直不明白为什么人们想在着色器中制作渐变,它非常有限,而且不一定性能更高,除非您每帧都更改值。我最好的解决方案是在 CPU 上将渐变生成为纹理,大小为 1x128。使用 Unity 提供的 Gradient 类,然后循环:

Texture2D texture = new Texture2D(128, 1);
Color[] pixels = Color[128];
for (int i = 0; i < 128; i++) {
    pixels[i] = gradient.Evaluate(i/127f);
}
texture.SetPixels(pixels);
texture.Apply();

使用以下方法将其发送到着色器:

material.SetTexture("_Gradient", texture)

然后,您可以像以前一样使用 2x2 矩阵随心所欲地旋转和滚动此纹理。只要确保将纹理溢出模式设置为钳制而不重复。请记住,您可以在行为中实现 OnValidate() 以在编辑器中应用值更新,但如果您需要在构建中更新它,则需要以其他方式监听更改。

使用顶点颜色确实对渐变很有用,因为它们是在硬件中插值的......但据我了解,这是一种屏幕空间效果,因此您需要顶点与实际对齐梯度带。

【讨论】:

    猜你喜欢
    • 2020-06-19
    • 2023-03-25
    • 2020-05-16
    • 1970-01-01
    • 2022-11-18
    • 1970-01-01
    • 2020-03-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多