做商城网站会不会被攻击,免费WAP建导航网站,微信小程序里的网站怎么做,学历提升报名基于光线步进的体积光 2025年4月16日12:59:42
体积光是在体积云的基础上完成的。
首先我们要解决一个问题#xff0c;我的光的颜色是怎么出来的#xff1f;
回顾一下体积云#xff0c;体积云的颜色#xff0c;是射线上的float叠加出来的#xff0c;那么体积光也是这样我的光的颜色是怎么出来的回顾一下体积云体积云的颜色是射线上的float叠加出来的那么体积光也是这样他是这样一个算法原理在光线步进的情况下也是算密度如何计算那个步进的小段里面有没有密度呢。因为是体积光我们采取的是这样一个操作让步进的那个位置向上进行采样与最顶上相交得到一个二维点坐标使用这个坐标去采样一个噪声如果采样到的是黑的那就是无光也就是没密度白的反之而这个向上也不用垂直我们可以拿太阳光方向从而达到一个体积光的效果。那就开码也是复习一下体积云部分了首先思路理清从摄像机出发那么就要有一个本源发射点碰到容器盒一个容器发射点一个发射方向做好数据准备,一步步下去还是挺简单的。之后把累加的密度加入衰减公式可以达到这样的效果。此时的代码是这样的Shader JH/体积光复习版 { Properties { _Noise(Noise, 2D) white {} _BlueNoise(BlueNoise, 2D) white {} _CausticMap(CausticMap, 2D) white {} _Absorption (Absorption, float) 0.5 _AbsorptionLerp(AbsorptionLerp, Range(0, 1)) 0.5 _Density(Density, float) 0.5 _Color1(Color1, Color) (1,1,1,1) _Color2(Color2, Color) (1,1,1,1) } SubShader { Cull front Tags { RenderTypeTransparent } LOD 100 Pass { Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM #pragma vertex vert #pragma fragment frag #include UnityCG.cginc #include Lighting.cginc #include AutoLight.cginc struct appdata { float4 pos_OS : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 pos_CS : SV_POSITION; float3 pos_OS : TEXCOORD1; }; sampler2D _Noise; sampler2D _BlueNoise; sampler2D _CausticMap; float _Absorption; float _AbsorptionLerp; float4 _Color1; float4 _Color2; float _Density; bool intersectAABB(float3 rayOrigin, float3 rayDir, float3 boxMin, float3 boxMax, out float2 tNearFar) { float3 tMin (boxMin - rayOrigin) / rayDir; float3 tMax (boxMax - rayOrigin) / rayDir; float3 t1 min(tMin, tMax); float3 t2 max(tMin, tMax); float tNear max(max(t1.x, t1.y), t1.z); float tFar min(min(t2.x, t2.y), t2.z); tNearFar float2(tNear, tFar); return tFar tNear; } bool intersectPlane(float3 n, float3 p0, float3 rayPos, float3 rayDir, out float t) { // assuming vectors are all normalized float denom dot(-n, rayDir); if (denom 1e-6) { float3 difference p0 - rayPos; t dot(difference, -n) / denom; return (t 0); } return false; } float GetCaustic(float2 uv) { //这里对输出的值进行处理使得其更加随机 float2 noise tex2D(_Noise, uv _Time.y * 0.1); float blueNoise tex2D(_BlueNoise, uv * 5); float caustic_d1 tex2D(_CausticMap, uv * 0.8 _Time.y * 0.02 noise * 0.2); float caustic_d2 tex2D(_CausticMap, uv * 0.8 - _Time.y * 0.02 caustic_d1 * 0.05); float caustic2 tex2D(_CausticMap, uv * 0.5 - _Time.y * 0.02 caustic_d2); return caustic2 * blueNoise * 5; } #define _G0 -0.1 #define _G1 0.1 float hg(float a, float g) { float g2 g * g; return (1 - g2) / (4 * 3.1415 * pow(1 g2 - 2 * g * (a), 1.5)); } float hg2(float a) { return lerp(hg(a, _G0), hg(a, _G1), _AbsorptionLerp); } float multipleOctaves(float depth, float mu) { float luminance 0; int octaves 8; // Attenuation float a 1; // Contribution float b 1; // Phase attenuation float c 1; float phase; for (int i 0; i octaves; i) { phase lerp(hg(mu, _G0 * c), hg(mu, _G1 * c), _AbsorptionLerp); luminance b * phase * exp(-depth * a * _Absorption); a * 0.2f; b * 0.5f; c * 0.5f; } // return hg2(mu) * Transmittance(depth, _Absorption); return luminance; } v2f vert (appdata v) { v2f o; o.pos_CS UnityObjectToClipPos(v.pos_OS); o.pos_OS v.pos_OS.xyz; o.uv v.uv; return o; } fixed4 frag (v2f i) : SV_Target { //对象空间下的光源位置 float3 LDir_OSnormalize(mul((float3x3)unity_WorldToObject, _WorldSpaceLightPos0.xyz)); float height i.pos_OS.y 0.5; float noise tex2D(_Noise, i.pos_OS.xz).r; //对象空间下的相机位置 float3 CameraPos_OSmul(unity_WorldToObject,float4(_WorldSpaceCameraPos,1)).xyz; //对象空间下的发射方向 float3 VDir_OSnormalize(i.pos_OS.xyz-CameraPos_OS); float cosTheta dot(LDir_OS, VDir_OS); float phase hg2(cosTheta); //AABB包围盒计算碰撞点以及通过的距离 float3 aabbMin float3(-0.5, -0.5, -0.5); float3 aabbMax float3(0.5, 0.5, 0.5); float2 aabbNearFar (float2)0; bool isHit intersectAABB(CameraPos_OS, VDir_OS, aabbMin, aabbMax, aabbNearFar); float tNear max(aabbNearFar.x, 0); float tFar aabbNearFar.y; float MaxDistance tFar - tNear; //计算光线与物体的交点 float3 HitPointBeginCameraPos_OSVDir_OS*tNear; float3 HitPointEndCameraPos_OSVDir_OS*tFar; //开始步进 float Step_Count50;//步进次数 float Step_Situation1.0/Step_Count;//步进状态 float3 Density0; UNITY_LOOP for(int i0;iStep_Count;i) { //步进位置使用lerp进行获取 float3 pos lerp(HitPointBegin,HitPointEnd,i*Step_Situation); //获取该位置向光照方向的射线与顶面的交点 //首先获得距离 float Distance_From_Pos_To_Plane0; //第一个是求交平面的法线方向第二个是求交平面的位置第三个为出发点第四个为方向第五个是inout的距离值 intersectPlane(float3(0,-1,0),float3(0, 0.5, 0),pos,LDir_OS,Distance_From_Pos_To_Plane); //获得交点 float3 PlaneHitPointposLDir_OS*Distance_From_Pos_To_Plane; //使用交点坐标采样噪声贴图 float3 caustic GetCaustic(PlaneHitPoint.xz); //计算密度 Densitycaustic*Step_Situation; } return exp(-Density*_Absorption).xyzz; } ENDCG } } }之后加上体积云里面的大气散射函数以及加上相应的颜色既可以达到这样的效果追加代码Density Density * smoothstep(0.2, 1.1 noise, height) * 20; Density Density * multipleOctaves(height, cosTheta); float3 color lerp(_Color1, _Color2, height) * 0.5 Density; float alpha exp(-MaxDistance * _Density); return float4(color, alpha);其实体积光的核心算法已经完成但是我们仍要精益求精我们先把体积光颜色改成彩色的它的原理是这样的我们不是到顶面去采样噪声吗其实也可以到顶面采样一些别的东西。比如说彩色的体积光也不是所有的都可以成为的所以我们可以在顶上采样一个遮罩使得特定区域的体积光成为彩色。之后我们可以使用HSV函数H不就是色相吗刚刚好符合我们的预期。我们用pos 的y轴塞进去使得高度不同的体积光颜色不同这不彩色的就来了之后再加上一些参数进行优化。效果就出来了。float noise tex2D(_Noise, PlaneHitPoint.xz).r; noise lerp(1, 1.3, noise); float3 causticColorful 5 * GetCaustic(PlaneHitPoint.xz) * hsv2rgb( float3( (pos.y _RainbowOffset dot(LDir_OS, -VDir_OS) * 0.1) * _RainbowScale * noise 0.5, _RainbowIntensity, 1) ); float rinbowMask tex2D(_RainbowMask, PlaneHitPoint.xz * 3); caustic lerp(caustic, causticColorful*1.5, rinbowMask) * 1.5;我把完整的代码放在这里Shader JH/体积光复习版 { Properties { _Noise(Noise, 2D) white {} _BlueNoise(BlueNoise, 2D) white {} _CausticMap(CausticMap, 2D) white {} _Absorption (Absorption, float) 0.5 _AbsorptionLerp(AbsorptionLerp, Range(0, 1)) 0.5 _Density(Density, float) 0.5 [Header(Rainbow)] _RainbowMask(RainbowMask, 2D) white {} _RainbowIntensity(RainbowIntensity, float) 1 _RainbowScale(RainbowScale, float) 1 _RainbowOffset(RainbowOffset, float) 0 [Space(30)] _Color1(Color1, Color) (1,1,1,1) _Color2(Color2, Color) (1,1,1,1) } SubShader { Cull front Tags { RenderTypeTransparent } LOD 100 Pass { Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM #pragma vertex vert #pragma fragment frag #include UnityCG.cginc #include Lighting.cginc #include AutoLight.cginc struct appdata { float4 pos_OS : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 pos_CS : SV_POSITION; float3 pos_OS : TEXCOORD1; }; sampler2D _Noise; sampler2D _BlueNoise; sampler2D _CausticMap; float _Absorption; float _AbsorptionLerp; float4 _Color1; float4 _Color2; float _Density; sampler2D _RainbowMask; float _RainbowIntensity; float _RainbowScale; float _RainbowOffset; bool intersectAABB(float3 rayOrigin, float3 rayDir, float3 boxMin, float3 boxMax, out float2 tNearFar) { float3 tMin (boxMin - rayOrigin) / rayDir; float3 tMax (boxMax - rayOrigin) / rayDir; float3 t1 min(tMin, tMax); float3 t2 max(tMin, tMax); float tNear max(max(t1.x, t1.y), t1.z); float tFar min(min(t2.x, t2.y), t2.z); tNearFar float2(tNear, tFar); return tFar tNear; } bool intersectPlane(float3 n, float3 p0, float3 rayPos, float3 rayDir, out float t) { // assuming vectors are all normalized float denom dot(-n, rayDir); if (denom 1e-6) { float3 difference p0 - rayPos; t dot(difference, -n) / denom; return (t 0); } return false; } float GetCaustic(float2 uv) { //这里对输出的值进行处理使得其更加随机 float2 noise tex2D(_Noise, uv _Time.y * 0.1); float blueNoise tex2D(_BlueNoise, uv * 5); float caustic_d1 tex2D(_CausticMap, uv * 0.8 _Time.y * 0.02 noise * 0.2); float caustic_d2 tex2D(_CausticMap, uv * 0.8 - _Time.y * 0.02 caustic_d1 * 0.05); float caustic2 tex2D(_CausticMap, uv * 0.5 - _Time.y * 0.02 caustic_d2); return caustic2 * blueNoise * 5; } #define _G0 -0.1 #define _G1 0.1 float hg(float a, float g) { float g2 g * g; return (1 - g2) / (4 * 3.1415 * pow(1 g2 - 2 * g * (a), 1.5)); } float hg2(float a) { return lerp(hg(a, _G0), hg(a, _G1), _AbsorptionLerp); } float multipleOctaves(float depth, float mu) { float luminance 0; int octaves 8; // Attenuation float a 1; // Contribution float b 1; // Phase attenuation float c 1; float phase; for (int i 0; i octaves; i) { phase lerp(hg(mu, _G0 * c), hg(mu, _G1 * c), _AbsorptionLerp); luminance b * phase * exp(-depth * a * _Absorption); a * 0.2f; b * 0.5f; c * 0.5f; } // return hg2(mu) * Transmittance(depth, _Absorption); return luminance; } float3 hsv2rgb(float3 c) { float3 rgb clamp(abs(fmod(c.x * 6. float3(0., 4., 2.), 6.) - 3.) - 1., 0., 1.); rgb rgb * rgb * (3. - 2. * rgb); return c.z * lerp((float3)(1.), rgb, c.y); } float3 hsv2rgb(float h, float s, float v) { return hsv2rgb(float3(h, s, v)); } v2f vert (appdata v) { v2f o; o.pos_CS UnityObjectToClipPos(v.pos_OS); o.pos_OS v.pos_OS.xyz; o.uv v.uv; return o; } fixed4 frag (v2f i) : SV_Target { //对象空间下的光源位置 float3 LDir_OSnormalize(mul((float3x3)unity_WorldToObject, _WorldSpaceLightPos0.xyz)); float height i.pos_OS.y 0.5; float noise tex2D(_Noise, i.pos_OS.xz).r; //对象空间下的相机位置 float3 CameraPos_OSmul(unity_WorldToObject,float4(_WorldSpaceCameraPos,1)).xyz; //对象空间下的发射方向 float3 VDir_OSnormalize(i.pos_OS.xyz-CameraPos_OS); float cosTheta dot(LDir_OS, VDir_OS); float phase hg2(cosTheta); //AABB包围盒计算碰撞点以及通过的距离 float3 aabbMin float3(-0.5, -0.5, -0.5); float3 aabbMax float3(0.5, 0.5, 0.5); float2 aabbNearFar (float2)0; bool isHit intersectAABB(CameraPos_OS, VDir_OS, aabbMin, aabbMax, aabbNearFar); float tNear max(aabbNearFar.x, 0); float tFar aabbNearFar.y; float MaxDistance tFar - tNear; //计算光线与物体的交点 float3 HitPointBeginCameraPos_OSVDir_OS*tNear; float3 HitPointEndCameraPos_OSVDir_OS*tFar; //开始步进 float Step_Count50;//步进次数 float Step_Situation1.0/Step_Count;//步进状态 float3 Density0; UNITY_LOOP for(int i0;iStep_Count;i) { //步进位置使用lerp进行获取 float3 pos lerp(HitPointBegin,HitPointEnd,i*Step_Situation); //获取该位置向光照方向的射线与顶面的交点 //首先获得距离 float Distance_From_Pos_To_Plane0; //第一个是求交平面的法线方向第二个是求交平面的位置第三个为出发点第四个为方向第五个是inout的距离值 intersectPlane(float3(0,-1,0),float3(0, 0.5, 0),pos,LDir_OS,Distance_From_Pos_To_Plane); //获得交点 float3 PlaneHitPointposLDir_OS*Distance_From_Pos_To_Plane; //使用交点坐标采样噪声贴图 float3 caustic GetCaustic(PlaneHitPoint.xz); //加入彩虹 float noise tex2D(_Noise, PlaneHitPoint.xz).r; noise lerp(1, 1.3, noise); float3 causticColorful 5 * GetCaustic(PlaneHitPoint.xz) * hsv2rgb( float3( (pos.y _RainbowOffset dot(LDir_OS, -VDir_OS) * 0.1) * _RainbowScale * noise 0.5, _RainbowIntensity, 1) ); float rinbowMask tex2D(_RainbowMask, PlaneHitPoint.xz * 3); caustic lerp(caustic, causticColorful*1.5, rinbowMask) * 1.5; //计算密度 Densitycaustic*Step_Situation; } Density Density * smoothstep(0.2, 1.1 noise, height) * 20; Density Density * multipleOctaves(height, cosTheta); float3 color lerp(_Color1, _Color2, height) * 0.5 Density; float alpha saturate(exp(-MaxDistance * _Density)); return float4(color, alpha); } ENDCG } } }