shader学习记录——Shadertoy Melt

本文详细记录了临摹Shadertoy上的MeltShader代码的过程,涉及OpenGL着色器的编写,包括纹理应用、坐标变换、时间变量以及动态动画效果的创建。代码中使用了sin和cos函数来生成色彩变化,并通过控制scaleValue调整缩放效果。此外,还实现了基于时间和坐标的位置偏移,以创造出独特的熔化效果。

临摹的Shadertoy代码,记录一下期间遇到问题。

Shader "Unlit/MeltShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _ScaleValue("scaleValue",float) = 1
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100
        Blend SrcAlpha OneMinusSrcAlpha
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"



            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _ScaleValue;


            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            #define RADIANS 0.017453292519943295
            //shaderToy代码,在此定义,在片元着色器中使用,返回值为0
            //const int zoom = 40;
            //const float brightness = 0.975;
            //float fScale = 1.25
            

            float cosRange(float degrees, float range, float minimum) {
                return (((1.0 + cos(degrees * RADIANS)) * 0.5) * range) + minimum;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                //shaderToy代码,在此定义,在片元着色器中使用才有值
                const int zoom =40;//猜测是颜色变化速率
                const float brightness = 0.975;//亮度
                float time = _Time.x * 10;//1.25;//取时间值作为变化周期

                //取纹理贴图color
                fixed4 col = tex2D(_MainTex, i.uv);
                
                //shaderToy代码目的是转换坐标为(-,+)
                //float2 uv = float2(i.uv.x * (_ScreenParams.x / _ScreenParams.y), i.uv.y);//i.uv.xy / _ScreenParams.xy; 
                //float2 p = (2.0 * i.uv.xy - _ScreenParams.xy) / max(_ScreenParams.x, _ScreenParams.y);
                
                //Unity shader代码转换坐标为(-,+)
                float2 p = (2.0 * i.uv - 1) * _ScaleValue;//转换坐标为(-1,+1)*scale
                float2 uv = float2(p.x * (_ScreenParams.x / _ScreenParams.y), p.y);//等比缩放

                float ct = cosRange(time * 5.0, 3.0, 1.1);
                float xBoost = cosRange(time * 0.2, 5.0, 5.0);
                float yBoost = cosRange(time * 0.1, 10.0, 5.0);

                float fScale = cosRange(time * 15.5, 1.25, 0.5);

                for (int i = 1; i < zoom; i++) {
                    float _i = float(i);
                    float2 newp = p;
                    newp.x += 0.25 / _i * sin(_i * p.y + time * cos(ct) * 0.5 / 20.0 + 0.005 * _i) * fScale + xBoost;
                    newp.y += 0.25 / _i * sin(_i * p.x + time * ct * 0.3 / 40.0 + 0.03 * float(i + 15)) * fScale + yBoost;
                    p = newp;
                 }
                //上边看不懂的算法返回了颜色值
                col *= float4(0.5 * sin(3.0 * p.x) + 0.5, 0.5 * sin(3.0 * p.y) + 0.5, sin(p.x + p.y),1);
                col *= brightness;//设置亮度

                //利用透明度设置边界
                // Add border
                float vigAmt = 5.0;
                float vignette = (1. - vigAmt * (uv.y - .5) * (uv.y - .5)) * (1. - vigAmt * (uv.x - .5) * (uv.x - .5));
                float extrusion = (col.x + col.y + col.z) / 4.0;
                extrusion *= 1.5;
                extrusion *= vignette;
                //我这里取了纹理贴图的color,可以直接用png图作为遮罩
                return col;//float4(col,extrusion);
            }
            ENDCG
        }
    }
}

在这里插入图片描述

<think>我们正在查找关于Unity Shader实现消融效果的相关内容。根据提供的引用,我们可以总结出实现消融效果的关键步骤和代码示例。 消融效果(Dissolve Effect)通常用于物体逐渐消失或融化的场景,其核心原理是利用噪声纹理(Noise Texture)作为遮罩,通过一个阈值(Threshold)来控制像素的裁剪(Clip)。当像素的噪声值低于阈值时,丢弃该像素;高于阈值时则显示。同时,为了增强效果,通常在消融边缘添加颜色渐变(如火焰燃烧效果)。 以下是实现消融效果的主要步骤: 1. **噪声纹理准备**: - 创建一张灰度噪声纹理(如云彩效果),确保纹理的Wrap Mode设置为Repeat(重复)模式,以便在模型表面平铺。 - 通过图像处理软件(如Photoshop)生成噪声纹理,并调整其色调范围(最暗为0,最亮为255)。 2. **Shader编写**: - 声明所需的属性(Properties),包括噪声纹理、消融阈值、边缘宽度、边缘颜色等。 - 在顶点着色器中传递必要的顶点信息(如位置、UV、法线等)。 - 在片元着色器中采样噪声纹理,根据阈值进行透明度裁剪(clip函数)。 - 在消融边缘处,通过插值计算两种颜色(如内边缘和外边缘的颜色)实现燃烧效果。 3. **脚本控制**: - 编写一个C#脚本(如Melt.cs)来控制消融阈值的变化(通常随时间增加),并将阈值传递给材质。 下面是一个简化的Unity Shader实现消融效果的示例代码(基于引用内容整理): ### Unity Shader消融效果示例 ```glsl Shader "Custom/DissolveShader" { Properties { _MainTex ("Texture", 2D) = "white" {} _NoiseMap ("Noise Map", 2D) = "white" {} // 噪声纹理 _Threshold ("Threshold", Range(0.0, 1.0)) = 0.0 // 消融阈值 _EdgeWidth ("Edge Width", Range(0.0, 0.2)) = 0.1 // 边缘宽度 _Color1 ("Edge Color 1", Color) = (1,0,0,1) // 边缘颜色1(内边缘) _Color2 ("Edge Color 2", Color) = (1,1,0,1) // 边缘颜色2(外边缘) } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; float3 normal : NORMAL; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; float2 noiseUV : TEXCOORD1; float3 worldNormal : TEXCOORD2; }; sampler2D _MainTex; float4 _MainTex_ST; sampler2D _NoiseMap; float _Threshold; float _EdgeWidth; float4 _Color1; float4 _Color2; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); // 噪声纹理的UV可以使用主纹理UV,也可以单独设置 o.noiseUV = v.uv; o.worldNormal = UnityObjectToWorldNormal(v.normal); return o; } fixed4 frag (v2f i) : SV_Target { // 采样噪声纹理 fixed4 noise = tex2D(_NoiseMap, i.noiseUV); float noiseValue = noise.r; // 裁剪:如果噪声值小于阈值,则丢弃像素 clip(noiseValue - _Threshold); // 计算消融边缘(在阈值附近一定宽度内) float edge = smoothstep(_Threshold, _Threshold + _EdgeWidth, noiseValue); // 混合边缘颜色(从_Color1到_Color2) fixed4 edgeColor = lerp(_Color1, _Color2, edge); // 采样主纹理 fixed4 col = tex2D(_MainTex, i.uv); // 如果处于边缘范围内,则使用边缘颜色;否则使用主纹理颜色 return edge > 0 ? edgeColor : col; } ENDCG } } } ``` ### 控制脚本 在C#脚本中控制消融阈值(随时间变化): ```csharp using UnityEngine; public class DissolveController : MonoBehaviour { public Material dissolveMaterial; // 绑定使用上述Shader的材质 public float dissolveSpeed = 0.5f; // 消融速度 private float _threshold = 0.0f; void Update() { // 随时间增加阈值(循环在0到1之间) _threshold = Mathf.Repeat(Time.time * dissolveSpeed, 1.0f); dissolveMaterial.SetFloat("_Threshold", _threshold); } } ``` ### 注意事项 - 噪声纹理的质量直接影响消融效果的自然程度,推荐使用无缝平铺的噪声纹理。 - 在边缘颜色混合时,可以使用`smoothstep`函数来实现平滑过渡。 - 为了优化性能,可以调整边缘宽度的范围,避免过大的计算开销。 以上代码和步骤提供了Unity Shader实现消融效果的基本框架。根据实际需求,还可以进一步扩展,例如添加光照、边缘发光等效果。 §§相关问题§§ 1. 如何优化消融效果的边缘过渡? 2. 消融效果中噪声纹理的选择有哪些注意事项? 3. 如何在消融效果中加入光照模型(如漫反射)? 4. 消融效果在移动设备上的性能优化方法有哪些? </think>基于提供的引用内容,以下是Unity Shader实现消融效果的核心方法和完整示例: ### 一、消融效果实现原理 1. **核心机制**:使用噪声纹理(Noise Map)作为遮罩,通过`clip()`函数裁剪像素 $$ \text{clip}(noiseValue - threshold) $$ 当噪声值 < 阈值时丢弃像素,实现物体"融化"效果[^1][^3] 2. **燃烧边缘效果**:在阈值边缘添加颜色过渡 $$ \text{edge} = \text{smoothstep}(threshold, threshold + width, noiseValue) $$ 通过`lerp`混合内边缘色(如红色)和外边缘色(如黄色)[^1][^4] --- ### 二、完整实现步骤 #### 1. 准备噪声纹理 ```csharp // Photoshop创建512x512灰度图 // 滤镜 → 渲染 → 云彩 → 图像 → 自动色调 // 导入Unity,Wrap Mode设为Repeat(避免边缘硬切)[^1] ``` #### 2. Shader关键代码 ```glsl Properties { _NoiseMap ("消融噪声图", 2D) = "white" {} _MeltThreshold ("消融阈值", Range(0,1)) = 0 _EdgeWidth ("边缘宽度", Range(0,0.2)) = 0.1 _Color1 ("内边缘色", Color) = (1,0,0,1) // 红色 _Color2 ("外边缘色", Color) = (1,1,0,1) // 黄色 } SubShader { Pass { CGPROGRAM sampler2D _NoiseMap; float _MeltThreshold; float _EdgeWidth; fixed4 _Color1, _Color2; fixed4 frag (v2f i) : SV_Target { // 采样噪声图 float noise = tex2D(_NoiseMap, i.uv).r; // 像素裁剪(核心消融逻辑) clip(noise - _MeltThreshold); // 边缘燃烧效果 float edge = smoothstep( _MeltThreshold, _MeltThreshold + _EdgeWidth, noise ); fixed4 edgeColor = lerp(_Color1, _Color2, edge); return edgeColor; } ENDCG } } ``` #### 3. C#控制脚本(Melt.cs) ```csharp public class Melt : MonoBehaviour { public Material material; // 绑定Shader的材质 [Range(0.01f, 1f)] public float meltSpeed = 0.3f; // 消融速度 void Update() { // 随时间增加阈值(0→1循环) float threshold = Mathf.Repeat(Time.time * meltSpeed, 1.0f); material.SetFloat("_MeltThreshold", threshold); } } ``` --- ### 三、效果增强技巧 1. **添加顶点偏移**:在Shader中使用噪声扰动顶点位置 ```glsl v.vertex.xyz += v.normal * (1 - noise) * _DistortStrength; ``` 2. **结合光照模型**:在片元着色器中加入漫反射计算[^4] ```glsl float3 lightDir = normalize(_WorldSpaceLightPos0.xyz); float diff = max(0, dot(i.worldNormal, lightDir)); fixed4 diffuse = _LightColor0 * diff * _Diffuse; ``` 3. **边缘发光**:在裁剪边界添加自发光 ```glsl float glow = 1 - saturate((noise - _MeltThreshold) / _EdgeWidth); emission = glow * _GlowColor * _GlowIntensity; ``` --- ### 四、示例效果说明 1. **基础消融**:物体从随机位置开始融化消失 2. **动态边缘**:阈值变化时产生燃烧颜色过渡 3. **参数控制**:通过`meltSpeed`调节消融速度,`_EdgeWidth`控制火焰带宽度 > 最终效果参考:[Unity Shader 消融效果_案例分享][^1]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值