基础概念

在3D游戏引擎中,球体、立方体以及所有其它复杂的集合体都是由三角面片组成的。引擎只会渲染物体的表面,比如球体,半透明物体等.整个世界由各种空壳构成.

立体渲染(Volumetric Rendering)的基本概念:模拟光线在物体内部的传送,从而实现更震撼也更真实的视觉效果。

片段着色器最后返回的对象,是从特定角度看过去特定位置的颜色。

这种方式计算的颜色是完全随意的,因此返回的内容可以不必匹配几何体的真实渲染情况。

下图展示了一个3D立方体的例子。当片段着色器检测到立方体表面的颜色时,模拟光线传送,使得结果如同一个球体

立体射线投射 Volumetric Raycasting

用一个函数判断光线与自定义的几何体相交的问题,限制较大,只能模拟简单几何体比如球,圆柱等。

固定步长立体光线追踪 Volumetric Raymarching with Constant Step

不依赖相交函数的,基于迭代的,可以模拟任意几何体

一步一步的检测光线是否已经投射到红色球体

bool raymarchHit (float3 position, float3 direction)
{
for (int i = 0; i < STEPS; i++)
{
if ( sphereHit(position) )
return true; position += direction * STEP_SIZE;
} return false;
} bool sphereHit (float3 p)
{
return distance(p,_Centre) < _Radius;
}

距离辅助的光线追踪 Distance Aided Raymarching

固定步长的光线追踪非常低效,需要一种方法估算在遇到几何体之前需要走多远,

比如之前的sphereHit函数,不是返回bool值,而是距离球面的距离

float sphereDistance (float3 p)
{
return distance(p,_Centre) - _Radius;
}

该函数就是一个有向距离函数(signed distance function),正数在几何体外,负数在几何体上,0在几何体表面

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

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;
}

在一个比较复杂的场景运行的效果如下

STEPS 最大步数,需要根据图像形状调整

MIN_DISTANCE 不能是0,给一个比较合适的误差值0.01左右

SDF Signed Distance Fields(Functions) 有向距离场(函数) 组合

可以用组合的方式做出比较复杂的图形,例如那个很出名的蜗牛

简单来说 min返回并集,max返回交集

可以用类似Alpha混合的方式做多个形状的混合 as1 + (1-a)s2

还有很多种别的合并方式,如光滑合并

float sdf_smin(float a, float b, float k = 32)
{
float res = exp(-k*a) + exp(-k*b);
return -log(max(0.0001,res)) / k;
}

法线预估

Íñigo Quílez的方法是对周围其它点的距离场进行取样,来估算局部表面的曲率

float3 normal (float3 p)
{
const float eps = 0.01;
return normalize
( float3 (
map(p + float3(eps, 0, 0) ) - map(p - float3(eps, 0, 0)),
map(p + float3(0, eps, 0) ) - map(p - float3(0, eps, 0)),
map(p + float3(0, 0, eps) ) - map(p - float3(0, 0, eps))
) );
}

更多

ShaderToy中有很多效果很好的例子

MERCURY团队创建的hg_sdf库,有很多元物件与操作

一个简单的实例Unity Shader

效果如下,在Cube内绘制了一个球

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

Shader "Unlit/VolumetricText"
{
Properties
{
_BaseColor ("Base Color", Color) = (1,1,1,1)
_SphereColor ("Sphere Color", Color) = (1,0,0,1)
_SphereCentre("Sphere Centre",Vector) = (0,0,0)
_ShpereRange ("Sphere Range", Range(0.1,2)) = 0.8
}
SubShader
{
Tags { "RenderType"="Opaque" "LightMode" = "ForwardBase" }
LOD 100 Pass
{
CGPROGRAM
#include "Lighting.cginc" #pragma vertex vert
#pragma fragment frag #include "UnityCG.cginc" struct appdata
{
float4 vertex : POSITION;
}; struct v2f
{
float4 vertex : SV_POSITION;
float3 wPos : TEXCOORD0; //世界坐标
}; float4 _BaseColor;
float4 _SphereColor;
float3 _SphereCentre;
fixed _ShpereRange; //有向距离函数
float SphereDistance(float3 p)
{
return distance(p, _SphereCentre) - _ShpereRange;
} //光线追踪
fixed Raymarch(float3 position, float3 direction)
{
float STEPS = 10;
float MIN_DISTANCE = 0.01; for (int i = 0; i < STEPS; i++)
{
float distance = SphereDistance(position);
if (distance < MIN_DISTANCE)
return i / (float)STEPS; position += distance * direction;
}
return 0;
} //法线模拟_简单球形测试
float3 NormalEstimation_Sphere(float3 p)
{
return normalize(p - _SphereCentre);
} v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.wPos = mul(unity_ObjectToWorld, v.vertex).xyz;
return o;
} fixed4 frag (v2f i) : SV_Target
{
fixed4 col = _BaseColor;
float3 viewDirection = normalize(i.wPos - _WorldSpaceCameraPos);
fixed rayHit = Raymarch(i.wPos, viewDirection);
if (rayHit >= 0.01)
col = _SphereColor; //丢弃不在形状内的,测试,不在的改为白色
clip(col.a - 0.01); fixed3 normal = NormalEstimation_Sphere(i.wPos); //简单处理下光照
fixed3 lightDir = _WorldSpaceLightPos0.xyz; // Light direction
fixed3 lightCol = _LightColor0.rgb; // Light color fixed NdotL = max(dot(normal, lightDir), 0);
col.rgb = col * lightCol * NdotL;
return col;
}
ENDCG
}
}
}

参考网页

Unity教程|立体渲染

Unity3D体积烟雾制作思路分享

梯度下降法

comprehensive guide to volume rendering

立体渲染 Volumetric Rendering的更多相关文章

  1. Single-Pass Stereo Rendering for HoloLens——HoloLens的单程立体渲染

    原文网站:https://docs.unity3d.com/Manual/SinglePassStereoRenderingHoloLens.html Single-Pass Stereo Rende ...

  2. CSharpGL(30)用条件渲染(Conditional Rendering)来提升OpenGL的渲染效率

    CSharpGL(30)用条件渲染(Conditional Rendering)来提升OpenGL的渲染效率 当场景中有比较复杂的模型时,条件渲染能够加速对复杂模型的渲染. 条件渲染(Conditio ...

  3. Libgls 1.0.1 发布,OpenGL 立体渲染

    Libgls 1.0.1 只是修复了一些小问题,更新了 FindGLS.cmake 脚本. Libgls 允许 OpenGL 立体渲染,不需要硬件支持四缓冲立体.支持许多立体显示模式,从立体眼镜的3D ...

  4. Unity3d 基于物理渲染Physically-Based Rendering之最终篇

    前情提要: 讲求基本算法 Unity3d 基于物理渲染Physically-Based Rendering之specular BRDF plus篇 Unity3d 基于物理渲染Physically-B ...

  5. 画面渲染:实时渲染(Real-time Rendering)、离线渲染(Offline Rendering)[转]

    实时渲染(Real-time Rendering) 实时渲染的本质就是图形数据的实时计算和输出.最典型的图形数据源是顶点.顶点包括了位置.法向.颜色.纹理坐标.顶点的权重等.在第一代渲染技术中(198 ...

  6. 《VR入门系列教程》之13---相机与立体渲染

    相机.透视图.视口.投影     渲染好的场景都需要一个可以供用户查看的视图,我们通常在3D场景中用相机来提供这种需求.相机相对场景有位置和方向,就像我们生活中的相机一样,它也提供透视图查看方式,这种 ...

  7. Unity3d 基于物理渲染Physically-Based Rendering之specular BRDF

    在实时渲染中Physically-Based Rendering(PBR)中文为基于物理的渲染它能为渲染的物体带来更真实的效果,而且能量守恒 稍微解释一下字母的意思,为对后文的理解有帮助,从右到左L为 ...

  8. unity, 替换shader渲染(Rendering with Replaced Shaders)

    实现特效,尤其是一些后处理特效,经常需要将各物体的shader替换为另一套shader进行渲染到纹理,再后再进行合成或以某种叠加方式叠加到最后的画面上去. 再复杂一点儿的,可能不同的物体所用的替换sh ...

  9. unity, 替换shader渲染(Rendering with Replaced Shaders)【转】

    实现特效,尤其是一些后处理特效,经常需要将各物体的shader替换为另一套shader进行渲染到纹理,再后再进行合成或以某种叠加方式叠加到最后的画面上去. 再复杂一点儿的,可能不同的物体所用的替换sh ...

随机推荐

  1. POJ 1144 割点

    题意 :求割点的数量 #include<iostream> #include<stdio.h> #include<vector> #include<strin ...

  2. java基础 4 继承(1)访问权限与作用域

    作用域与可见性 当前类 同一package 子类 其他package public √ √ √ √ protected √ √ √   defalut √ √     private √      

  3. ModelAndView对象作用

    ModelAndView ModelAndView对象有两个作用: 作用一  :设置转向地址,如下所示(这也是ModelAndView和ModelMap的主要区别) ModelAndView mv = ...

  4. cors跨域深刻理解

    1.跨域问题只出现在前端和后端不在同一个主机上.前后端在同一个主机上不会出现跨域问题. 2.浏览器的一种自我保护机制,不允许出现本地浏览器ajax异步请求访问127.0.0.1以外的系统,因为浏览器不 ...

  5. MIT 操作系统实验 MIT JOS lab1

    JOS lab1 首先向MIT还有K&R致敬! 没有非常好的开源环境我不可能拿到这么好的东西. 向每个与我一起交流讨论的programmer致谢!没有道友一起死磕.我也可能会中途放弃. 跟丫死 ...

  6. 基于 Vue.js 之 iView UI 框架非工程化实践记要 使用 Newtonsoft.Json 操作 JSON 字符串 基于.net core实现项目自动编译、并生成nuget包 webpack + vue 在dev和production模式下的小小区别 这样入门asp.net core 之 静态文件 这样入门asp.net core,如何

    基于 Vue.js 之 iView UI 框架非工程化实践记要   像我们平日里做惯了 Java 或者 .NET 这种后端程序员,对于前端的认识还常常停留在 jQuery 时代,包括其插件在需要时就引 ...

  7. centos+nginx+php-fpm+php include fastcgi_params php页面能訪问但空白,被fastcgi_params与fastcgi.conf害慘了

    今天在centos上折腾这块是发现老是訪问页面时,浏览器中提示是200 ok.且訪问html后缀却是正常出现内容. 可是訪问php后缀却返回空白页面,同一时候查看全部的log没有发现不论什么出错信息; ...

  8. web.xml中的ServletContextListener

    要想了解ServletContextListener,先看看web.xml中的<listener>配置. 一)web.xml中的内容载入顺序: 首先能够肯定的是,载入顺序与它们在 web. ...

  9. 使用HD/IDE层的ioctl接口获取磁盘容量get_hdd_max_sector

    利用HD/IDE layer的ioctl函数接口获取HD/IDE的磁盘容量.HDIO_DRIVE_TASK  能发出訪问LBA地址的命令.但不能读写数据. #include <stdio.h&g ...

  10. asp.net mvc + javascript生成下载文件

    近期做的是对现有项目进行重构.WEB FROM改成MVC,其实也算是推倒重来了. 里面有一个导出功能,将数据输出成txt文件,供下载.原先的做法是有一个隐藏的iframe,在这个iframe的页面中设 ...