几天来我一直在尝试实现 J. Amanatides 和 A. Woo 的快速体素遍历算法。但是奇怪的是,体素被渲染得好像它们只是平面一样。 我首先检查射线是否与整个体素网格相交,然后触发遍历函数。 要创建窗口、绘制像素和读取点击次数,我使用 SDL2。
main.cpp
#include <iostream>
#include "sdl_working.h"
#include "vec3.h"
#include "ray.h"
#include "voxel.h"
#include <time.h>
#include "intersections.h"
bool c;
int speed = 1;
double seconds;
vec3 velocity;
bool hit_box(const ray& r)
{
// id++;
vec3 tMin = (gridMin - r.origin()) / r.direction();
vec3 tMax = (gridMax - r.origin()) / r.direction();
vec3 t0 = min(tMin, tMax);
vec3 t1 = max(tMin, tMax);
float tNear = std::max(std::max(t0.x(), t0.y()), t0.z());
float tFar = std::min(std::min(t1.x(), t1.y()), t1.z());
if (tNear > tFar) { return false; }
ray r_inter = ray(vec3(r.origin() + tNear * r.direction()), r.direction());
InitializeStep(r_inter);
return hit_brick(r_inter, tNear);
}
void InitializeStep(const ray& r)
{
if (r.direction().x() > 0) StepX = 1;
else if (r.direction().x() < 0) StepX = -1;
else StepX = 0;
if (r.direction().y() > 0) StepY = 1;
else if (r.direction().y() < 0) StepY = -1;
else StepY = 0;
if (r.direction().z() > 0) StepZ = 1;
else if (r.direction().z() < 0) StepZ = -1;
else StepZ = 0;
}
bool hit_brick(const ray& r, float tMin)
{
int current_X_index = std::max(1.f, std::ceil(r.origin().x() - gridMin.x()));
int current_Y_index = std::max(1.f, std::ceil(r.origin().y() - gridMin.y()));
int current_Z_index = std::max(1.f, std::ceil(r.origin().z() - gridMin.z()));
int end_X_index = current_X_index;
int end_Y_index = current_Y_index;
int end_Z_index = current_Z_index;
vec3 ray_start = r.origin() + tMin * r.direction();
tDeltaX = 1 / r.direction().x();
tDeltaY = 1 / r.direction().y();
tDeltaZ = 1 / r.direction().z();
tMaxX = tMin + (gridMin.x() + current_X_index - ray_start.x()) / r.direction().x();
tMaxY = tMin + (gridMin.y() + current_Y_index - ray_start.y()) / r.direction().y();
tMaxZ = tMin + (gridMin.z() + current_Z_index - ray_start.z()) / r.direction().z();
bool isEmpty = true;
do
{
if (tMaxX < tMaxY && tMaxX < tMaxZ)
{
current_X_index += StepX;
tMaxX += tDeltaX;
}
else if (tMaxY < tMaxZ)
{
current_Y_index += StepY;
tMaxY += tDeltaY;
}
else
{
current_Z_index += StepZ;
tMaxZ += tDeltaZ;
}
if ((end_X_index < current_X_index || end_Y_index < current_Y_index || end_Z_index < current_Z_index)
&& (end_X_index < 0 || end_Y_index < 0 || end_Z_index < 0)) return false;
isEmpty = blocks[current_X_index][current_Y_index][current_Z_index].GetStatus();
c = blocks[current_X_index][current_Y_index][current_Z_index].GetColor();
//std::cout << current_X_index << " " << current_Y_index << " " << current_Z_index << " " << isEmpty << std::endl;
} while (isEmpty);
return !isEmpty;
}
void fillGrid()
{
for (int x = 0; x < gridSize; x++)
{
for (int y = 0; y < gridSize; y++)
{
for (int z = 0; z < gridSize; z++)
{
blocks[x][y][z].SetStatus(0);
blocks[x][y][z].SetColor(1);
}
}
}
}
vec3 color(const ray& r)
{
vec3 unit_dir = unit_vector(r.direction());
if (hit_box(r))
return vec3(1, 0, c);
float t = 0.5 * (unit_dir.y() + 1.0);
return(1.0 - t) * vec3(1.0, 1.0, 1.0) + t * vec3(0.5, 0.7, 1.0);
}
void sdl_working::keyDownEvent()
{
switch (sdl_working::sdl_event.key.keysym.sym)
{
case SDLK_w:
std::cout << "pressed w" << std::endl;
velocity = vec3(velocity.x(), 0, -(speed / seconds));
break;
case SDLK_s:
std::cout << "pressed s" << std::endl;
velocity = vec3(velocity.x(), 0, (speed / seconds));
break;
case SDLK_a:
std::cout << "pressed a" << std::endl;
velocity = vec3((speed / seconds), 0, velocity.z());
break;
case SDLK_d:
std::cout << "pressed d" << std::endl;
velocity = vec3(-(speed / seconds), 0, velocity.z());
break;
case SDLK_SPACE:
std::cout << "pressed space" << std::endl;
velocity = vec3(velocity.x(), -(speed / seconds), velocity.z());
break;
case SDLK_LCTRL:
std::cout << "pressed lctrl" << std::endl;
velocity = vec3(velocity.x(), (speed / seconds), velocity.z());
break;
default: break;
}
}
void sdl_working::keyUpEvent()
{
switch (sdl_working::sdl_event.key.keysym.sym)
{
case SDLK_w:
velocity = vec3(velocity.x(), 0, 0);
break;
case SDLK_s:
velocity = vec3(velocity.x(), 0, 0);
break;
case SDLK_a:
velocity = vec3(0, 0, velocity.z());
break;
case SDLK_d:
velocity = vec3(0, 0, velocity.z());
break;
case SDLK_SPACE:
std::cout << "pressed space" << std::endl;
velocity = vec3(velocity.x(), 0, velocity.z());
break;
case SDLK_LCTRL:
std::cout << "pressed lctrl" << std::endl;
velocity = vec3(velocity.x(), 0, velocity.z());
break;
default: break;
}
}
int main(int argc, char* argv[])
{
int width = 800;
int height = 400;
sdl_working::sdl("Ray Tracer", width, height);
sdl_working::loop();
vec3 lower_left_corner(-2.0, -1.0, -1.0);
vec3 horizontal(4.0, 0, 0);
vec3 vertical(0.0, 2.0, 0.0);
vec3 origin(0.0, 0.0, 0.0);
gridMin = vec3(gridCenter.x() - gridSize / 2, gridCenter.y() - gridSize / 2, gridCenter.z() - gridSize / 2);
gridMax = vec3(gridCenter.x() + gridSize / 2, gridCenter.y() + gridSize / 2, gridCenter.z() + gridSize / 2);
while (sdl_working::running)
{
gridCenter += velocity;
gridMin += velocity;
gridMax += velocity;
clock_t start = clock();
for (int y = height - 1; y >= 0; y--)
{
for (int x = 0; x < width; x++)
{
float u = float(x) / float(width);
float v = float(y) / float(height);
ray r(origin, lower_left_corner + u * horizontal + v * vertical);
vec3 col = color(r);
int ir = int(255.99 * col[0]);
int ig = int(255.99 * col[1]);
int ib = int(255.99 * col[2]);
sdl_working::setDrawColor(sdl_working::createColor(ir, ig, ib, 255));
sdl_working::drawPoint(x, height - y);
}
}
clock_t end = clock();
seconds = (double)(end - start) / CLOCKS_PER_SEC;
printf("The time: %f seconds\n", seconds);
sdl_working::loop();
}
return 0;
}
路口.h
#pragma once
#include "vec3.h"
#include "ray.h"
ray p;
float d;
int StepX = 0, StepY = 0, StepZ = 0;
float tMaxX = 0, tMaxY = 0, tMaxZ = 0,
tDeltaX = 0, tDeltaY = 0, tDeltaZ = 0;
vec3 gridMin, gridMax;
vec3 gridCenter = vec3(-2, -2, -5);
const int gridSize = 2;
brick blocks[gridSize][gridSize][gridSize];
void InitializeStep(const ray& r);
bool hit_brick(const ray& r, float tMin);
体素.h
#pragma once
class brick
{
bool isEmpty = true;
bool c;
public:
brick()
{
c = rand() % 2;
isEmpty = rand() % 2;
}
void SetStatus(bool status)
{
isEmpty = status;
}
bool GetStatus()
{
return isEmpty;
}
bool GetColor()
{
return c;
}
void SetColor(bool color)
{
c = color;
}
};
一开始似乎一切正常,但后来我添加了网格运动,很明显体素改变了颜色,看起来像平面。