|
一、简介
关于3d篇的内容更多的在于介绍基础知识,所以相对简单一些,等3d篇介绍完了,笔者会以特别篇的方式做些给力的效果,敬请期待。本文呢笔者将介绍电流的实现。效果如图1所示。
图1 电流效果
二、原理剖析
首先电流是随机扰动的,所以噪声纹理采样是比不可少的,同时电流是随时间变化的,所以还要加入一个时间数据;但是仅采样一张噪声,得到的效果是朝某个方向偏移,不像电流随机方向的效果,所以要采样两次,分别从不同方向以不同速度采样,在将2个噪声数据叠加,这个时候,电流就会产生不固定的方向了;
接下来,噪声纹理得到的效果是不规则的白块,而电流则是细线的效果,这里有2种方法,一种是像消融效果一样,取两个相邻的step值相减得到边缘,另一种则是通过Procedual/Shape里的形状节点来获取,笔者参考的是网上大佬的思路使用的后者,具体差异呢大家可以自己比对一下,笔者感觉差不太多!
最后叠加到主纹理上,一个电流效果就完成了,哈哈,细节可以看shadergraph及shader代码~
三、绘制shadergraph
按照惯例上连连看!
图2 电流shadergraph
四、翻译为urpshader
按照惯例上shader!
Shader "3d/electricity"
{
Properties
{
_FirstUvOffsetSpeed("Speed", Vector) = (0, 0.3,0,0)
_SecondUvOffsetSpeed("Speed (1)", Vector) = (0, -0.3,0,0)
_testFloat("testFloat", Float) = 0.6
_Color("Color", Color) = (1, 0.7926317, 0, 0)
[NoScaleOffset]_MainTex("MainTex", 2D) = "white" {}
}
SubShader
{
Tags
{
"RenderPipeline"="UniversalPipeline"
"RenderType"="Opaque"
"UniversalMaterialType" = "Unlit"
"Queue"="Geometry"
}
Pass
{
Name "ELECTRICITY"
Tags
{
"LightMode" = "UniversalForward"
}
Cull Back
Blend One Zero
ZTest LEqual
ZWrite On
HLSLPROGRAM
#pragma target 3.0
#pragma exclude_renderers d3d11_9x
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Texture.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DBuffer.hlsl"
struct Attributes
{
float3 positionOS : POSITION;
float3 normal:NORMAL;
half4 uv0 : TEXCOORD0;
half4 color:COLOR;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
half4 uv : TEXCOORD0;
};
CBUFFER_START(UnityPerMaterial)
float2 _SecondUvOffsetSpeed;
float2 _FirstUvOffsetSpeed;
float _testFloat;
float4 _Color;
float4 _MainTex_TexelSize;
CBUFFER_END
// Object and Global properties
SAMPLER(SamplerState_Linear_Repeat);
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);
inline float Unity_SimpleNoise_RandomValue_float (float2 uv)
{
float angle = dot(uv, float2(12.9898, 78.233));
#if defined(SHADER_API_MOBILE) && (defined(SHADER_API_GLES) || defined(SHADER_API_GLES3) || defined(SHADER_API_VULKAN))
// 'sin()' has bad precision on Mali GPUs for inputs > 10000
angle = fmod(angle, TWO_PI); // Avoid large inputs to sin()
#endif
return frac(sin(angle)*43758.5453);
}
inline float Unity_SimpleNnoise_Interpolate_float (float a, float b, float t)
{
return (1.0-t)*a + (t*b);
}
inline float Unity_SimpleNoise_ValueNoise_float (float2 uv)
{
float2 i = floor(uv);
float2 f = frac(uv);
f = f * f * (3.0 - 2.0 * f);
uv = abs(frac(uv) - 0.5);
float2 c0 = i + float2(0.0, 0.0);
float2 c1 = i + float2(1.0, 0.0);
float2 c2 = i + float2(0.0, 1.0);
float2 c3 = i + float2(1.0, 1.0);
float r0 = Unity_SimpleNoise_RandomValue_float(c0);
float r1 = Unity_SimpleNoise_RandomValue_float(c1);
float r2 = Unity_SimpleNoise_RandomValue_float(c2);
float r3 = Unity_SimpleNoise_RandomValue_float(c3);
float bottomOfGrid = Unity_SimpleNnoise_Interpolate_float(r0, r1, f.x);
float topOfGrid = Unity_SimpleNnoise_Interpolate_float(r2, r3, f.x);
float t = Unity_SimpleNnoise_Interpolate_float(bottomOfGrid, topOfGrid, f.y);
return t;
}
float GetSimpleNoiseValue(float2 UV, float Scale)
{
float t = 0.0;
float freq = pow(2.0, float(0));
float amp = pow(0.5, float(3-0));
t += Unity_SimpleNoise_ValueNoise_float(float2(UV.x*Scale/freq, UV.y*Scale/freq))*amp;
freq = pow(2.0, float(1));
amp = pow(0.5, float(3-1));
t += Unity_SimpleNoise_ValueNoise_float(float2(UV.x*Scale/freq, UV.y*Scale/freq))*amp;
freq = pow(2.0, float(2));
amp = pow(0.5, float(3-2));
t += Unity_SimpleNoise_ValueNoise_float(float2(UV.x*Scale/freq, UV.y*Scale/freq))*amp;
return t;
}
float GetRemapValue(float In, float2 InMinMax, float2 OutMinMax)
{
return OutMinMax.x + (In - InMinMax.x) * (OutMinMax.y - OutMinMax.x) / (InMinMax.y - InMinMax.x);
}
float GetRectangleNicestValue(float2 UV, float Width, float Height)
{
UV = UV * 2.0 - 1.0;
float2 w = float2(Width, Height); // rectangle width/height
#if defined(SHADER_STAGE_RAY_TRACING)
float2 o = saturate(0.5f + 1e7 * (w - abs(UV)));
o = min(o, 1e7 * w * 2.0f);
#else
float2 f = min(fwidth(UV), 0.5f);
float2 k = 1.0f / f;
float2 o = saturate(0.5f + k * (w - abs(UV)));
o = min(o, k * w * 2.0f);
#endif
return o.x * o.y;
}
Varyings vert(Attributes input)
{
const float3 positionWS = TransformObjectToWorld(input.positionOS);
Varyings outPut;
outPut.positionCS = TransformWorldToHClip(positionWS);
outPut.uv = input.uv0;
return outPut;
}
half4 frag(Varyings packedInput) : SV_TARGET
{
const half2 uv = packedInput.uv.xy;
const float time = _TimeParameters.x;
UnityTexture2D mainTex2D = UnityBuildTexture2DStructNoScale(_MainTex);
const float4 mainColor = SAMPLE_TEXTURE2D(mainTex2D.tex, mainTex2D.samplerstate, mainTex2D.GetTransformedUV(uv));
const float2 firstSpeedMulTime = _FirstUvOffsetSpeed * (time.xx);
const half2 firstOffsetUv = uv * half2(1, 1) + firstSpeedMulTime;
const float noiseUv = GetSimpleNoiseValue(firstOffsetUv, 20);
const half2 secondSpeedMulTime = _SecondUvOffsetSpeed * (time.xx);
const half2 secondOffsetUv = uv * half2(1, 1) + secondSpeedMulTime;
const float noiseUv2 = GetSimpleNoiseValue(secondOffsetUv, 20);
const float finalNoise = noiseUv + noiseUv2;
const float remapValue = GetRemapValue(finalNoise, half2 (0, 1), half2 (-25, 5));
const float rectangleValue = GetRectangleNicestValue((remapValue.xx), 1, 1);
const half4 electricityColor = _Color * (rectangleValue.xxxx);
half4 finalColor = mainColor + electricityColor;
return half4(finalColor.xyz,1);
}
ENDHLSL
}
}
FallBack "Hidden/Universal Render Pipeline/FallbackError"
}五、结语
一个好用的电流效果,请收好,3d篇效果还在持续进行中,欢迎大家收藏关注~ |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|