当前位置: 首页 > news >正文

体渲染原理及WebGL实现【Volume Rendering】

体渲染(Volume Rendering)是NeRF神经场辐射AI模型的基础,与传统渲染使用三角形来显示 3D 图形不同,体渲染使用其他方法,例如体积光线投射 (Volume Ray Casting)。本文介绍体渲染的原理并提供Three.js实现代码,源代码可以从Github下载。

在这里插入图片描述

推荐:用 NSDT编辑器 快速搭建可编程3D场景。

1、体渲染基础

体渲染是基于图像的方法,通过沿 3D 体积投射光线,将 3D 标量场渲染为 2D 图像。 我们在屏幕上看到的每个像素都是光线穿过立方体并按一定间隔从体素获取强度样本的结果。

但是我们如何投射光线呢?

一个简单的选择是使用大小为 (1,1,1) 的 3D 网格立方体,并在两个不同的渲染通道中渲染正面和背面(启用和禁用背面剔除)。

对于屏幕中生成的每个立方体片段,我们可以创建一条从立方体正面开始并在背面结束的射线。 有了光线的起点和终点,我们就可以开始对体素进行采样,以生成最终的片段颜色。

在这里插入图片描述

标量场表示为包含每个 (x,y,z) 位置处的强度值的体素

面我们将解释使用 WebGL 和 ThreeJS 实现体渲染的实现步骤。

2、准备原始文件

原始文件是非常简单的文件,仅包含体素强度,它们没有标头或元数据,并且通常每个体素具有按 X、Y 和 Z 顺序排列的 8 位(或 16 位)强度值。

在 OpenGL 或 DirectX 中,我们可以将所有这些数据加载到专门设计的 3D 纹理中,但由于 WebGL 目前不支持存储或采样 3D 纹理,因此我们必须以 2D 纹理可以使用的方式存储它 。 因此,我们可以存储一个 png 图像文件,其中所有 Z 切片一个挨着一个,形成 2D 切片的马赛克。 我开发了一个非常简单的转换器工具,其中包含源代码。 该工具获取原始文件并生成一个 png 图像马赛克,对 alpha 通道中每个体素的强度进行编码(尽管理想的是将 png 存储为 A8 格式只是为了节省一些空间)。

一旦 png 文件作为 2D 纹理加载到内存中,我们就可以使用我们自己的自定义 SampleAs3DTexture 函数对其进行采样,就好像它是 3D 纹理一样。

在本文末尾的参考资料部分中查找更多要测试的原始文件。

3、第一个渲染通道

在第二步中,我们打算生成用作光线终点的片段。 因此,对于第一个渲染通道,我们不是绘制背面颜色,而是将片段的世界空间位置存储在渲染纹理中,作为 RGB 片段颜色内的 x、y、z 坐标值(此处 RGB 被编码为浮点值)。

请注意 worldSpaceCoords 如何用于存储立方体背面位置的世界空间位置。

顶点着色器第一遍:

varying vec3 worldSpaceCoords;void main()
{
//Set the world space coordinates of the back faces vertices as output.
worldSpaceCoords = position + vec3(0.5, 0.5, 0.5); //move it from [-0.5;0.5] to [0,1]
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}

片段着色器第一遍:

varying vec3 worldSpaceCoords;void main()
{
//The fragment's world space coordinates as fragment output.
gl_FragColor = vec4( worldSpaceCoords.x , worldSpaceCoords.y, worldSpaceCoords.z, 1 );
}

在这里插入图片描述

左:正面颜色坐标 右:背面颜色坐标

4、第2个渲染通道

该渲染通道是实际执行体积光线投射的通道,它首先绘制立方体的正面,其中正面的每个点都将是光线起点。

顶点着色器创建两个输出:投影坐标(片段的 2D 屏幕坐标)和世界空间坐标。

世界空间坐标将用作光线起点,而投影坐标将用于对存储立方体背面位置的纹理进行采样。

顶点着色器第二遍:

varying vec3 worldSpaceCoords;
varying vec4 projectedCoords;void main()
{
worldSpaceCoords = (modelMatrix * vec4(position + vec3(0.5, 0.5,0.5), 1.0 )).xyz;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
projectedCoords = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}

第二个渲染通道的片段着色器有点复杂,因此我们将分部分进行介绍。

在这里插入图片描述

在此示例中,光线 R0 到 R4 从立方体的正面片段位置(f0 到 f4)投射,并在背面位置(I0 到 I4)结束

4.1 获取光线结束位置

基于上一步的位置,我们对纹理进行采样,得到背面片段的世界空间位置。

请注意我们如何通过除以 W 将投影坐标转换为 NDC(标准化设备坐标),然后如何将其转换为 [0;1] 范围,以便将其用作 UV 坐标。 当我们对先前渲染通道中生成的 2D 纹理进行采样时,可以获得光线的结束位置。

片段着色器第二遍第 1 部分:

//Transform the coordinates it from [-1;1] to [0;1]
vec2 texc = vec2(((projectedCoords.x / projectedCoords.w) + 1.0 ) / 2.0,
((projectedCoords.y / projectedCoords.w) + 1.0 ) / 2.0 );//The back position is the world space position stored in the texture.
vec3 backPos = texture2D(tex, texc).xyz;//The front position is the world space position of the second render pass.
vec3 frontPos = worldSpaceCoords;//The direction from the front position to back position.
vec3 dir = backPos - frontPos;float rayLength = length(dir);

4.2 设置射线

有了前面和后面的位置,我们现在可以创建一条从 frontPos 开始并在 backPos 结束的射线。

片段着色器第二遍第 2 部分

//Calculate how long to increment in each step.
float delta = 1.0 / steps;//The increment in each direction for each step.
vec3 deltaDirection = normalize(dir) * delta;
float deltaDirectionLength = length(deltaDirection);//Start the ray casting from the front position.
vec3 currentPosition = frontPos;//The color accumulator.
vec4 accumulatedColor = vec4(0.0);//The alpha value accumulated so far.
float accumulatedAlpha = 0.0;//How long has the ray travelled so far.
float accumulatedLength = 0.0;vec4 colorSample;
float alphaSample;

4.3 光线行进

一旦设置了射线,我们就开始从起始位置行进射线并将射线当前位置向方向推进。

在每个步骤中,我们都会对纹理进行采样以搜索体素强度。 值得注意的是,体素仅包含强度值,因此到目前为止它们没有任何有关颜色的信息。 每个体素的颜色由变换函数给出。 可以查看 sampleAs3DTexture函数代码来了解变换函数是如何工作的。

在获得由 sampleAs3DTexture 给出的体素颜色后,将通过 alphaCorrection 参数对其进行校正。 可以在线调整该值并查看不同的结果。

每次迭代的重要部分是实际的颜色组合,其中根据 alpha 值将累积颜色值添加到先前存储的值之上。 我们还保留了一个 alphaAccumulator,它可以让我们知道何时停止光线行进。

迭代不断进行,直到满足以下三个条件之一:

  • 光线传播的距离达到了假定的光线长度。 请记住,射线从 startPos 到 endPos。
  • 累计alpha值达到100%
  • 迭代达到最大常数 MAX_STEPS

最后,片段着色器返回所遍历的体素值的合成结果。

片段着色器第二遍第 3 部分

//Perform the ray marching iterations
for(int i = 0 ; i < MAX_STEPS ; i++)
{
//Get the voxel intensity value from the 3D texture.
colorSample = sampleAs3DTexture( currentPosition );//Allow the alpha correction customization
alphaSample = colorSample.a * alphaCorrection;//Perform the composition.
accumulatedColor += (1.0 - accumulatedAlpha) * colorSample * alphaSample;//Store the alpha accumulated so far.
accumulatedAlpha += alphaSample;//Advance the ray.
currentPosition += deltaDirection;
accumulatedLength += deltaDirectionLength;//If the length traversed is more than the ray length, or if the alpha accumulated reaches 1.0 then exit.
if(accumulatedLength >= rayLength || accumulatedAlpha >= 1.0 )
break;}gl_FragColor = accumulatedColor;

如果你可以更改每条射线完成的最大迭代次数,则更改控件中的步骤,并且你可能必须相应地调整 alphaCorrection 值。


原文链接:体渲染Three.js实现 — BimAnt

相关文章:

体渲染原理及WebGL实现【Volume Rendering】

体渲染&#xff08;Volume Rendering&#xff09;是NeRF神经场辐射AI模型的基础&#xff0c;与传统渲染使用三角形来显示 3D 图形不同&#xff0c;体渲染使用其他方法&#xff0c;例如体积光线投射 (Volume Ray Casting)。本文介绍体渲染的原理并提供Three.js实现代码&#xff…...

VUE3组件

组件基础 {#components-basics} 组件允许我们将 UI 划分为独立的、可重用的部分&#xff0c;并且可以对每个部分进行单独的思考。在实际应用中&#xff0c;组件常常被组织成层层嵌套的树状结构&#xff1a; 这和我们嵌套 HTML 元素的方式类似&#xff0c;Vue 实现了自己的组件…...

【iOS】autoreleasepool

来说一下最近在了解的autoreleasepool吧&#xff0c;我们可能平时书写过许多脑残代码&#xff0c;其有很多的缺陷但是我们可能当时学的比较浅就也不太了解&#xff0c;就像下面这样的&#xff1a; for (int i 0; i < 1000000; i) {NSNumber *num [NSNumber numberWithInt…...

0基础学习VR全景平台篇 第80篇:Insta360 影石如何直播推流

一、下载Insta360 Pro APP 1、手机进入Insta360官网Insta360 | Action Cameras | 360 Cameras | VR Cameras&#xff0c;页面往下滑动到Insta360 Pro2相机处&#xff0c;点击相机图片进入详情页。详情页继续下滑到到手机APP处&#xff0c;根据自己的手机系统选择对应的客户端进…...

大语言模型之三 InstructGPT训练过程

大语言模型 GPT历史文章中简介的大语言模型的的发展史&#xff0c;并且简要介绍了大语言模型的训练过程&#xff0c;本篇文章详细阐述训练的细节和相关的算法。 2020年后全球互联网大厂、AI创业公司研发了不少AI超大模型&#xff08;百亿甚至千亿参数&#xff09;&#xff0c;…...

ChatGPT在自动化报告和数据分析中的应用如何?

ChatGPT在自动化报告和数据分析领域的应用正日益受到关注&#xff0c;这种强大的语言模型不仅可以加速报告生成的过程&#xff0c;还可以辅助数据分析&#xff0c;从而帮助企业和个人更高效地处理信息和做出决策。以下将详细探讨ChatGPT在自动化报告和数据分析中的应用。 **自…...

面试热题(三数之和)

给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三元组。 注意&#xff1a;答案中不可以包含重复的三元组。 输入&…...

在idea运行python文件

在idea运行python文件 如果在idea运行python文件而没有弹出run的选项&#xff0c;则点击File->Settings…->Plugins&#xff0c;在里面搜索python&#xff0c;如果没有显示则在Maketplace进行搜索&#xff0c; 接着Install&#xff0c;然后restart...

SQL - limit

介绍: limit 是限制的意思, 用于限制返回的查询结果的行数(可以通过limit指定查询多少行数据). MySQL支持limit语法, 用来完成分页. 用法: select 字段1, 字段2, ... from table_name limit offset, length;参数说明: offset: 起始行数, 从0开始计数, 如果省略, 则默认为…...

11. Redis基础知识

文章目录 一、概述二、数据类型STRINGLISTSETHASHZSET 三、数据结构字典跳跃表 四、使用场景计数器缓存查找表消息队列会话缓存分布式锁实现其它 五、Redis 与 Memcached数据类型数据持久化分布式内存管理机制 六、键的过期时间七、数据淘汰策略八、持久化RDB 持久化AOF 持久化…...

list模拟实现【引入反向迭代器】

文章目录 1.适配器1.1传统意义上的适配器1.2语言里的适配器1.3理解 2.list模拟实现【注意看反向迭代器】2.1 list_frame.h2.2riterator.h2.3list.h2.4 vector.h2.5test.cpp 3.反向迭代器的应用1.使用要求2.迭代器的分类 1.适配器 1.1传统意义上的适配器 1.2语言里的适配器 容…...

【华为OD机试】字符串变换最小字符串【2023 B卷|100分】

【华为OD机试】-真题 !!点这里!! 【华为OD机试】真题考点分类 !!点这里 !! 题目描述: 给定一个字符串s,最多只能进行一次变换,返回变换后能得到的最小字符串(按照字典序进行比较)。 变换规则:交换字符串中任意两个不同位置的字符。 输入描述: 一串小写字母组成的字…...

ARTS 挑战打卡的第8天 ---volatile 关键字在MCU中的作用,四个实例讲解(Tips)

前言 &#xff08;1&#xff09;volatile 关键字作为嵌入式面试的常考点&#xff0c;很多人都不是很了解&#xff0c;或者说一知半解。 &#xff08;2&#xff09;可能有些人会说了&#xff0c;volatile 关键字不就是防止编译器优化的吗&#xff1f;有啥好详细讲解的&#xff1…...

第二课-一键安装SD-Stable Diffusion 教程

前言 看完这篇文章并跟着操作,就可以在本地开始 SD 绘图了。 理论上来说,这篇课程结束,想要画什么图都可以画了。 启动器介绍 SD 是开源的,可以在 github 上找到。但直接下载源码安装,非常费劲,而且因为国内外差异,就是我这样的秃头程序员也难以应对。 所以,我们改…...

Vue3 动态列 <el-table-column> 实现 formatter 的两种方法

文章目录 动态列实现动态列实现formatter第一种第二种方法 动态列实现 参考此篇文章 Vue3 动态列实现 动态列实现formatter 第一种 以此为例&#xff1a;传递该行的wxUserInfo字段&#xff08;对象&#xff09;中的nickName 假设该行 {prop: "wxUserInfo", label: …...

室温超导是什么?有哪些应用场景?

目录 一、应用场景&#xff1a;二、案例分析&#xff1a; 室温超导是指在室温下&#xff08;即约 20C 至 30C&#xff09;实现超导现象的材料。超导是指某些材料在低温下电阻为零的物理现象&#xff0c;室温超导材料是超导材料的一种。室温超导现象的发现和研究是超导领域的一个…...

Windows+VMware+Ubuntu+Anaconda+VMware Tools

Q1&#xff1a;Windows不支持***agent模拟器 A1&#xff1a;在VMware安装Ubuntu虚拟机 P1: 下载 VMware-workstation-full-15.5.6-16341506.exe 安装包&#xff08;峰哥电脑软件&#xff09; P2: 下载Ubuntu镜像 地址 ubuntu-18.04.6-desktop-amd64.iso P3&#xff1a;搭载镜…...

Xray配置文件详解

Xray配置文件详解 1.并发配置2.HTTP配置3.插件配置4.被动代理配置5.反连平台配置1.并发配置 在配置文件中可以用下面的配置改变漏洞探测的 worker 数量: parallel: 30 # 漏洞探测的 worker 数量,可以简单理解为同时有 30 个 POC 在运行这个值并非越大越好,因为高并发的情况…...

flink优化

1. 大状态调优 大状态调优&#xff1a;在我们的项目中&#xff0c;在做新老访客修复时&#xff0c;我们将每个mid的访问时间都存到了状态里面&#xff0c;在做回流用户数时&#xff0c;我们将每个用户的登录时间都存到了状态里面&#xff0c;导致了大状态问题&#xff0c;由于…...

docker: ERROR: Couldn‘t connect to Docker daemon at http+docker://localhost

环境&#xff1a; linuxt centos 7.x 如下图&#xff0c; 使用docker-compose时&#xff0c;提示错误 [explorebridge tinyproxy]$ docker-compose up ERROR: Couldnt connect to Docker daemon at httpdocker://localhost - is it running?If its at a non-standard locati…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

golang循环变量捕获问题​​

在 Go 语言中&#xff0c;当在循环中启动协程&#xff08;goroutine&#xff09;时&#xff0c;如果在协程闭包中直接引用循环变量&#xff0c;可能会遇到一个常见的陷阱 - ​​循环变量捕获问题​​。让我详细解释一下&#xff1a; 问题背景 看这个代码片段&#xff1a; fo…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能

下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能&#xff0c;包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例

一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...