代码参考自:http://blog.csdn.net/baidu_26153715/article/details/46510703
效果如图:
完整代码及详细注释如下:
Shader "Custom/RayMarching"
{
Properties
{
//_MainTex ("Texture", 2D) = "white" {}
//_Cube("cubemap", cube) = ""{}
}
// http://blog.csdn.net/baidu_26153715/article/details/46510703
SubShader
{
// No culling or depth
Cull Off ZWrite Off ZTest Always
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
// 球体 (<=0)
float sdSphere(float3 p, float s)
{
return length(p) - s;
}
// 立方体
float udBox(float3 p, float3 b)
{
return length(max(abs(p) - b, 0.));
}
// p换算到相机空间
float3 P2CameraSpace(in float3 camPos, in float3 p)
{
float3 dian = float3(0, 0, 0);
float3 ArixY = float3(0, 1, 0);
float3 z = normalize(dian - camPos);
float3 x = normalize(cross(z, ArixY));
float3 y = normalize(cross(z, x));
float3 theCameraSpaceP = float3(
// dot(p, x), dot(p, y), dot(p, z)
//p.x*x + p.y*y + p.z*z
//mul(float3x3(x, y, z), p)
mul(p, float3x3(x, y, z))
);
return theCameraSpaceP;
}
// 步进的光线终点和球体表面的距离
float map(in float3 pos)
{
//float d = sdSphere(pos, 1);
float d = udBox(pos, float3(.5, .5, .5));
return d;
}
float3 normal(in float3 pos)
{
float2 offset = float2(.01, 0);
float3 nDir = normalize(
float3(
// 通过计算 xyz 三个方向的差值(梯度),归一化后得到法线方向
map(pos + offset.xyy) - map(pos - offset.xyy),
map(pos + offset.yxy) - map(pos - offset.yxy),
map(pos + offset.yyx) - map(pos - offset.yyx)
)
);
return nDir;
}
float marching(in float3 orgin, in float3 p)
{
float t = 1;// 步进的光线总长度
int i;
for (i = 0; i<64; ++i)
{
// 随着光线的步进,检查是否到达球体的表面
float3 sphere = orgin + t*p;
float d = map(sphere);
// 当距离小于一个最小阈值,或者长度超过一个最大阈值,则中断中循环
if (d < .02 || t>20)
break;
// 步进
t += d;
}
return t;
}
float3 render(in float3 pos, in float3 p)
{
// ray-marching
float d = marching(pos, p);
// 计算法线方向
float3 nDir = normal(pos + p*d);
float3 c = 0;
if (d<30)
{
// 光源方向
float3 lDir = normalize(half3(0, 1, 0));
// diffuse
float diff = max(0, dot(lDir, nDir));
// 将法线方向作为颜色返回
c = nDir;
}
return c;
}
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.uv;
return o;
}
//sampler2D _MainTex;
fixed4 frag (v2f i) : SV_Target
{
float time = _Time.y;
float2 uv = i.uv * 2 - 1;
float3 p = normalize(float3(uv, 2));
// 相机的世界坐标(随时间变化)
float3 camPos = float3(3 + sin(time), 3, 3 + cos(time));
// 将 p 点换算到相机坐标系
float3 theNewP = P2CameraSpace(camPos, p);
// 渲染模型的法线
float3 col = render(camPos, theNewP);
return float4(col, 1);
}
ENDCG
}
}
FallBack "Diffuse"
}