Notifications
Article
体积渲染简要《一》
Published 8 days ago
10
0
什么是体积渲染?
3D引擎如在处理几何的时候一般都是使用三角面。所有物体,都是由基础三角形构成的。也有物体不能由三角形构成,那就是体积渲染,利用光线追踪技术,然后使用几何公式来绘制图形。本文将从最简单的体积渲染例子开始体积渲染之旅。
摄像机的光线撞击物体表面时,Unity 引擎的标准行为会停止渲染。这些光线没有内置机制穿透物体表面。为了弥补这一点,我们引入了一种名为Raymarch的技术。具体实现是在我们在片段着色器里渲染的点的位置(在世界坐标中),以及来自摄像机的视图方向。我们可以手动扩展这些光线,使它们击中仅存在于着色器代码中的自定义几何体函数。
struct v2f { float4 pos : SV_POSITION; // Clip space float3 wPos : TEXCOORD1; // World position }; // Vertex function v2f vert (appdata_full v) { v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.wPos = mul(_Object2World, v.vertex).xyz; return o; } // Fragment function fixed4 frag (v2f i) : SV_Target { float3 worldPosition = i.wPos; float3 viewDirection = normalize(i.wPos - _WorldSpaceCameraPos); return raymarch (worldPosition, viewDirection); }
本文的Raymarch从简单的固定光线步进开始,光线在视图方向上由STEP_SIZE的距离进行步进,直到它碰到几何形状公式的边界。如果是这种情况,我们绘制红色像素,否则绘制白色像素。
以下代码是具体实现:
fixed4 raymarch (float3 position, float3 direction) { for (int i = 0; i < STEPS; i++) { if ( sphereHit(position) ) return fixed4(1,0,0,1); // Red position += direction * STEP_SIZE; } return fixed4(0,0,0,1); // White } //几何形状函数 bool sphereHit (float3 p) { //unity_ObjectToWorld._14_24_34 为物体的中心点 return distance(p, unity_ObjectToWorld._14_24_34) < _Radius; }
以下是完整的代码:
Shader "Raymarch/VolumetricRendering1"{ Properties{ _Radius("Radius", Range(0, 1.0)) = 1.0 } SubShader{ Tags { "RenderType"="Opaque" } LOD 100 Pass{ CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" #define STEPS 128 #define STEP_SIZE 0.01 struct appdata{ float4 vertex : POSITION; }; struct v2f{ float4 vertex : SV_POSITION; float3 wPos : TEXCOORD0; }; float _Radius; v2f vert (appdata v){ v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.wPos = mul(unity_ObjectToWorld, v.vertex).xyz; return o; } bool sphereHit (float3 p){ return distance(p, unity_ObjectToWorld._14_24_34) < _Radius; } fixed4 raymarch (float3 position, float3 direction){ for (int i = 0; i < STEPS; i++){ if(sphereHit(position)) return return fixed4(1,0,0,1); position += direction * STEP_SIZE; } return fixed4(0,0,0,1); } fixed4 frag (v2f i) : SV_Target{ float3 worldPosition = i.wPos; float3 viewDirection = normalize(worldPosition - _WorldSpaceCameraPos); return raymarch (worldPosition, viewDirection); } ENDCG } } }
在Unity里面创建一个Cube和材质,就能看到效果:
好了,效果出来了,是不是觉得很简单,今天就到这里,下次再见。
程庆宝
引擎专家 - Programmer
1
Comments