##
随机在shader中制作各种noise非常常见。下文中我将介绍如何利用shader生成随机数。
1维随机
1维随机是我们在shader中制作随机数的基础。我简单介绍下各个函数、参数的作用。
fract(x)->就是取x小数部分然后做个绝对值处理
sin(x)->不必多说
fract(sin(x)*a),a=1.0 如上图
fract(sin(x)*a),a=10.5 如上图
fract( sin(x + b) * a ),a=100,b=0.546 如上图
fract( sin(x + 0.546) * 143758.5964)->如上图
通常程序中我们把a、b看做随机数种子的一部分,当a越大时实际上fract( sin(x) * a)会表现的“更密集"(扩大了定义域),也就会更“随机”。实际上定义好种子数后,我们得到的是特定的随机。
float Random1DTo1D(float value,float a,float b){
//make value more random by making it bigger
float random = frac(sin(value+b)*a);
return random;
}
2维/3维/4维 高维到低维随机
在程序中我们更常用的是4D/3D/2D->3D/2D/1D的随机,通常我们使用dot()来处理高维到1维的情况,并且在dot()前为了减少artifacts(超过float边界)我们一般会对传进来的value进行处理。
2D->1D:
float Random2DTo1D(float2 value,float a ,float2 b)
{
//avaoid artifacts
float2 smallValue = sin(value);
//get scalar value from 2d vector
float random = dot(smallValue,b);
random = frac(sin(random) * a);
return random;
}
2D->2D:(其实就是对2D用不同的种子处理2次)
float2 Random2DTo2D(float2 value){
return float2(
Random2DTo1D(value,14375.5964, float2(15.637, 76.243)),
Random2DTo1D(value,14684.6034,float2(45.366, 23.168))
);
}
3D->1D
float Random3DTo1D(float3 value,float a,float3 b)
{
float3 smallValue = sin(value);
float random = dot(smallValue,b);
random = frac(sin(random) * a);
return random;
}
3D->2D
float2 Random3DTo2D(float3 value){
return float2(
Random3DTo1D(value,14375.5964, float3(15.637,76.243,37.168)),
Random3DTo1D(value,14684.6034,float3(45.366, 23.168,65.918))
);
}
3D->3D
float3 Random3DTo3D(float3 value){
return float3(
Random3DTo1D(value,14375.5964, float3(15.637,76.243,37.168)),
Random3DTo1D(value,14684.6034,float3(45.366, 23.168,65.918)),
Random3DTo1D(value,17635.1739,float3(62.654, 88.467,25.111))
);
}
4D->1D
float Random4DTo1D(float4 value,float a ,float4 b)
{
float4 smallValue = sin(value);
float random = dot(smallValue,b);
random = frac(sin(random) * a);
return random;
}
4D->2D
float2 Random4DTo2D(float4 value)
{
return float2(
Random4DTo1D(value,14375.5964,float4(15.637,76.243,37.168,83.511)),
Random4DTo1D(value,14684.6034,float4(45.366, 23.168,65.918,57.514))
);
}
4D->3D
float3 Random4DTo3D(float4 value)
{
return float3(
Random4DTo1D(value,14375.5964,float4(15.637,76.243,37.168,83.511)),
Random4DTo1D(value,14684.6034,float4(45.366, 23.168,65.918,57.514)),
Random4DTo1D(value,14985.1739,float4(62.654, 88.467,25.111,61.875))
);
}
4D->4D
float4 Random4DTo4D(float4 value)
{
return float4(
Random4DTo1D(value,14375.5964,float4(15.637,76.243,37.168,83.511)),
Random4DTo1D(value,14684.6034,float4(45.366, 23.168,65.918,57.514)),
Random4DTo1D(value,14985.1739,float4(62.654, 88.467,25.111,61.875)),
Random4DTo1D(value,17635.1739,float4(44.383, 38.174,67.688,22.351))
);
}
1维/2维/3维/4维 低维到高维随机
方法和上面一样不再赘述。
整个文件 :
(因为是在URP里写的,所以风格保持了统一;另外在URP中我们可以用real来替换float,提高在移动端的性能)
#ifndef UNIVERSAL_RANDOM_INCLUDED
#define UNIVERSAL_RANDOM_INCLUDED
//1D
float Random1DTo1D(float value,float a,float b){
//make value more random by making it bigger
float random = frac(sin(value+b)*a);
return random;
}
float2 Random1DTo2D(float value){
return float2(
Random1DTo1D(value,14375.5964,0.546),
Random1DTo1D(value,18694.2233,0.153)
);
}
float3 Random1DTo3D(float value){
return float3(
Random1DTo1D(value,14375.5964,0.546),
Random1DTo1D(value,18694.2233,0.153),
Random1DTo1D(value,19663.6565,0.327)
);
}
float4 Random1DTo4D(float value){
return float4(
Random1DTo1D(value,14375.5964,0.546),
Random1DTo1D(value,18694.2233,0.153),
Random1DTo1D(value,19663.6565,0.327),
Random1DTo1D(value,12748.4774,0.688)
);
}
//2D
float Random2DTo1D(float2 value,float a ,float2 b)
{
//avaoid artifacts
float2 smallValue = sin(value);
//get scalar value from 2d vector
float random = dot(smallValue,b);
random = frac(sin(random) * a);
return random;
}
float2 Random2DTo2D(float2 value){
return float2(
Random2DTo1D(value,14375.5964, float2(15.637, 76.243)),
Random2DTo1D(value,14684.6034,float2(45.366, 23.168))
);
}
float3 Random2DTo3D(float2 value){
return float3(
Random2DTo1D(value,14375.5964,float2(15.637, 76.243)),
Random2DTo1D(value,18694.2233,float2(45.366, 23.168)),
Random2DTo1D(value,19663.6565,float2(62.654, 88.467))
);
}
float4 Random2DTo4D(float2 value){
return float4(
Random2DTo1D(value,14375.5964,float2(15.637, 76.243)),
Random2DTo1D(value,18694.2233,float2(45.366, 23.168)),
Random2DTo1D(value,19663.6565,float2(62.654, 88.467)),
Random2DTo1D(value,17635.1739,float2(44.383, 38.174))
);
}
//3D
float Random3DTo1D(float3 value,float a,float3 b)
{
float3 smallValue = sin(value);
float random = dot(smallValue,b);
random = frac(sin(random) * a);
return random;
}
float2 Random3DTo2D(float3 value){
return float2(
Random3DTo1D(value,14375.5964, float3(15.637,76.243,37.168)),
Random3DTo1D(value,14684.6034,float3(45.366, 23.168,65.918))
);
}
float3 Random3DTo3D(float3 value){
return float3(
Random3DTo1D(value,14375.5964, float3(15.637,76.243,37.168)),
Random3DTo1D(value,14684.6034,float3(45.366, 23.168,65.918)),
Random3DTo1D(value,17635.1739,float3(62.654, 88.467,25.111))
);
}
float4 Random3DTo4D(float3 value){
return float4(
Random3DTo1D(value,14375.5964, float3(15.637,76.243,37.168)),
Random3DTo1D(value,14684.6034,float3(45.366, 23.168,65.918)),
Random3DTo1D(value,17635.1739,float3(62.654, 88.467,25.111)),
Random3DTo1D(value,17635.1739,float3(44.383, 38.174,67.688))
);
}
//4D
float Random4DTo1D(float4 value,float a ,float4 b)
{
float4 smallValue = sin(value);
float random = dot(smallValue,b);
random = frac(sin(random) * a);
return random;
}
float2 Random4DTo2D(float4 value)
{
return float2(
Random4DTo1D(value,14375.5964,float4(15.637,76.243,37.168,83.511)),
Random4DTo1D(value,14684.6034,float4(45.366, 23.168,65.918,57.514))
);
}
float3 Random4DTo3D(float4 value)
{
return float3(
Random4DTo1D(value,14375.5964,float4(15.637,76.243,37.168,83.511)),
Random4DTo1D(value,14684.6034,float4(45.366, 23.168,65.918,57.514)),
Random4DTo1D(value,14985.1739,float4(62.654, 88.467,25.111,61.875))
);
}
float4 Random4DTo4D(float4 value)
{
return float4(
Random4DTo1D(value,14375.5964,float4(15.637,76.243,37.168,83.511)),
Random4DTo1D(value,14684.6034,float4(45.366, 23.168,65.918,57.514)),
Random4DTo1D(value,14985.1739,float4(62.654, 88.467,25.111,61.875)),
Random4DTo1D(value,17635.1739,float4(44.383, 38.174,67.688,22.351))
);
}
#endif
随机算法其实利用了hash的思想,所以国外又有把Random function称为Hash function的。
Shadertoywww.shadertoy.com/results?query=hash
生成简单噪声图
很简单的shader:源文件链接
Shader "Noise"
{
SubShader
{
Pass
{
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Random.hlsl"
struct appdata
{
float4 vertex : POSITION;
};
struct v2f
{
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = TransformObjectToHClip(v.vertex.xyz);
return o;
}
float4 frag (v2f i) : SV_Target
{
float3 value = i.vertex.xyz;
float4 col = Random3DTo4D(value);
return col;
}
ENDHLSL
}
}
}
利用噪声图制作卡牌背景
————————————————