Unity Shader - Noise 噪点应用,实现类似流水的表面效果

整体效果


水平流动

垂直流动

扰动放大+扰动速度=激流

Noise 纹理

详细参考:柏林噪声(Perlin Noise)(译)

下面简单说说
噪点可以用不同的平滑波函数来叠加,即可组合出其他的噪点
如下:
Unity Shader - Noise 噪点应用,实现类似流水的表面效果_第1张图片
将它们叠加在一起
Unity Shader - Noise 噪点应用,实现类似流水的表面效果_第2张图片

同样,噪点生成的噪点图(其实都是波的高低数据),也可以叠加,组合出另一个噪点图
Unity Shader - Noise 噪点应用,实现类似流水的表面效果_第3张图片
Unity Shader - Noise 噪点应用,实现类似流水的表面效果_第4张图片
上面6个噪点图,叠加在一起,如下图:
Unity Shader - Noise 噪点应用,实现类似流水的表面效果_第5张图片

是不是很像云朵、烟雾一样。简直就是魔术似的,太帅了。

另外说一个叠加计算方式,unity shader代码如下:

fixed4 col = (
                tex2D(_MainTex1, i.uv) + 
                tex2D(_MainTex2, i.uv) + 
                tex2D(_MainTex3, i.uv) + 
                tex2D(_MainTex4, i.uv) + 
                tex2D(_MainTex5, i.uv) + 
                tex2D(_MainTex6, i.uv)
                ) / 6;

或是:逐噪点图的减半amp系数的,我们这个例子使用上面那种简单处理

fixed4 col = (
                tex2D(_MainTex1, i.uv) + 
                tex2D(_MainTex2, i.uv) * 0.5 + 
                tex2D(_MainTex3, i.uv) * 0.25 + 
                tex2D(_MainTex4, i.uv) * 0.125 + 
                tex2D(_MainTex5, i.uv) * 0.0625 + 
                tex2D(_MainTex6, i.uv) * 0.03125
                ) * 0.5;

然后将网站那个参考网站上的图下下来,简单矩形扣出每个图片来在unity中做实验

将它们叠加在一起,生成最终噪点图
Unity Shader - Noise 噪点应用,实现类似流水的表面效果_第6张图片
但对于只存了单通道数据的柏林噪点图,喜欢用灰度来存:
所以我在shader加了这么一句,求三原色灰度值:

col.rgb = dot(col.rgb, float3(0.299,0.587,0.114));

下面是效果:
Unity Shader - Noise 噪点应用,实现类似流水的表面效果_第7张图片
然后,我用另一外*.cs脚本,导出到文件,脚本如下:

using System;
using System.IO;
using UnityEngine;

public class BlitToTex : MonoBehaviour
{
    public RenderTexture Rt;
    public Material Mat;
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            if (Rt == null || Mat == null) return;
            var newTex = new Texture2D(128, 128);
            Graphics.Blit(newTex, Rt, Mat);
            Graphics.CopyTexture(Rt, 0, 0, 0, 0, 128, 128, newTex, 0, 0, 0, 0);
            newTex.Apply(false, false);
            newTex.ReadPixels(new Rect(0, 0, 128, 128), 0, 0);
            var dir = "Assets/Textures/PerlinNoiseTex";
            if (Directory.Exists(dir)) Directory.CreateDirectory(dir);
            var file = $"{dir}/{DateTime.Now.Ticks}_outTex.jpg";
            File.WriteAllBytes(file, newTex.EncodeToJPG());
            Debug.Log($"out put tex2d success:{file}");
        }
    }
}

完整Shader

// jave.lin 2019.08.12
Shader "Test/PerlinNoiseApp" {
    Properties {
        [NoScaleOffset] _MainTex ("MainTex", 2D) = "white" {}               // 主纹理
        [NoScaleOffset] _NoiseTex ("NoiseTex", 2D) = "white" {}             // 噪点图
        _NoiseScaleX ("NoiseScaleX", Range(0, 1)) = 0.1                     // 水平噪点放大系数
        _NoiseScaleY ("NoiseScaleY", Range(0, 1)) = 0.1                     // 垂直放大系数
        _NoiseSpeedX ("NoiseSpeedX", Range(0, 10)) = 1                      // 水平扰动速度
        _NoiseSpeedY ("NoiseSpeedY", Range(0, 10)) = 1                      // 垂直扰动速度
        _NoiseBrightOffset ("NoiseBrightOffset", Range(0, 0.9)) = 0.25      // 噪点图整体的数值偏移
        _SpecularGlossy ("SpecularGlossy", Range(0, 1)) = 0.16              // 水面光泽度
        _SpecularIntensity ("SpecularIntensity", Range(0, 1)) = 0.5         // 高光强度
    }
    SubShader {
        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
			#include "Lighting.cginc"
			#include "AutoLight.cginc"
            struct appdata {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float3 normal : NORMAL;
            };
            struct v2f {
                float4 vertex : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 normal : TEXCOORD1;
                float3 wPos : TEXCOORD2;
            };
            sampler2D _MainTex;
            sampler2D _NoiseTex;
            fixed _NoiseScaleX;
            fixed _NoiseScaleY;
            fixed _NoiseSpeedX;
            fixed _NoiseSpeedY;
            fixed _NoiseBrightOffset;
            fixed _SpecularGlossy;
            fixed _SpecularIntensity;
            v2f vert (appdata v) {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                o.normal = UnityObjectToWorldNormal(v.normal);
                o.wPos = mul(unity_ObjectToWorld, v.vertex);
                return o;
            }
            fixed4 frag (v2f i) : SV_Target {
                fixed2 ouvxy = fixed2( // 噪点图采样,用于主纹理的UV偏移的
                    tex2D(_NoiseTex, i.uv + fixed2(_Time.x * _NoiseSpeedX, 0)).r,
                    tex2D(_NoiseTex, i.uv + fixed2(0, _Time.x * _NoiseSpeedY)).r);
                ouvxy -= _NoiseBrightOffset; // 0~1 to ==> -_NoiseBrightOffset~ 1 - _NoiseBrightOffset
                ouvxy *= fixed2(_NoiseScaleX, _NoiseScaleY); // 扰动放大系数
                fixed4 col = tex2D(_MainTex, i.uv + ouvxy); // 加上扰动UV后再采样主纹理

                i.normal.xy += ouvxy; // 扰动法线

                // diffuse
                half3 L = normalize(_WorldSpaceLightPos0.xyz);
                half3 N = normalize(i.normal);
                half LdotN = dot(L, N);
                fixed3 diffuse = col.rgb * LdotN;

                // specular
                half3 specular = 0;
                half3 V = normalize(_WorldSpaceCameraPos.xyz - i.wPos);
                half3 H = normalize(L + V);
                if (LdotN > 0)
                {
                    half HdotN = max(0, dot(H, N)); // blinn-phone
                    specular = _LightColor0.rgb * pow(HdotN, _SpecularGlossy * 100) * _SpecularIntensity;
                }

                // ambient
                half3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;

                return fixed4(diffuse + specular + ambient, 1);
            }
            ENDCG
        }
    }
    Fallback "Diffuse"
}

噪点图

最后将我在那个网站里扣出来,再到Unity Shader合作,在到CSharp脚本导出的纹理分享出来:
Unity Shader - Noise 噪点应用,实现类似流水的表面效果_第8张图片

好了,那么有了噪点图后,我们就可以用它来搞事情了。
那就是我们开篇的效果图了。

噪点图,在游戏中应用非常的广泛:

  • 看似随机的地形(MC:MineCraft就用了这个算法来生成地图的)
  • 除了地形高度,还有地表表面的混合纹理
  • 天空的云
  • 火焰效果
  • 水面波纹
  • 模型消融(溶解)
  • 程序纹理
    • 各种岩石:花岗岩、鹅卵石,等

还有好多,我都记不起,基本很多看似随机,但是效果又很像大自然中奇妙造艺的东西,基本都用噪点算法来模拟的。

References

  • 柏林噪声(Perlin Noise)(译)
  • 【图形学】谈谈噪声
  • 木木的Unity学习笔记(四)—— Unity中的柏林噪声(Perlin Noise)
  • Unity shader 使用噪声实现火光摇曳效果
  • Unity Shader学习:噪声noise

你可能感兴趣的:(C#,unity,unity-shader)