Unity Shader学习:简单RayMarching(光线步进)
Unity Shader学习:简单RayMarching(光线步进)
简单raymarching实现,还是很好玩的,当然和Shadertoy上的大佬比不了。
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
}
}
}