Unity Shader学习:简单RayMarching(光线步进)

Unity Shader学习:简单RayMarching(光线步进)

简单raymarching实现,还是很好玩的,当然和Shadertoy上的大佬比不了。
Unity Shader学习:简单RayMarching(光线步进)
Unity Shader学习:简单RayMarching(光线步进)
shader部分:

Shader "Custom/RayMarching"
{
	Properties
	{
		_MainTex("MainTex",2D)="white"{}
		//相机位置
		_CamPos("CamPos",Vector) = (0,0,0,0)
		//球体位置,w分量为半径
		_SpherePos("SpherePos",Vector) = (0,0,0,0)
		_BoxPos("BoxPos",Vector)=(0,0,0,0)
		//立方体旋转
		_BoxRotation("BoxRotation",Vector)=(0,0,0,0)
		//光源位置,w分量为强度
		_LightPos("LightPos",Vector)=(0,0,0,0)
		//抗锯齿采样数
		_AAFactor("AAFactor",Range(1,5))=3
	}
	SubShader
	{
		Tags{"RenderType" = "Opaque"}
		Pass{
			CGPROGRAM
			#pragma vertex vert_img
			#pragma fragment frag
			#include "UnityCG.cginc"
			#include "Lighting.cginc"		

			float4 _CamPos;
	        float4 _SpherePos;
			float4 _TargetPos;
			float4 _LightPos;
			float4 _BoxPos;
			float4 _BoxRotation;
			int _AAFactor;
			sampler2D _MainTex;

			//球体
			float sdfSphere(float3 rayPos,float3 spherePos,float radius) {
				return length(rayPos-spherePos) - radius;
            }	        	      

            //立方体
			float sdfBox(float3 rayPos,float3 boxPos,float3 scale) {
				float3 d = abs(rayPos - boxPos) - scale;
				return length(max(d, 0.0));
            }

	        //并集操作
			float operationUnion(float d1,float d2) {
				return (d1 < d2) ? d1 : d2;
            }

			//相减操作
			float opSubtraction(float d1, float d2) {
				return max(-d1, d2);
			}

			//Y轴旋转
			float3 rotateY(float3 pos, float t) {
				pos.xz = mul(float2x2(cos(t), -sin(t), sin(t), cos(t)),pos.xz);
				return pos;
			}

			//X轴旋转
			float3 rotateX(float3 pos, float t) {
				pos.yz = mul(float2x2(cos(t), -sin(t), sin(t), cos(t)), pos.yz);
				return pos;
			}

			//Z轴旋转
			float3 rotateZ(float3 pos, float t) {
				pos.xy = mul(float2x2(cos(t), -sin(t), sin(t), cos(t)), pos.xy);
				return pos;
			}

			//布置整个场景
			float Map(float3 pos) {
				float3 posRotate = rotateY(rotateZ(rotateX(pos, _BoxRotation.x*-_Time.x),_BoxRotation.z),_BoxRotation.y);
				float3 box = sdfBox(posRotate, _BoxPos.xyz, float3(0.5, 0.5, 0.5));
				float3 sphere = sdfSphere(pos, _SpherePos.xyz, _SpherePos.w);
				return opSubtraction(sphere,box);
			}

			//求射线的交点步进数
			float intersects(float3 ro, float3 drt) {
				float t;
				for (int i = 0; i < 255; ++i)
				{
					float res = Map(ro+drt*t);
					t += res;
					if (res<0.00001)
					{
						return t;
					}
				}
				return 10000;
			}

			//计算法线
			float3 Normal(float3 surface_pos) {
				float3 eps = float3(0.0001, 0.0, 0.0);
				float3 nor = float3(
					Map(surface_pos + eps.xyy).x - Map(surface_pos - eps.xyy).x,
					Map(surface_pos + eps.yxy).x - Map(surface_pos - eps.yxy).x,
					Map(surface_pos + eps.yyx).x - Map(surface_pos - eps.yyx).x);
				return normalize(nor);
			}

			//渲染物体
			float4 render(float3 ro, float3 rd) {
				float3 drt = normalize(rd - ro);
				float3 light = _LightPos.xyz;
				float t = intersects(ro, drt);
				if (t <= 1000)
				{
					float3 surface_pos = ro + drt * t;
					float3 L = surface_pos - light;
					float3 N = Normal(surface_pos);
					//半兰伯特
					float3 diffuse = max(0.0, dot(N, L))*_LightPos.w*0.5+0.25;
					return float4(diffuse, 1);
				}
				else
				{
					return float4(0, 0, 0, 1);
				}
			}

			float4 frag(v2f_img i):SV_Target{
				float2 uv = i.uv - 0.5;
				float3 rayOriPos, rayDir;
				float3 finalCol;
				//抗锯齿
				for (int m = 0; m < _AAFactor; m++)
				{
					for (int n = 0; n < _AAFactor; n++)
					{						
						float2 o = float2(m, n) / _AAFactor - 0.5;
						//抗锯齿采样偏移
						uv = uv + o * 1.0 / 1080.0*2;
						//设定相机位置、每个像素射线方向
						rayOriPos = _CamPos.xyz;
						rayDir = float3(4.0, uv*0.5);
						float3 col = render(rayOriPos, rayDir);
						finalCol += col;
					}
				}
				return float4(finalCol / (_AAFactor*_AAFactor), 1.0);
            }
			ENDCG
        }
	}

}