raymarching算法
raymarching 算法
raymarching 算法思想很直观:首先有一个3D的体纹理,然后从相机发射n条射线,射线有一个采样的步长。当射线处在体纹理中时,每个步长采一次样,获取纹理值(实际上表示该点的密度值),计算光照,然后和该条射线当前累积的颜色值进行混合。
为什么这样就可以渲染出正确的图案呢?因为光路是可逆的,从光源射出的光线经过散射,最终进入摄像机的效果等同于从摄像机发出的射线进行着色和采样,这个raytracing的道理是一样的。
这种算法很适合在GPU上实现,因为每条射线的计算都是独立并行的,GPU在大量并行计算上有先天的优势。为了在GPU上实现,我们需要解决的问题主要有2个:
- 哪些片段需要raymarching。
- raymarching的方向和终点在哪里。
下面来逐一进行解决。
确定raymarching的片段
体绘制首先需要一个载体(proxy geometry),也就是为了确定屏幕上的哪些像素是属于某个体纹理的。这个问题很容易就让人联想到包围盒,问题也就引刃而解。
我们只需将体纹理的包围盒绘制出来,那么包围盒在屏幕上覆盖的片段自然就是需要进行raymarching的了。如下图所示:
随后只需要执行raymarching的片断着色器即可。
raymarching的方向和终止点
在使用包围盒作为体绘制的载体时,起/终点就是每根ray进出包围盒时的两个交点。关于如何得到这两个点的坐标,有一种2个pass的算法:
- 绘制包围盒的背面,即将OpenGL背面剔除设置为GL_FRONT,并将每个片段的世界坐标保存在纹理缓存中。
- 绘制正面,将每个片段的坐标和上一个pass中的每个片段的坐标相减,即可的到ray的方向和长度,然后进行raymarching算法,达到长度终止即可(采样时要转换为纹理坐标)。
2个pass过程相对繁琐,我使用了1个pass:
- 获得片段的世界坐标,然后减去视点位置得到ray的方向。然后每次步进时都判断当前的纹理坐标是否超出了包围盒的边界,一旦超出,就停止算法。
确定ray的起始和终止点,是一个对资源消耗很大的过程,这方面也有许多内容值得研究,作为一个探索原理的程序,就以体现算法思想为主了。
顶点着色器如下:
#version 450 corelayout(location = 0) in vec3 vertices;
layout(location = 1) in vec3 UVW;uniform mat4 M;
uniform mat4 V;
uniform mat4 P;
uniform vec3 viewPos;out vec3 textCoord;
out vec3 fragWorldPos;void main()
{gl_Position = P*V*M*vec4(vertices, 1.0);// 把片段的世界坐标以及纹理坐标传递给下一个阶段fragWorldPos = vec3(M*vec4(vertices, 1.0));textCoord = UVW;
}
然后是片断着色器:
#version 450 coreuniform sampler3D noiseSampler;
out vec4 outColor;in vec3 textCoord;
in vec3 fragWorldPos;
uniform vec3 viewPos;uniform mat4 M;struct Ray{vec3 o;vec3 d;
}eyeRay;// 这个着色函数copy的shadertoy上iq大神的,关于体绘制的着色还没有开始深入的学习,日后再说哈哈
vec4 integrate( in vec4 sum, in float dif, in float den, in vec3 bgcol, in float t )
{// lightingvec3 lin = vec3(0.65,0.7,0.75)*1.4 + vec3(1.0, 0.6, 0.3)*dif; vec4 col = vec4( mix( vec3(1.0,0.95,0.8), vec3(0.25,0.3,0.35), den ), den );col.xyz *= lin;col.xyz = mix( col.xyz, bgcol, 1.0-exp(-0.003*t*t) );// front to back blending col.a *= 0.2;col.rgb *= col.a;return sum + col*(1.0-sum.a);
}#define CHECK_IN_BOX(p) \
if(p.x < 0.0 || p.x > 1.0\||p.y < 0.0 || p.y > 1.0\||p.z < 0.0 || p.z > 1.0)\break;void main()
{vec3 bgColor = vec3(0.8,0.0,0.4);vec3 lightColor = vec3(0.6, 0.8, 0.7);vec3 lightDir = normalize(vec3(5,5,5));// 射线的起点和方向eyeRay.o = viewPos;// 由于采样时使用的纹理坐标,// 而这个3D纹理坐标系和包围盒的本地坐标系是平行的(原点可能不一致),// 因此将ray的方向向量从世界坐标转换回本地坐标eyeRay.d = inverse(mat3(M)) * normalize(fragWorldPos - viewPos);float stepSize = 0.005;vec4 result = vec4(0.0);// 采样其实是从这个片段的纹理坐标开始的,然后沿着ray的方向步进vec3 p = textCoord;float steps = 0;for(int i = 0; i < 1000; i++, steps++){CHECK_IN_BOX(p);float dens = texture(noiseSampler, p).r;if(dens >= 0.01){float dif = clamp((dens - texture(noiseSampler, p + lightDir *0.5).r), 0.0, 1.0);result = integrate(result, dif, dens, bgColor, stepSize);}p += stepSize*eyeRay.d;}outColor = result;//outColor = vec4(fragWorldPos, 1.0);
}
raymarching算法相关推荐
- ShaderToy入门教程(1) - SDF 和 Raymarching 算法
许多演示场景中使用的技术之一称为 光线追踪(Ray Marching) .该算法与一种称为 有符号距离函数 的特殊函数结合使用,可以实时创建一些非常酷的东西.这是系列教程,陆续推出,这篇涵盖以下黑体所 ...
- shader编程-RayMarching与SDF结合开始三维探索(WebGL-Shader开发基础07)
RayMarching与SDF结合开始三维探索 1. 初识RayMarching 2. 实现过程 2.1 光线步进函数 2.2 获取物体表面距离 2.3 计算光照阴影 2.4 物体表面距离计算 3 d ...
- NeurIPS2019获奖论文!7篇论文斩获!微软华裔研究员斩获经典论文
点上方蓝字计算机视觉联盟获取更多干货 在右上方 ··· 设为星标 ★,与你不见不散 编辑:Sophia 计算机视觉联盟 报道 | 公众号 CVLianMeng 转载于 :https://mediu ...
- RayMarching2:给球加上光照
接上文:RayMarching1:用射线的方式画一个圆 四.法线与光照 如果对偏导或者梯度场有了解,那么对于一个规则的平面想要得到某一点的法线就不是难题 考虑到第一节 SDF 函数 ,我们知道:对于刚 ...
- RayMarching1:用射线的方式画一个球
一.ShaderToy作品 如果你对 Shader 有一定的了解,那么你或多或少听说过 shaderToy 这个网站,这个网站上有很多令人振奋的 shader 效果,而这些效果有可能只用了几行代码来实 ...
- ShaderToy入门教程(2) - 光照和相机
回顾上一篇 ShaderToy入门教程(1) - SDF 和 Raymarching 算法 继续上篇,这篇涵盖以下黑体所示内容 符号距离函数 Ray-marching算法 曲面法线和光照 相机变换 构 ...
- PyTorch3D 立体隐式形状渲染:教你构建场景 3D 结构
内容导读 3D 深度学习一直是机器视觉领域的难点,为了准确高效地建立场景的立体模型,得到相对真实的渲染成果,行业内的一些大厂先后开源了自己的研发成果. 本文首发自微信公众号「PyTorch 开发者社区 ...
- 图形学基础|屏幕空间反射(SSR)
图形学基础|屏幕空间反射(SSR) 文章目录 图形学基础|屏幕空间反射(SSR) 一.前言 二.反射技术概述 2.1 环境贴图反射 2.2 IBL反射 2.3 平面反射(Planar Reflecti ...
- nerf-pytorch3D 代码详细流程 debug
train_nerf.py import main config内容 model class RadianceFieldRenderer def __init__ 分"coarse" ...
最新文章
- 内推 58 人拿到微软 offer!这位大佬有多强?
- Java I/O Demo
- jQuery中的DatePicker今天按钮不起作用
- 最简单的c#Remoting编程
- 什么是matlab中的fints函数,Matlab基本函数
- 二叉树已知先序和中序输出后序
- linux macos 界面对比,GNOME 3与Mac OS X 10.7 (Lion)的纵览模式比较
- 美柚上云 致力成为最懂女人的互联网企业
- 学计算机专业的需要买电脑吗,高三党升级“准大一生”,有必要买电脑吗?学长的回答可以参考...
- 生成介于0.95-1的随机数MATLAB,matlab生成随机数函数
- mysql 忘记密码处理方式
- cad卸载工具_Adobe软件卸载与常见问题解决方案
- 基于51单片机的手机电话拨号盘模拟protues仿真
- 一些又用的国内著名期刊
- iOS开发--微信和支付宝网页支付(过审, 支付宝支付成功可回跳)
- c语言删除元素1116,C语言网-1116题-IP判断
- Flutter 基础UI功能,常用结构框架代码
- http协议及httpd配置
- 真无线蓝牙耳机性价比高?真无线蓝牙耳机性价比排行
- linux下安装MySQL遇到的坑