Shader实验室: RayMarching(一)

介绍

相信玩过ShaderToy的伙伴都对上图印象深刻,除了上图所呈现的效果外,ShaderToy的绝大多数3D效果都使用到了RayMarching技术,该算法通常与Signed distance functions(有符号距离函数,简称 SDF )结合来实现各种炫酷的效果。

原理

在开始RayMarching原理分析之前,我们不得不先分析下有符号距离函数的概念,因为有符号距离函数是RayMarching算法中创建3D形状最通用的方式。
有符号距离函数
为了更细致的分析有符号距离函数(简称为 SDF ),我们假设空间中有一球体,同时空间中还存在另一点A,当点A在球体内部时,则A点到球心的距离小于球的半径,即 length(A) - r < 0 ;当点A在球体表面上时,则A点到球心的距离等于球的半径,即 length(A) - r = 0 ; 当点A远离球体表面时,则A点到球心的距离大于球的半径,即 length(A) - r > 0 ;上述的表述可用以下公式表示(假设球体的半径为1):
    
float sphereSDF ( float3 p ) { return length ( p ) - 1.0 ; }
上式是球体的SDF公式,更多的SDF公式可查阅 SDF距离函数
RayMarching算法
通过上述SDF的简单分析后我们已经有了建立各种基础形状的SDF函数,那么我们如何渲染他们呢?
RayMarching翻译为中文的意思为光线行进,要介绍它就需要先介绍下RayTracing(光线追踪),从字面上看这类型的技术与光线相关,在现实世界中光线的行进方向从光源开始,在经过一系列的反射,散射或折射的过程后进入眼睛。但是在计算机世界中,如果要从光源位置开始计算光线经过的一系列路径,最后进入人眼的全过程,会变得异常复杂,因为所有行进的光线不会全部进入人眼,这往往增加了巨大的工作量,因为我们最终想要的仅仅是被光源影响后的直接或间接光照后的结果图像,那么为了避免无谓的运算,通过从眼睛或相机发出射线来反方向追踪光线就变成了最直接的处理方式。
<img src="https://u3d-connect-cdn-public-prd.cdn.unity.cn/h1/20200406/p/images/697dce1d-637c-4143-b962-46b4c00cf9b2_raytrace.png" style="text-align:center;width:300px;height:200px;display:block;margin:0 auto">
上图是来自维基百科RayTracing的图示,与RayTracing一样,我们为相机选择一个位置,在相机前放置一个网格,通过网格中的每个点发送来自相机的射线,每个网格点对应于输出图像中的一个像素。在光线行进中,整个场景是根据SDF函数定义的。为了找到视线和场景之间的交点,我们从摄影机开始,沿着视线一点一点地移动。在每个步骤中,我们会获取点与物体中心的距离,直到获取到的点与物体中心的距离小于物体表面到物体中心的距离时,代表此时的点已经在物体的内部了。反之就将沿着射线不断增加最大数量。
<img src="https://u3d-connect-cdn-public-prd.cdn.unity.cn/h1/20200406/p/images/7bd81cfc-8bc1-4a83-a361-159021aeb990_spheretrace.jpg" style="text-align:center;width:400px;height:244px;display:block;margin:0 auto">

实验

1.新建Unlit着色器后,在片元着色器中定义相机位置与行进方向。
    
// 定义球体SDF,半径为1 float sdfSphere ( float3 p ) { return length ( p ) - 1 ; } // 获取当前行进点与物体中心的距离 float getDist ( float3 p ) { float sdf = sdfSphere ( p ) ; return sdf ; } fixed4 startRay ( float3 ro , float3 rd , fixed4 col ) { float dStart = 0 ; float dSphere ; fixed4 resultCol = fixed4 ( 1.0 , 1.0 , 1.0 , 1.0 ) ; for ( int i = 0 ; i <= _MaxDist ; i ++ ) { // 当行进距离超出了最大距离时返回背景色 if ( dStart > _MaxDist ) { resultCol = col ; break ; } // 从相机位置开始行进 float3 p = ro + rd * dStart ; dSphere = getDist ( p ) ; dStart += dSphere ; // 当行进点与物体中心距离小于半径时,表示已经碰触到了物体 // 小于0.01表示接近于物体表面 if ( dSphere < 0.01 ) { resultCol = fixed4 ( 1 , 1 , 1 , 1 ) ; break ; } } return resultCol ; } float3 getRayDir ( float2 uv ) { // uv坐标原点移至屏幕中心,uv范围为-0.5~0.5 float2 coord = uv - 0.5 ; // 使画面的x方向不至于拉伸 coord . x *= screenSize . x / screenSize . y ; return normalize ( float3 ( coord . x , coord . y , 1 ) ) ; } fixed4 frag ( v2f i ) : SV_Target { // 建立网格,确立行进方向 float3 rd = getRayDir ( i . uv ) ; // 相机位置 float3 rayOri = _WorldSpaceCameraPos ; fixed4 col = tex2D ( _MainTex , i . uv ) ; fixed4 result = startRay ( rayOri , rd , col ) ; return result ; }
2.新建C#脚本,传递屏幕尺寸。
    
using System . Collections ; using System . Collections . Generic ; using UnityEngine ; [ ExecuteInEditMode ] public class RayMarching : MonoBehaviour { public Material mat ; private void OnRenderImage ( RenderTexture src , RenderTexture dest ) { if ( ! mat ) { Graphics . Blit ( src , dest ) ; return ; } mat . SetVector ( "screenSize" , new Vector2 ( Screen . currentResolution . width , Screen . currentResolution . height ) ) ; Graphics . Blit ( src , dest , _mat ) ; } }
3.此时在屏幕上输出的结果图像如下:
注意,上面那个白色圆形,确实是个球,为了证明它是个球,下一篇将会引入基础的光照模型,除了这些我们还发现转动相机并没有改变模型的位置,显然是一个bug,下篇实验也会对此进行分析并提出解决方案。我们可以试着在场景中增加一个Cube,发现白色球体一直在立方体前方,这些优化的点,将会在后续的RayMarching系列实验中一并解决。
本篇实验就到这里了,那么我们下次实验见吧。如果觉得有用,就用微信扫描下面的二维码,关注我们吧!更多干货一起互撩。
<img src="https://u3d-connect-cdn-public-prd.cdn.unity.cn/h1/20200406/p/images/f6f110ec-1a11-465a-bc68-12484f81b109_qrcode_for_gh_7256935cd7f7_344.jpg" style="text-align:center;width:344px;height:344px;display:block;margin:0 auto">
混合动力汽车(HEV)模型的Simscape模型(Matlab代码、Simulink仿真实现)内容概要:本文档介绍了个混合动力汽车(HEV)的Simscape模型,该模型通过Matlab代码和Simulink仿真工具实现,旨在对混合动力汽车的动力系统进行建模与仿真分析。模型涵盖了发动机、电机、电池、传动系统等关键部件,能够模拟车辆在不同工况下的能量流动与控制策略,适用于动力系统设计、能耗优化及控制算法验证等研究方向。文档还提及该资源属于个涵盖多个科研领域的MATLAB仿真资源包,涉及电力系统、机器学习、路径规划、信号处理等多个技术方向,配套提供网盘下载链接,便于用户获取完整资源。; 适合人群:具备Matlab/Simulink使用基础的高校研究生、科研人员及从事新能源汽车系统仿真的工程技术人员。; 使用场景及目标:①开展混合动力汽车能量管理策略的研究与仿真验证;②学习基于Simscape的物理系统建模方法;③作为教学案例用于车辆工程或自动化相关课程的实践环节;④与其他优化算法(如智能优化、强化学习)结合,实现控制策略的优化设计。; 阅读建议:建议使用者先熟悉Matlab/Simulink及Simscape基础操作,结合文档中的模型结构逐步理解各模块功能,可在此基础上修改参数或替换控制算法以满足具体研究需求,同时推荐访问提供的网盘链接获取完整代码与示例文件以便深入学习与调试。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值