快速遍历体素算法工作不正确

问题描述 投票:0回答:0

几天来我一直在尝试实现 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;
    }
};

一开始似乎一切正常,但后来我添加了网格运动,很明显体素改变了颜色,看起来像平面。

c++ sdl-2 traversal voxel
© www.soinside.com 2019 - 2024. All rights reserved.