ThreeJS中体渲染,利用噪声模拟烟,云

ThreeJS中体渲染,利⽤噪声模拟烟,云
ThreeJS 中体渲染,利⽤噪声模拟烟,云
体渲染的东西也看了⼀段时间了,这⾥结合Three.js中体积云的例⼦,实现shdertoy中的⼀个效果,先放效果图。
, 这⾥是参考的效果,可以⾃⾏参看源码。
体渲染,Volume Rendering
传统建模⽅式,可以理解为表⾯建模,通过构建物体外表⾯,在三维中展⽰实际物体。相对的,体渲染是从三维数据中⽣成图像,典型的例⼦就是医疗上的CT。本⽂中不涉及体渲染中的光学模型,仅是对数据进⾏采样,上⾊。同时简化计算,使⽤的⼏何体为圆球,当然也可以换成⽴⽅体,计算⽅式不会复杂,之后附带⽴⽅体和球体射线检测。
体渲染在表现⾃然现象,云、雾、⽕等,相对于表⾯建模,或者贴图有很⼤优势。最⼤的不同就是,实⼼的,当然效果也好太多了。
3D纹理,sample3D
本次主要要渲染动态更新的体数据,就不需要提前⽣成体数据了。通过fragmentshader来对采样的射线进⾏噪声处理,达到动画效果。相关算法
噪声
噪声函数相关的内容,可以⾃⾏搜索,这⾥贴⼀个IQ⼤神的博客地址。
⽂中涉及的噪声,分型布朗都是从shadertoy获取,代码仅作适当说明。
⽴⽅体射线求交,AABB
先解释⼀下AABB,Axis-Aligned Bounding Box, 轴对称包围盒。我们在放置⽴⽅体时,⽴⽅体各边都同三个坐标轴平⾏,可以极⼤简化计算。如下图,计算射线进⼊⼀组平⾯(可以理解为⽴⽅体的两个对⽴⾯),计算进⼊和射出的位置时,可以只采⽤对应轴的分量即可。
如下图右侧的公式。
假设平⾯P垂直于X轴,则计算过程可以仅考虑x⽅向的分量。图中为平⾯p在x轴处的值,分别为:射线原点的x值,射线朝向在x轴的分量(射线朝向为单位向量时,可以理解为,射线进⼊出去两个平⾯的时间)。球体射线求交
球体就是射线⽅程同球⾯⽅程,利⽤求根公式解⽅程组了,不再介绍。
Three.js 中的体渲染
基础内容介绍完,先看⼀下Three提供的体渲染的例⼦。场景中主要包括天空盒,和承载体渲染结果的⽴⽅体。这些不做说明,重点看⼀下渲染使⽤的着⾊器。渲染⽴⽅体的材质要使⽤RawShaderMaterial ,采⽤⾃定义的着⾊器。
顶点着⾊器
vertexshader中主要处理相机位置,和相机朝向,⽤于传⼊到fragment中。
Three中相机位置为世界坐标,通过模型变换的逆矩阵,将相机位置换算到模型本地坐标中。模型在本地坐标中处于原点位置,可以简化计算。相机朝向通过顶点位置减相机的本地坐标即可得到。
in vec3 position;
uniform mat4 modelMatrix;  //模型本地坐标系,转换到世界坐标系
uniform mat4 modelViewMatrix; //模型世界坐标系,转换到相机坐标系空间
uniform mat4 projectionMatrix; //投影矩阵
uniform vec3 cameraPos;  //相机位置农村妇女肥大
out vec3 vOrigin;
out vec3 vDirect
void main() {
//相机空间坐标
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
//相机在模型本地坐标的位置
vOrigin = vec3( inverse( modelMatrix ) * vec4( cameraPos, 1.0 ) ).xyz;
药绘图
//相机在模型本地坐标的朝向
vDirection = position - vOrigin;
gl_Position = projectionMatrix * mvPosition;
}
⽚元着⾊器
71岁过芭蕾六级相机位置作为射线原点,相机朝向作为射线⽅向,这条射线将参与后续的体数据的采样。代码中的hitBox 即为上⾯提到的AABB⽅法。得到的vec2,其中x为最近,y为最远。
od p x ′
o ,d x x dir
void main(){
vec3 rayDir = normalize( vDirection );
vec2 bounds = hitBox( vOrigin, rayDir );
// 丢弃⽴⽅体外的像素
if ( bounds.x > bounds.y ) discard;
// 当相机位置在⽴⽅体内部时,x为负值,射线反向不需要采样,设置为0,即从内部开始采样
bounds.x = max( bounds.x, 0.0 );
// p为射线第⼀次进⼊⽴⽅体的位置
vec3 p = vOrigin + bounds.x * rayDir;
vec3 inc = 1.0 / abs( rayDir );
float delta = min( inc.x, min( inc.y, inc.z ) );
delta /= steps;
// Nice little seed from
// /2020/05/25/casual-shadertoy-path-tracing-1-basic-camera-diffuse-emissive/
uint seed = uint( gl_FragCoord.x ) * uint( 1973 ) + uint( gl_FragCoord.y ) * uint( 9277 ) + uint( frame ) * uint( 26699 );
vec3 size = vec3( textureSize( map, 0 ) );
刻楦机float randNum = randomFloat( seed ) * 2.0 - 1.0;
// 对开始位置进⾏偏移,可能是为了避免射线在表⾯这种临界条件吧
p += rayDir * randNum * ( 1.0 / size );
vec4 ac = vec4( base, 0.0 );
// 从射线进⼊,到射线穿过⽴⽅体,依次采样
for ( float t = bounds.x; t < bounds.y; t += delta ) {
float d = sample1( p + 0.5 );
d = smoothstep( threshold - range, threshold + range, d ) * opacity;
float col = shading( p + 0.5 ) * 3.0 + ( ( p.x + p.y ) * 0.25 ) + 0.2;
ac.a += ( 1.0 - ac.a ) * d;
// 采样颜⾊累积到接近不透明时,停⽌采样
if ( ac.a >= 0.95 ) break;
p += rayDir * delta;
}
color = ac;
if ( color.a == 0.0 ) discard;
}
main⽅法中的shading可以理解为上⾊的过程。
修改⽚元着⾊器
以上了解了体渲染基本流程后,开始修改⽚元着⾊器以期实现shadertoy中的效果。
⾸先,shadertoy中的造型是基于球体做的,我们修改⼏何体为球体。添加hitSphere⽅法,t0,t1依次为进⼊和出去的时间。
vec2 hitSphere(vec3 origin,vec3 dir){
float b=dot(dir,origin);
float c=dot(origin,origin)-_SphereRadius*_SphereRadius;
float t0=-b-sqrt(b*b-c);
float t1=-b+sqrt(b*b-c);
t0=max(t0,0.);
return vec2(t0,t1);
}
RayMarch
由于我们需要在shader中实现球体的绘制,因此需要通过射线原点到球体的距离来绘制球体。这⾥类似于cloud页⾯中的步进采样。
vec4 rayMarch(vec3 rayOrigin,vec3 rayStep,out vec3 pos)
{
richard chaivec4 sum=vec4(0.,0.,0.,0.);
pos=rayOrigin;
for(int i=0;i<_VolumeSteps;i++)
2013年东亚四强赛
{
vec4 col=volumeFunc(pos);
col.a*=_Density;
sum=sum+col*(1.0-sum.a);
pos+=rayStep;
}
return sum;
}
渲染球体
同时为了简化计算,射线累计的采样次数都为固定值,不再单独计算。
void main(){
vec3 rayDir = normalize( vDirection );
vec2 bounds=hitSphere(vOrigin,rayDir);
if(bounds.y<0.) discard;
vec3 hitPos;
//射线第⼀次进⼊球的位置
vec3 p=vOrigin+bounds.x*rayDir;
vec4 col=rayMarch(p,rayDir*_StepSize,hitPos);
color = col;
if ( color.a == 0.0 ) discard;
}
当rayMarch中的volumeFunc直接返回射线到球⾯的距离时,你将能得到⾮常光滑的球。
接下来就是对这个球进⾏造型了,噪声函数很多,可以⾃⾏测试,添加噪声函数后,可能得到如下,实时计算的噪声,在GTX1650显卡上,还是很流畅的,再低⼀些就不好使了,卡成PPT:
这个球还是太规则,添加fbm(分形布朗)后,增加不规则程度,即可得到如下:
最后附上全部代码。代码⽐较乱,放了⼏种噪声函数,可以⾃⼰试试不同的形状,谨慎观看。
最后贴⼀个不同的着⾊效果。

本文发布于:2024-09-25 00:40:04,感谢您对本站的认可!

本文链接:https://www.17tex.com/xueshu/71456.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:射线   渲染   噪声   球体   位置   模型   采样
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议