shader 获取法线_Ray-Marching 绘制图形的法线信息【Unity Shader】

本文介绍如何使用Unity Shader通过Ray-Marching技术获取并绘制图形的法线信息。通过球体和立方体的 Signed Distance Function (SDF) 实现,详细展示了Shader代码,包括法线计算、光照处理等步骤。
摘要由CSDN通过智能技术生成

代码参考自: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"

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值