Unity立体渲染系列教程链接:

Unity教程|立体渲染(一)

Unity立体渲染(二)|Raymarching

Unity立体渲染(三)|表面着色


  在立体渲染(Volumetric Rendering,为保持一致,本系列译文均称立体渲染)系列第一篇文章——Unity教程|立体渲染中,我们简单介绍了立体渲染的基本概念。对立体渲染不太熟悉的开发者,请先查阅第一篇文章。

本系列教程全集:
第一篇:立体渲染。介绍立体渲染的概念以及在Unity中如何实现立体渲染。 第二篇:光线追踪。文章着重说明如何实现距离辅助的光线追踪,这是是渲染立体的事实性标准技术。 第三篇:表面着色。全面指引如何逼真地进行立体着色。 第四篇:有向距离函数。一篇对于数学工具更深入的讨论,让我们能制作和组合任意几何体。

尽管传统着色器只能渲染材质的外壳,但还是有办法让光线穿透到材质内部的几何体,创造画面的深度。Raymarch就是最常用的技术,第一篇文章使用Raymarch技术在立方体内绘制了一个红色球体。本文将深入为大家介绍效率更高的Raymarch实现方案。

引言
不严谨地说,当光线从相机发射到物体表面时,Unity 5光照引擎的标准行为是停止渲染。目前并没有内建机制能让这些射线穿透物体表面进入内部。为了补偿这个缺陷,我们引入了光线追踪(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); } 

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函数的多种不同实现。

固定步长(Constant Step)的光线追踪
在立体渲染系列文章第一篇中实现的光线追踪就使用了固定步长。每一束射线都会沿视线方向延伸STEP_SIZE的长度,直到击中目标为止。上篇的示例将目标绘制为红色,而其他部分为白色。

165952em3ecma6ce65qzaa.png

固定步长的光线追踪可以通过下列代码实现:

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 
}


上篇已经看到其渲染结果是看起来像平面的几何体:

165952emxhr0t2r1fuypgy.png

下面是距离辅助的光线追踪实现代码:

fixed4 raymarch (float3 position, float3 direction) 
{ 
  for (int i = 0; i < STEPS; i++) { 
  float distance = sphereDistance(position); 
  if (distance < MIN_DISTANCE) 
  return i / (float) STEPS; position += distance * direction; } 
  return 0; 
}


为了更好地理解它的工作原理,将表面着色替换为渐变色,来表示光线追踪命中几何体前究竟需要多少个步骤:

190316gllmlrzduockbssr.gif

很明显,立刻就能找出面向相机的平面几何体。其边缘相比之前复杂了许多。这种技术同样可以估算出到附近任意几何体之间的距离。

结论
本文介绍了实现实时光线追踪着色器实际可用的标准技术。射线会先保守估计到附近几何体的最近距离,再根据该距离进入立体空间。
下一篇文章将着重介绍使用距离函数创建基本几何体的方法,以及如何组合这些几何体以便得到您想要的任意形状。

锐亚教育

锐亚教育 锐亚科技 unity unity教程