水平流动
垂直流动
扰动放大+扰动速度=激流
详细参考:柏林噪声(Perlin Noise)(译)
下面简单说说
噪点可以用不同的平滑波函数来叠加,即可组合出其他的噪点
如下:
将它们叠加在一起
同样,噪点生成的噪点图(其实都是波的高低数据),也可以叠加,组合出另一个噪点图
上面6个噪点图,叠加在一起,如下图:
是不是很像云朵、烟雾一样。简直就是魔术似的,太帅了。
另外说一个叠加计算方式,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中做实验
将它们叠加在一起,生成最终噪点图
但对于只存了单通道数据的柏林噪点图,喜欢用灰度来存:
所以我在shader加了这么一句,求三原色灰度值:
col.rgb = dot(col.rgb, float3(0.299,0.587,0.114));
下面是效果:
然后,我用另一外*.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}");
}
}
}
// 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脚本导出的纹理分享出来:
好了,那么有了噪点图后,我们就可以用它来搞事情了。
那就是我们开篇的效果图了。
噪点图,在游戏中应用非常的广泛:
还有好多,我都记不起,基本很多看似随机,但是效果又很像大自然中奇妙造艺的东西,基本都用噪点算法来模拟的。