Shadertoy - 02. Interior Mapping


Shadertoy地址


Interior Mapping是一种伪造室内场景的实时渲染技术
不需要建模,在一个平面上就可以渲染出房间的体积感

这里是该技术开发者的博客,里面有paper及demo
需要了解光线追踪的基础知识,可以看我上一篇或者Scratchapixel

实际应用中有两种思路,一种是生成单个房间,然后在房间内划分区域
另一种是将房间拆分成xyz三个方向的平面,本文实现的是这种


实现思路

  1. 设置参数搭建场景
  2. 发射光线,检测是否和物体相交
  3. 计算最终颜色

如何检测相交

首先只考虑xz方向的平面,平面上任意一点可以表示为(0,h,0)
如何检测和平面相交在前一篇里说过了,$ t = \frac{h - ro.y}{rd.y} $
假设两个平面之间间隔为$d$,那么平面的位置$h$可以表示为$n * d$( $n$为任意整数)
但是因为平面是无限延伸的,如果直接做检测相交,光线碰到的永远只有最近的两个平面

所以我们需要判断每个像素应该对应的平面坐标$h$,而不是找到最近的相交平面

当摄像机是仰视的时候,我们看到的是高于像素的天花板
当摄像机是俯视的时候,我们看到的是低于像素的地板

那么我们可以通过判断$rd$的方向来确认是需要向上取整还是向下取整得到$h$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
vec2 intersect(in vec3 ro, in vec3 rd, in vec3 Axis, in float d, in float id1, in float id2)
{
float rd_weight = dot( rd, Axis );
float ro_weight = dot( ro ,Axis );
float pointer = ceil( ro_weight / d );

if( rd_weight > 0.0 ) // look up
{
float h = pointer * d;
float t = ( h - ro_weight ) / rd_weight;
return vec2( t, id1 );
}
else // look down
{
float h = ( pointer - 1.0 ) * d;
float t = ( h - ro_weight ) / rd_weight;
return vec2( t, id2 );
}
}

对三个轴向都完成相交检测后,比较得到最近的$t$,完成相交检测

1
2
3
4
5
6
7
8
9
10
11
vec2 nearest(in vec2 c1,in vec2 c2,in vec2 c3)
{
if( c1.x < c2.x )
{
return c1.x<c3.x? c1:c3;
}
else
{
return c2.x<c3.x? c2:c3;
}
}

设置参数搭建场景

基本跟上一篇一致,构造正确的摄像机视锥

计算最终颜色

把坐标位置换算成uv,读取贴图得到最终颜色

参考资料

Interior Mapping

Share