Unity Shader 流光 边缘光

文章介绍了如何使用Unity2021.3.23版本中的Shader实现流光效果,通过控制UV变化并采样流光贴图,展示了边缘光和扫描光的制作过程以及相关的代码示例。
摘要由CSDN通过智能技术生成

前言

Unity2021.3.23

一、实现原理

Time控制UV的变化,再采样一张流光贴图.即可实现流光效果。

二、效果及源码展示

1.流光效果

效果描述:
1.边缘光(菲尼尔),
2.从上到下扫描光.

效果图如下:

代码如下:

Shader "Unlit/ScanCode"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _RimMin("RimMin",Range(-1,1)) = 0.0
        _RimMax("RimMax",Range(0,2)) = 1.0
        _InnerColor("InnerColor",Color) = (0.0, 0.0, 0.0 ,0.0)
        _RimColor("Rim Color", Color) = (1,1,1,1)
        _RimIntensity("Rim Intensity", Float) = 1.0
        _FlowTilling("Flow Tilling",Vector) = (1,1,0,0)
        _FlowSpeed("Flow Speed", Vector)= (1,1,0,0)
        _FlowTex("Flow Tex", 2D) = "white"{}
        _FlowIntensity("Flow Intensity",Float) = 0.5
        _InnerAlpha("Inner Alpha",Range(0.0,1.0)) = 0.0

    }
    SubShader
    {
        //Tags { "RenderType"="Opaque" }
       Tags { "Queue"="Transparent" }
        LOD 100

        Pass
        {
            ZWrite off
            Blend SrcAlpha One
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag


            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 texcoord : TEXCOORD0;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                float3 pos_world :TEXCOORD1;
                float3 normal_world : TEXCOORD2;
                //轴点的世界空间坐标
                float3 pivot_world :TEXCOORD3;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _RimMin;
            float _RimMax;
            float4 _InnerColor;
            float4 _RimColor;
            float4 _RimIntensity;
            float4 _FlowTilling;
            float4 _FlowSpeed;
            sampler2D _FlowTex;
            float _FlowIntensity;
            float _InnerAlpha;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                //float4(v.normal,0.0)如果是向量,后面补0.0
                float3 normal_world = mul(float4(v.normal,0.0), unity_WorldToObject);
                float3 pos_world = mul(unity_ObjectToWorld,v.vertex).xyz;
                o.normal_world = normalize(normal_world);
                o.pos_world = pos_world;
                //三维向量变成一个四维向量,后面补1.0,
                o.pivot_world = mul(unity_ObjectToWorld,float4(0.0, 0.0, 0.0, 1.0));
                o.uv = v.texcoord;            
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                //1.边缘光
               half3 normal_world = normalize(i.normal_world);
               //视线方向的向量,先拿到世界空间上的摄像机的位置,然后归一化。
               //精度上,向量用half3就够了。片元阶段要非常注意性能
               half3 view_world = normalize(_WorldSpaceCameraPos.xyz -i.pos_world);
               //限制在0-1的范围内 
                half NdotV = saturate(dot(normal_world, view_world));
                half fresnel = 1.0 - NdotV;
                fresnel = smoothstep(_RimMin,_RimMax, fresnel);
            
               //自发光
               half emiss = tex2D(_MainTex, i.uv).r;
               emiss = pow(emiss, 5.0);
               half final_fresnel = saturate(fresnel + emiss);
               //设置颜色
               half3 final_rim_color = lerp(_InnerColor.xyz, _RimColor.xyz *_RimIntensity, final_fresnel);
                half final_rim_alpha = final_fresnel;



                //2.流光
                half2 uv_flow = (i.pos_world.xy - i.pivot_world.xy) * _FlowTilling.xy;         
                uv_flow =uv_flow + _Time.y * _FlowSpeed.xy;
                float4 flow_rgba = tex2D(_FlowTex, uv_flow) * _FlowIntensity;
                
                //整合
                float3 final_col = final_rim_color + flow_rgba.xyz;
                float final_alpha = saturate(final_rim_alpha + flow_rgba.a + _InnerAlpha);
                return float4(final_col,final_alpha);
            }
            ENDCG
        }
    }
}

(i.pos_world.xy - i.pivot_world.xy)
用于计算UV位置,达到从上到下的扫描效果.

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 好的,下面是一个简单的用Unity Shader实现边缘发光效果的例子。 首先,我们需要一个称为"RenderTexture"的工具来在屏幕上渲染场景。这个RenderTexture将会成为我们在Shader中计算边缘发光的基础。 在这个Shader中,我们需要做以下几个步骤: 1. 将场景渲染到RenderTexture中。 2. 对RenderTexture进行处理,找到场景中的边缘,并将边缘标记为白色。 3. 对处理后的RenderTexture进行模糊处理,以产生发光效果。 4. 将模糊后的RenderTexture和原始场景图像混合在一起,产生最终的边缘发光效果。 下面是一个简单的Shader代码示例: ``` Shader "Custom/EdgeGlow" { Properties { _MainTex ("Texture", 2D) = "white" {} _EdgeColor ("Edge Color", Color) = (1,1,1,1) _EdgeWidth ("Edge Width", Range(0, 0.1)) = 0.01 _BlurRadius ("Blur Radius", Range(0, 10)) = 2 } SubShader { Tags { "RenderType"="Opaque" } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; float4 _EdgeColor; float _EdgeWidth; float _BlurRadius; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; } fixed4 frag (v2f i) : SV_Target { // Step 1: Render scene to a RenderTexture float4 scene = tex2D(_MainTex, i.uv); // Step 2: Find edges and mark them white float4 edge = (4 * scene.rgba - tex2D(_MainTex, i.uv + float2(0, 1) * _MainTex_ST.y).rgba - tex2D(_MainTex, i.uv - float2(0, 1) * _MainTex_ST.y).rgba - tex2D(_MainTex, i.uv + float2(1, 0) * _MainTex_ST.x).rgba - tex2D(_MainTex, i.uv - float2(1, 0) * _MainTex_ST.x).rgba); edge = max(edge, 0); edge = step(_EdgeWidth, edge.r); // Step 3: Apply Gaussian blur to edges for (int i = -_BlurRadius; i <= _BlurRadius; i++) { for (int j = -_BlurRadius; j <= _BlurRadius; j++) { float2 offset = float2(i, j) * ### 回答2: 使用Unity Shader编写边缘发光效果可以通过以下几个步骤来实现: 1. 为对象创建一个新的材质,并在着色器选项中选择"Custom/Edge Glow"。 2. 编写一个新的边缘发光Shader,并将其与上一步骤中创建的材质相关联。 3. 在着色器中添加顶点和片段着色器函数。 4. 顶点着色器中,使用传入的模型视图矩阵和投影矩阵将顶点位置转换为屏幕空间坐标。 5. 片段着色器中,将屏幕空间坐标作为输入。 6. 在片段着色器中,使用采样函数获取当前像素的颜色。 7. 使用一个for循环,遍历像素的邻居,比较颜色差异,如果颜色差异超过一个阈值,则表示该像素位于边缘。 8. 将边缘像素的颜色设置为发光颜色,将非边缘像素的颜色设置为原始颜色。 9. 在Unity中将该材质应用到需要应用该边缘发光效果的对象上。 以上是一种实现边缘发光效果的例子,可以根据具体需求适应更多的应用场景和效果。编写Shader需要一定的Shader编程经验,建议在学习和实践的过程中参考Unity官方文档和其他相关资源。 ### 回答3: 要使用Unity Shader编写一段边缘发光效果,我们可以参考一种基本的方法。首先,我们需要两个Pass来实现效果:一个Pass用于将发光部分高亮,另一个Pass使用轮廓检测算法将边缘区域描绘出来。 首先,在顶点着色器中,我们需要将顶点位置从模型空间转换为剪辑空间,通过将顶点坐标乘以Unity内置变量`UNITY_MATRIX_MVP`实现。然后,我们可以将变换后的位置传递给片段着色器。 在片段着色器中,我们需要进行两个Pass。在第一个Pass中,通过计算法线和视线的角度余弦值,将发光部分高亮。我们可以使用照信息和噪声函数来模拟高亮效果。最后,我们将高亮部分的颜色与原始颜色进行混合。 在第二个Pass中,我们使用轮廓检测算法来描绘边缘。我们可以通过计算像素的法线差异来确定边缘区域。如果法线差异大于阈值,则将像素颜色设置为边缘颜色,否则保持原始颜色。 边缘发光效果的实现需要额的几何信息,例如模型的法线信息。因此,在Unity中将需要在材质中导入法线贴图,并在Shader中进行采样。 总结起来,要使用Unity Shader编写一段边缘发光效果,我们需要进行两个Pass:一个用于高亮发光部分,另一个用于描绘边缘部分。通过计算角度余弦和法线差异,我们可以实现边缘发光效果。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值