建立一个raymarching

Posted xiaogeformax

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了建立一个raymarching相关的知识,希望对你有一定的参考价值。

建立一个raymarching


shadertoy 查看

先解释一波 raymarching, Raymatching是一种计算机图形渲染方式,但它的潜力仍未被完全发掘。Raymatching一般用于渲染体积纹理、高度图以及解析曲面。如今,大多数游戏用OpenGL或Direct3D(DirectX)来使用显卡的硬件加速器绘制多边形,电脑可以以每秒60帧的速度渲染几百万个三角面。虽然Raymatching没有那些图形API那么出名,但它可以仅用两个三角面实现无与伦比的细节。

创建一个camera

我们需要去定义camera的origin,target,和up 就是定义摄像机的起源,目标位置,还有就是定义向上的位置。

vec3 cameraOrigin = vec3(2.0, 3.0, 2.0);
vec3 cameraTarget = vec3(0.0, 0.0, 0.0);
vec3 upDirection = vec3(0.0, 1.0, 0.0);

然后就可以得出摄像机的发向是

vec3 cameraDir = normalize(cameraTarget - cameraOrigin);

由此可以计算出摄像机的右方向和顶上的方向。

vec3 cameraRight = normalize(cross(upDirection, cameraOrigin));
vec3 cameraUp = cross(cameraDir, cameraRight);

下面对屏幕坐标进行转化,把屏幕坐标放缩到-1到1之间。

vec2 screenPos = -1.0 + 2.0 * gl_FragCoord.xy / iResolution.xy; // screenPos can range from -1 to 1
screenPos.x *= iResolution.x / iResolution.y; // Correct aspect ratio

在知道了摄像机的方向之后,我们来计算出ray的方向。

vec3 rayDir = normalize(cameraRight * screenPos.x + cameraUp * screenPos.y + cameraDir);

Raymarching loop

在 marching 里面 先来设置步进的光线总长度

const int MAX_ITER = 100; 

物体的离摄像机的最大范围

const float MAX_DIST = 20.0;

设置物体离光线的阈值距离

const float EPSILON = 0.001;

下面是loop的代码:在个里面点会被转化为和交集的东西。

 // The raymarching loop
float totalDist = 0.0;
vec3 pos = cameraOrigin;
float dist = EPSILON;

// trying to find a point of intersection 
for (int i = 0; i < MAX_ITER; i++)

    // Either we've hit the object or hit nothing at all, either way we should break out of the loop
    if (dist < EPSILON || totalDist > MAX_DIST)
    break; // If you use windows and the shader isn't working properly, change this to continue;

    dist = distfunc(pos); // Evalulate the distance at the current point
    totalDist += dist;
    pos += dist * rayDir; // Advance the point forwards in the ray direction by the distance

定义显示的模型

float sphere(vec3 pos, float radius)

	return length(pos) - radius;


float box(vec3 pos, vec3 size)

    return length(max(abs(pos) - size, 0.0));

定义一下Lighting

光也要在EPSILON的距离里面

if (dist < EPSILON)

    // Lighting code

else

	gl_FragColor = vec4(0.0);

光函数里面需要取得表面着色器的normal向量,可以用点来预计算出点的位置。

vec2 eps = vec2(0.0, EPSILON);
vec3 normal = normalize(vec3(
	distfunc(pos + eps.yxx) - distfunc(pos - eps.yxx),
	distfunc(pos + eps.xyx) - distfunc(pos - eps.xyx),
	distfunc(pos + eps.xxy) - distfunc(pos - eps.xxy)));

由光照公式可以得出

  fragColor = vec4(ambientColor +
                      lambertian * diffuseColor +
                      specular * specColor, 1.0);

shadertoy 查看

以上是关于建立一个raymarching的主要内容,如果未能解决你的问题,请参考以下文章

可以在 SIMD 架构下加速 raymarching 吗?

建立一个raymarching

建立一个raymarching

光线行进时的 GLSL 伪影

3D渲染-光线追踪-包围盒

Three.js - 将光线从物体发送到相机