关于下面的噪声图,一定要自己动手输出每张图的效果,结合代码分析图的效果。
1.白噪声WhiteNoise
主要是用到 frac函数,此函数主要是 返回小数部分
{小注: frac(10x) 和 frac(100x)的区别}
// 白噪声
float whiteNoise(float2 uv,int seed)
{
float r = frac(sin(dot(uv,float2(seed + 12.9898,seed + 78.233)))*43758.5453);
return r;
}
2.柏林噪声perlinNoise
下面是smoothStep的函数用代码来表达的形式:
重点:t = t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);
// smooth interpolation for perlin noise
float SmoothLerp(float min, float max, float t)
{
t = t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);
return min + t * (max - min);
}
“双线性插值”:
(1)在水平方向上插值X1
(1)在水平方向上插值X2
(1)在将X1和X2在竖直方向上插值得到结果
// 当w为0时,返回a,当w为1时返回b,否则返回a与b的插值
float lerp(float a, float b, float w) {
return a + w*(b-a);
}
3.分形布朗运动
下面给出代码:包括白噪声,柏林噪声,用分形布朗运动对柏林噪声进行处理:
高度雾 + 噪声–>流动的雾:
Shader "custom/fog"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_FogXSpeed("_fogXSpeed",range(0,0.5)) = 0.01
_FogYSpeed("_fogYSpeed",range(0,0.5)) = 0.03
}
SubShader
{
// No culling or depth
Cull Off ZWrite Off ZTest Always
Pass
{
Tags { "RenderType"="Opaque" }
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;
float4 scrProj : TEXCOORD1;
float2 uv_depth : TEXCOORD2;
float4 interpolatedRay : TEXCOORD3;
};
sampler2D _MainTex;
half4 _MainTex_TexelSize;
sampler2D _CameraDepthTexture;
float4x4 _FrustumCornersRay;
float4 _FogColor;
float _FogDensity;
float _FogStart;
float _FogEnd;
float _FogXSpeed;
float _FogYSpeed;
// 白噪声
float whiteNoise(int seed, int i, int j)
{
//return frac(sin(dot(float2(i,cos(j)),float2(seed+12.9898,seed + 78.233)))*43758.5453);
return frac(
sin(dot(float2(i, cos(j)), float2(float(seed) + 12.9898, float(seed) + 78.233))) * 43758.5453);
}
//求出梯度值
float HashGrid(int seed, int i, int j)
{
// 将得到的白噪声的值(0,1) -》还原为 (-1,-1)
float r = whiteNoise(seed, i, j);
r = r * 2 - 1;
return r;
}
// 梯度向量
float2 ComputeGradient(int seed, int gridX, int gridY)
{
float2 gradient = float2(HashGrid(seed * 123 + 456, gridX, gridY),
HashGrid(seed * 456 + 123, gridX, gridY));
return gradient;
}
// 柏林噪声
float perlinNoise(int seed, float2 p, float gridSize)
{
p /= gridSize;
int gridX = floor(p.x);
int gridY = floor(p.y);
float2 gradient00 = ComputeGradient(seed, gridX, gridY);
float2 gradient01 = ComputeGradient(seed, gridX, gridY + 1);
float2 gradient10 = ComputeGradient(seed, gridX + 1, gridY);
float2 gradient11 = ComputeGradient(seed, gridX + 1, gridY + 1);
float2 v00 = float2(gridX, gridY);
float2 v01 = float2(gridX, gridY + 1);
float2 v10 = float2(gridX + 1, gridY);
float2 v11 = float2(gridX + 1, gridY + 1);
float dp00 = dot((p - v00), gradient00);
float dp01 = dot((p - v01), gradient01);
float dp10 = dot((p - v10), gradient10);
float dp11 = dot((p - v11), gradient11);
// blinear interpolation 双线性插值
float tx = (p.x - v00.x);
float ty = (p.y - v00.y);
// 此处将lerp 转换成smoothstep 比较一下效果
float res = smoothstep(lerp(dp00, dp10, tx), lerp(dp01, dp11, tx), ty);
float res = lerp(lerp(dp00, dp10, tx), lerp(dp01, dp11, tx), ty);
return res;
}
float PerlinNoiseFBM6(int seed, float2 p, float gridSize)
{
// const float aspect = 2.0f;
// p.x *= aspect;
// fBM : https://www.iquilezles.org/www/articles/fbm/fbm.htm
// https://www.shadertoy.com/view/lsl3RH
// https://www.shadertoy.com/view/XslGRr
//Vector4 deltaVec = new Vector4(Random.Range(-1.0f, 1.0f), Random.Range(-1.0f, 1.0f), 0.0f, 0.0f); ;// new Vector4(Random.Range(-1.0f, 1.0f), Random.Range(-1.0f, 1.0f), 0.0f, 0.0f);
float2x2 mat = {
//some rotation matrix
0.8f, 0.6f,
-0.6f, 0.8f
};
float f = 0.0f;
int numFbmSteps = 6;
float multiplier[6] = {2.02f, 2.03f, 2.01f, 2.04f, 2.01f, 2.02f};
// float multiplier[6] = { 1.02f, 2.03f, 3.01f, 2.04f, 3.01f, 3.02f };
float amp = 1.0f;
for (int i = 0; i < numFbmSteps; ++i)
{
f += amp * perlinNoise(seed, p, gridSize);
p = mul(mat, p) * multiplier[i];
//(2.0f + Random.Range(0.0f, 0.05f));//brownian motion applied to sample coord
// p *= multiplier[i];
amp *= 0.5f;
}
return f / 0.96875f;
}
// 分形布朗运动
float perLinNoiseFBM(int seed,float2 p,float gridSize)
{
float2x2 mat = {
0.8f,0.6f,
-0.6f,0.8f
};
float f = 0.0f;
int numFbmSteps = 6;
float multiplier[6] = {2.02f,2.03f,2.01f,2.04f,2.01f,2.02f};
float amp = 1.0f;
for (int i = 0;i<numFbmSteps;i++)
{
f += amp * perlinNoise(seed,p,gridSize);
p = mul(mat,p) * multiplier[i];
amp *= 0.5f;
}
return f / 0.96875f;
}
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.uv_depth = v.uv;
# if UNITY_UV_STARTS_AT_TOP
o.uv_depth.y = 1 - o.uv_depth.y;
#endif
int index = 0;
float2 uv = v.uv;
if (uv.x < 0.5 && uv.y < 0.5)
{
index = 0;
}
else if (uv.x > 0.5 && uv.y < 0.5)
{
index = 1;
}
else if (uv.x > 0.5 && uv.y > 0.5)
{
index = 2;
}
else if (uv.x < 0.5 && uv.y > 0.5)
{
index = 3;
}
#if UNITY_UV_STARTS_AT_TOP
if (_MainTex_TexelSize.y < 0)
index = 3 - index;
#endif
o.interpolatedRay = _FrustumCornersRay[index];
return o;
}
fixed4 frag(v2f i) : SV_Target
{
float speed = _Time.y * float2(_FogXSpeed,_FogYSpeed);
float gridSize = 0.500;
float nosie = perLinNoiseFBM(42, i.uv + speed, gridSize);
// 重建世界坐标系
float depth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv_depth));
float3 worldPos = _WorldSpaceCameraPos + depth * i.interpolatedRay.xyz;
// y值越小, 浓度越高
float fogDensity = (_FogEnd - worldPos.y) / (_FogEnd - _FogStart);
fogDensity = saturate(fogDensity * _FogDensity * (1+ nosie));
fixed4 finalCol = tex2D(_MainTex,i.uv);
finalCol.rbg = lerp(finalCol.rgb,_FogColor.rgb,fogDensity);
return fixed4(finalCol);
}
ENDCG
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
[ExecuteInEditMode]
[ImageEffectAllowedInSceneView]
public class fog : MonoBehaviour
{
#region const data
private const string m_FrustumCornersRay = "_FrustumCornersRay";
private const string fogCol = "_FogColor";
private const string fogDen = "_FogDensity";
private const string fogSt = "_FogStart";
private const string fogEn = "_FogEnd";
#endregion
private Material m_Material;
public Camera camera;
public Shader FogShader;
[Range(0,3)]
public float fogDensity;
public Color fogColor;
public float fogStart = 0;
public float fogEnd = 2.0f;
[Range(0,0.3f)]
public float _FogXSpeed;
[Range(0,0.3f)]
public float _FogYSpeed;
private void OnRenderImage(RenderTexture src, RenderTexture dest)
{
if (!m_Material)
{
m_Material= new Material(FogShader);
}
Matrix4x4 frustumCorners = Matrix4x4.identity;
float fov = camera.fieldOfView;
float near = camera.nearClipPlane;
float aspect = camera.aspect;
float halfHeight = near * Mathf.Tan(fov * 0.5f * Mathf.Deg2Rad);
var cameraTransform = camera.transform;
Vector3 toRight = cameraTransform.right * halfHeight * aspect;
Vector3 toTop = cameraTransform.up * halfHeight;
//
Vector3 topLeft = cameraTransform.forward * near + toTop-toRight;
// magnitude ,返回向量的长度
float scale = topLeft.magnitude / near;
topLeft.Normalize();
topLeft *= scale;
//
Vector3 topRight = cameraTransform.forward * near + toRight + toTop;
topRight.Normalize();
topRight *= scale;
//
Vector3 bottmLeft = cameraTransform.forward * near - toTop - toRight;
bottmLeft.Normalize();
bottmLeft *= scale;
//
Vector3 bottmRigh = cameraTransform.forward * near - toTop + toRight;
bottmRigh.Normalize();
bottmRigh *= scale;
frustumCorners.SetRow(0,bottmLeft);
frustumCorners.SetRow(1,bottmRigh);
frustumCorners.SetRow(2,topRight);
frustumCorners.SetRow(3,topLeft);
m_Material.SetMatrix(m_FrustumCornersRay,frustumCorners);
m_Material.SetColor(fogCol,fogColor);
m_Material.SetFloat(fogDen,fogDensity);
m_Material.SetFloat(fogSt,fogStart);
m_Material.SetFloat(fogEn,fogEnd);
m_Material.SetFloat("_FogXSpeed",_FogXSpeed);
m_Material.SetFloat("_FogYSpeed",_FogYSpeed);
Graphics.Blit(src,dest,m_Material);
}
}