体渲染(一)渲染一个球体

来源:互联网 发布:sql语句update用法 编辑:程序博客网 时间:2024/04/28 00:57

最终效果


思路

伪体渲染

通常体渲染是模拟射线在模型中逐步判断,每个像素需要for循环若干次逐步递进,然后对每个路过的像素进行加工,步距决定精度,最终输出。
消耗相当高,但如果我们绘制的是可预测的规则模型,我们就可以预先算出射线的位置来进行判断。
优点是:效率极快,几乎可以避免逻辑判断和for循环。
缺点是:比较繁杂,不能实现象射线递进那样完全真实和自由的效果。

快速判断射线位置


关于求向量的投影大家自行百度,这里用了张百度搜的图片讲解。
我们知道视线的角度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 100Pass{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}}}


0 0
原创粉丝点击