[Unity Shader Base] RayMarching in Cloud Rendering

作者:一步一个foot-print日期:2025/11/14

基础知识:
1.SDF 有符号距离场,且通过正负可以判断在物体外部还是内部,通常外正内负

这是RayMarching的灵魂支撑,能够通过一个数学函数,输入一个空间中的点,输出这个点到物体表面的最短距离(带符号)。可以使复杂的几何形状可以通过简单的 SDF运算来组合。比如,两个球体的 SDF 可以通过 min() 操作来融合,通过 max() 来相交,通过 abs()和减法来创造出“镂空”效果。

RayMarching 区别于正常的射线求交,根据他的中文翻译名,光线步进,可以比较生动的理解。
光并非直接打到物体表面求交然后渲染,而是每一步都计算和物体表面的SDF,从而安全前进,循环直道命中物体或者超出最大步数结束。

第一种制作方法:

球体采用XYZW四维向量,W表示球体半径
在这里插入图片描述

1// 版本1:简单的球体密度测试
2void raymarchv1_float(
3    float3 rayOrigin,        // 光线起点
4    float3 rayDirection,     // 光线方向
5    float numSteps,          // 步进次数
6    float stepSize,          // 步长
7    float densityScale,      // 密度缩放
8    float4 Sphere,           // 球体数据:xyz=中心位置, w=半径
9    out float result         // 输出:累积密度
10)
11{
12    float density = 0;
13
14    // 简单步进循环
15    for (int i = 0; i < numSteps; i++)
16    {
17        // 沿光线方向移动
18        rayOrigin += (rayDirection * stepSize);
19
20        // 计算到球心的距离
21        float sphereDist = distance(rayOrigin, Sphere.xyz);
22
23        // 如果点在球体内,增加密度
24        if (sphereDist < Sphere.w)
25        {
26            density += 0.1; // 固定密度值
27        }
28    }
29
30    // 应用密度缩放
31    result = density * densityScale;
32}
33

在此基础上能输出一个白色的圆环
光线步进-经典的三个参数:
numstep是步数,步数越大,光线越容易走出圆圈的范围,渲染出的效果越淡 stepSize是步长,步长越长,分层越明显, 越小,分层越不明显,越偏向全白 densityScale是密度缩放数值, result = density * densityScale;

在这里插入图片描述在这里插入图片描述

然后把球的节点更换增加一个3D体积纹理就可以变得更像云一些了

1// 版本2:使用3D纹理的基本实现
2void raymarchv2_float(
3    float3 rayOrigin,        // 光线起点
4    float3 rayDirection,     // 光线方向
5    float numSteps,          // 步进次数
6    float stepSize,          // 步长
7    float densityScale,      // 密度缩放
8    UnityTexture3D volumeTex, // 3D体积纹理
9    UnitySamplerState volumeSampler, // 采样器
10    float3 offset,           // 纹理偏移
11    out float result         // 输出:累积密度
12)
13{
14    float density = 0;
15    float transmission = 0;
16
17    // 基本步进循环
18    for (int i = 0; i < numSteps; i++)
19    {
20        // 沿光线方向移动
21        rayOrigin += (rayDirection * stepSize);
22
23        // 从3D纹理采样密度
24        float sampledDensity = SAMPLE_TEXTURE3D(volumeTex, volumeSampler, rayOrigin + offset).r;
25        
26        // 累积密度
27        density += sampledDensity;
28    }
29
30    // 应用密度缩放
31    result = density * densityScale;
32}
33

在这里插入图片描述
参数还是同理在这里插入图片描述
sphere四个参数控制圆心位置和半径
numsteps 确定步数,步长太少根本画不出圆,只有能走过圆的步长才能有形状,step数量确定有没有
step size 确定步长,步长越长数值越大
density scale 确定每一步的值的缩放尺寸

云越多,光线照射到物体上的光线方向数量就越少
在这里插入图片描述
最终版本的代码如下

1void raymarch_float(float3 rayOrigin, float3 rayDirection, float numSteps, float stepSize,
2                    float densityScale, UnityTexture3D volumeTex, UnitySamplerState volumeSampler,
3                    float3 offset, float numLightSteps, float lightStepSize, float3 lightDir,
4                    float lightAbsorb, float darknessThreshold, float transmittance, out float3 result)
5{
6    float density = 0;
7    float transmission = 0;
8    float lightAccumulation = 0;
9    float finalLight = 0;
10
11
12    for (int i = 0; i < numSteps; i++)
13    {
14        rayOrigin += (rayDirection * stepSize);
15
16        //The blue dot position
17        float3 samplePos = rayOrigin + offset;
18        float sampledDensity = SAMPLE_TEXTURE3D(volumeTex, volumeSampler, samplePos).r;
19        density += sampledDensity * densityScale;
20
21        //light loop   numLightSteps 数量直接影响性能
22        float3 lightRayOrigin = samplePos;
23
24        for (int j = 0; j < numLightSteps; j++)
25        {
26            //The red dot position
27            lightRayOrigin += -lightDir * lightStepSize;
28            float lightDensity = SAMPLE_TEXTURE3D(volumeTex, volumeSampler, lightRayOrigin).r;
29            //The accumulated density from samplePos to the light - the higher this value the less light reaches samplePos
30            lightAccumulation += lightDensity;
31        }
32
33        //The amount of light received along the ray from param rayOrigin in the direction rayDirection
34        float lightTransmission = exp(-lightAccumulation);
35        //shadow tends to the darkness threshold as lightAccumulation rises
36        float shadow = darknessThreshold + lightTransmission * (1.0 - darknessThreshold);
37        //The final light value is accumulated based on the current density, transmittance value and the calculated shadow value 
38        finalLight += density * transmittance * shadow;
39        //Initially a param its value is updated at each step by lightAbsorb, this sets the light lost by scattering
40        transmittance *= exp(-density * lightAbsorb);
41    }
42
43    transmission = exp(-density);
44
45    result = float3(finalLight, transmission, transmittance);
46}
47

[Unity Shader Base] RayMarching in Cloud Rendering》 是转载文章,点击查看原文


相关推荐


DNS正反向解析&转发服务器&主从服务
firstacui2025/11/13

DNS正反向解析&转发服务器&主从服务 1. 正反向解析 主机角色系统IPclient客户端redhat 9.6192.168.72.7server域名解析服务器redhat 9.6192.168.72.181.1 配置服务端 1)修改主机名和IP地址 [root@localhost ~]# hostnamectl hostname server [root@server ~]# nmcli c m ens160 ipv4.addresses 192.168.72.18/24 [root@s


CV论文速递:覆盖视频理解与生成、跨模态与定位、医学与生物视觉、图像数据集等方向(11.03-11.07)
CV实验室2025/11/11

本周精选12篇CV领域前沿论文,覆盖视频理解与生成、跨模态与定位、医学与生物视觉、图像数据集与模型优化等方向。全部200多篇论文感兴趣的自取! 原文 资料 这里! 一、视频理解与生成方向 1、Cambrian-S: Towards Spatial Supersensing in Video 作者:Shusheng Yang, Jihan Yang, Pinzhi Huang, Ellis Brown, Zihao Yang, Yue Yu, Shengbang Tong,


软考 系统架构设计师之考试感悟4
蓝天居士2025/11/10

接前一篇文章:软考 系统架构设计师之考试感悟3 昨天(2025年11月8日),本人第四次参加了软考系统架构师的考试。和前三次一样,考了一天,身心俱疲。这次感觉和上一次差不多,考的次数多了,也就习惯了。仍然有诸多感悟,下边将本次参加考试的感悟写在这里,以资自己及后来者借鉴。 上一次参加考试是今年的5月24号,地点还是前两次那个地方(本次也是) —— 北京市商业学院(远大路校区),坐公交只需要30分钟、骑车只需要15分钟左右。上次考试结果是在今年的6月26号、即考试后的一个月左右的时间出的。


C++:类和对象---进阶篇
仟千意2025/11/8

1. 类的默认成员函数 默认成员函数就是我们没有显式实现,C++会自动生成的成员函数称为默认成员函数,C++11后,C++类的默认成员函数有8个(默认构造函数、默认析构函数、拷贝构造函数、赋值运算符重载、取地址运算符重载、const取地址运算符重载、移动构造函数(C++11后)、移动赋值运算符重载(C++11后)),我们此文只了解重要的前4个,后4个中前两个不常用,后两个之后再做讲解。 2. 构造函数 构造函数是特殊的成员函数,虽名为构造,但它完成的是成员变量的初始化工作,所以它可以完美的


90%前端面试必问的12个JS核心,搞懂这些直接起飞!
良山有风来2025/11/5

你是不是也遇到过这样的场景?面试官抛出一个闭包问题,你支支吾吾答不上来;团队代码review时,看到同事用的Promise链一脸懵逼;明明功能实现了,性能却总是差那么一点... 别慌!今天我整理了12个JavaScript核心概念,这些都是2024年各大厂面试的高频考点,也是日常开发中真正实用的硬核知识。搞懂它们,不仅能轻松应对面试,更能让你的代码质量提升一个档次! 变量与作用域 先来看个最常见的面试题: // 经典面试题:猜猜输出什么? for (var i = 0; i < 3; i++)


OpenAI Aardvark:当AI化身代码守护者
墨风如雪2025/10/31

想象一下,一个不知疲倦、聪明绝顶的数字侦探,夜以继日地巡视你的代码,在每一个新提交、每一行变更中嗅探潜在的危险。这不是科幻,而是OpenAI在2025年末悄然放出的重磅炸弹——Aardvark。这款以“土豚”命名的AI智能体,并非简单的代码扫描器,它标志着AI在网络安全领域,真正迈出了“自主思考”的第一步。 认识你的新安全伙伴 Aardvark,由OpenAI最先进的GPT-5模型驱动,被定位为一个“agentic security researcher”。你可以把它理解为一位全职的“白帽黑客


CoAlbum:多级缓存与性能对比
RealmElysia2025/10/29

目录 Target 1.多级缓存生效注解 2.缓存上下文 3.责任链 Hander接口 责任链初始化 5.切面Aop Coalbum项目 使用缓存 性能对比 Jmeter tips Target Caffeine+Redis构建多级缓存,采用责任链模式,使用aop+注解的方式增强目标方法。若缓存命中,返回命中值。若没命中,执行目标方法,将目标方法返回值依次存入缓存链。 1.多级缓存生效注解 /** * 多级缓存生效注解 */ @Target


为超过10亿条记录的订单表新增字段
Sam_Deep_Thinking2025/10/26

如何为 10 亿行 MySQL 大表安全新增字段? 之前在一家餐饮公司待过几年。由于这家公司已经营业了很多年,MySQL 5.6 的订单表数据早已超过 10 亿行。这就带来一个经典难题: 如何为这张大表新增字段? 当时的处理方式 假设业务需求的上线时间是 2025 年 10 月 23 日,我们会安排组内同事在 10 月 22 日或 23 日凌晨 提交数据库变更: ALTER TABLE order_items ADD COLUMN new_flag TINYINT DEFAULT 0; 变


C 语言标准库头文件 time.h
hubenchang05152025/10/23

#C 语言标准库头文件 time.h 请查看 C 语言标准库头文件列表 了解更多相关 API。 这个头文件提供 线程 相关的功能。例如线程控制、互斥量、条件变量、线程局部存储等。 #常量 宏标准说明CLOCKS_PER_SECC89处理器的每秒时钟数,POSIX 上定义为 1000000 而非实际的时钟数TIME_UTCC11表示时间基准为 UTC 时间 #类型 类型标准说明time_tC89日历时间的时间戳类型(自 1970 年 1 月 1 日 00:00:00.000 UTC 以来的秒数


Redis(77)Redis缓存的优点和缺点是什么?
Victor3562025/10/22

Redis作为一个高性能的分布式缓存系统,具有许多优点,但也有一些缺点。以下详细讲解Redis缓存的优点和缺点,并结合代码说明如何尽量发挥其优点和规避其缺点。 优点 1. 高性能 Redis以其卓越的读写性能著称,能够支持高吞吐量的读写操作。 示例代码: import redis.clients.jedis.Jedis; public class RedisPerformanceExample { public static void main(String[] args) {

首页编辑器站点地图

Copyright © 2025 聚合阅读

License: CC BY-SA 4.0