思路
· 这个体渲染并不是投射射线的体渲染。以后会写常规体渲染给大家。
· 判断射线位置
我们知道视线的角度normalize(u),和 视线和球心的距离u`(_SpherePos - _CameraPos)
通过投影的逆运算,我们能求出视角U未来在球心垂面上的点位置。
即: p = normalize(U) · normalize(U`) * |U|
未来的位置为:视角法向量 点乘 视角和球心的法向量 乘以 视角和球心的模长,推导公式学了投影向量自然就会了,这里不累述。
然后通过对比 p和球心的长度是否小于半径,就可以实现简单的画圆。
· 求出球面法线向量
如果要在球体上使用光照模型,必然需要知道法线向量。
我们知道了坐标和半径的比值,通过反sin或者反cos值得到弧度,然后求弧度在π/2的比例就可以得出法向量的差值,进行视角向量和位置向量的插值运算即可。
源代码
Shader "QQ/Volume/Sphere"
{
Properties
{
_Color("Color",Color) = (0.5,0.5,0.5,1)
_Radius("radius",Range(0,1)) = 0.4
_Smoothness("smoothness",Range(0.1,1)) = 0.5
}
SubShader
{
Tags { "RenderType" = "Opaque"}
LOD 100
Pass
{
Tags{
"LightMode" = "ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
uniform fixed4 _Color;
uniform float _Radius;
uniform float _Smoothness;
uniform fixed4 _LightColor0;
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 pos : SV_POSITION;
float3 wPos:TEXCOORD0;
float3 normal : TEXCOORD1;
};
v2f vert(a2v v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.wPos = mul(unity_ObjectToWorld,v.vertex);
o.normal = v.normal;
return o;
}
inline float3 ToLocal(float3 pos)
{
return mul(unity_WorldToObject, float4(pos, 1.0)).xyz;
}
fixed4 frag(v2f i) : SV_Target
{
fixed4 col;
float3 pos = ToLocal(i.wPos);
float3 nor = UnityObjectToWorldNormal(i.normal);
float _i = length(pos) / _Radius;
if (_i > 1)
{
float3 camera = ToLocal(_WorldSpaceCameraPos.xyz);
float3 dir = normalize(pos - camera);
float len0 = distance(pos, camera);
float len1 = length(camera) * dot(dir, normalize(-camera));
if (len1 > len0)
{
pos = dir * len1 + camera;
_i = length(pos) / _Radius;
float3 dir0 = normalize(pos);
float3 dir1 = normalize(camera);
nor = UnityObjectToWorldNormal(normalize(lerp(dir1, dir0, asin(_i) / UNITY_PI * 2)));
}
}
if (_i <= 1)
{
float3 wPos = mul(unity_ObjectToWorld, pos);
float LdotN = max(dot(_WorldSpaceLightPos0.xyz, nor), 0);
float3 Half = normalize(normalize(_WorldSpaceLightPos0.xyz) + normalize(_WorldSpaceCameraPos.xyz - wPos));
float spec = pow(max(dot(nor, Half),0), _Smoothness * _Smoothness * 1000);
col = _Color * fixed4(UNITY_LIGHTMODEL_AMBIENT.rgb, 1.0) + (LdotN + spec) * fixed4(_LightColor0.rgb,1.0);
}
else
{
discard;
}
return col;
}
ENDCG
}
}
}