我们一直在尝试在WebGL中渲染3D云场。到目前为止我们采用的方法是here - 每条光线的起始位置是体积立方体正面的当前位置,结束位置是从前一个通道计算的,该通道编码xyx vales作为背面纹理。
当相机在卷内时,我们如何将其扩展?我们是否需要动态创建体积较小的立方体?我们可以只更改着色器以开始从相机而不是正面行进,并投影到立方体的背面吗?
我们真的不确定从哪里开始!
提前致谢
答案 0 :(得分:0)
只渲染一次。
在该过程中,您只渲染背面。摄像机位置需要从世界坐标转换为由3个轴构建的坐标系,其中包含您渲染的音量盒的大小。您的目标是创建一个4x4矩阵,其中所有列向量都是vec4(...,0),这些向量的x,y,z由x,y,z轴方向定义,并带有音量框的长度。如果框与x轴平行,则该向量为(1,0,0)。如果它被拉伸到(2,0,0)那么那就是它自己的x轴,它将是矩阵中第0列的列向量。用y轴和z轴表示它们的长度。矩阵中的最后一列向量是框的位置为vec4(tx,ty,tz,1),因为此矩阵定义了一个坐标系,您可以使用它将相机位置转换为均匀(0,0,0) ) - (1,1,1)盒子的音量。
创建该体积矩阵的逆矩阵,并将凸轮作为vec4(campos,1)从右侧乘以invVolMatrix。将生成的vec3作为UNIFORM发送到着色器。
在它们各自的volBox角上仅渲染带有(0,0,0)到(1,1,1)坐标的背面 - 正如您已经做的那样。现在你有了你的着色器
在着色器中执行:
varying vec3 vLocalUnitTexCoord; // backface interpolated coordinate
uniform vec3 LOCAL_CAM_POS; // localised camPos
struct AABB {
vec3 min; // (0,0,0)
vec3 max; // (1,1,1)
};
struct Ray {
vec3 origin; vec3 dir;
};
float getUnitAABBEntry( in Ray r ) {
AABB b;
b.min = vec3( 0 );
b.max = vec3( 1 );
// compute clipping for box.min and box.max corner
vec3 rInvDir = vec3( 1.0 ) / r.dir;
vec3 tMinima = ( b.min - r.origin ) * rInvDir;
vec3 tMaxima = ( b.max - r.origin ) * rInvDir;
// sort for nearest corner
vec3 tEntries = min( tMinima, tMaxima );
// find first real entry value of 3 t-distance values in vec3 container
vec2 tMaxEntryCandidates = max( vec2( tEntries.st ), vec2( tEntries.pp ) );
float tMaxEntry = max( tMaxEntryCandidates.s, tMaxEntryCandidates.t );
}
vec3 getCloserPos( in vec3 camera, in vec3 frontFaceIntersection, in float t ) {
float useFrontCoord = 0.5 + 0.5 * sign( t );
vec3 startPos = mix( camera, frontFaceIntersection, useFrontCoord );
return startPos;
}
vec4 main(void)
{
Ray r;
r.origin = LOCAL_CAM_POS;
r.dir = normalize( vLocalUnitTexCoord - LOCAL_CAM_POS );
float t = getUnitAABBEntry( r );
vec3 frontFaceLocalUnitTexCoord = r.origin + r.dir * t;
vec3 startPos = getCloserPos( LOCAL_CAM_POS, frontFaceLocalUnitTexCoord, t );
// loop for integration follows here
vec3 start = startpos;
vec3 end = vLocalUnitTexCoord;
...for loop..etc...
}
快乐的编码!