OpenGL光线行进场景中的摄像机运动

sigwle7e  于 2022-09-26  发布在  其他
关注(0)|答案(1)|浏览(196)

我正在做一个OpenGL项目,它使用光线推进的图形,但我在控制相机时遇到了一些问题。

场景完全在顶点明暗器内生成,顶点明暗器在位于视区前面的四顶点平面上渲染。我的输入函数从用户那里获得按键和鼠标移动,并计算传递给片段着色器的相机的平移和旋转。

问题是,相机的旋转和移动行为非常奇怪。同时俯仰和偏航不仅会导致相机滚动(尽管我使用的是四元数来计算旋转),而且相机的移动(WASD)似乎只沿着世界的X和Z轴移动,而不是相机的相对轴。

任何帮助解决这个问题的人都将不胜感激。

Main.cpp:


# include <iostream>

# include <string>

# include <glad/glad.h>

# include <glfw/glfw3.h>

# include <glm/glm.hpp>

# include <glm/gtc/type_ptr.hpp>

# include "readshader.h"

# include "input.h"

# define GLM_SWIZZLE_XYZ

# define WIDTH 640

# define HEIGHT 480

using namespace std;
using namespace glm;

int main() {
    GLFWwindow* window;

    //Vertex array for screen plane
    float vertices[] = {
        -1.0f, -1.0f, 0.0f,
        1.0f, -1.0f, 0.0f,
        1.0f, 1.0f, 0.0f,
        -1.0f, 1.0f, 0.0f
    };

    unsigned int vbo;
    unsigned int vao;
    unsigned int vs;
    unsigned int fs;
    unsigned int shader_prog;

    //Game logic variables
    vec3 camera_pos = vec3(0.0f, 0.0f, 0.0f);
    quat camera_rot = quat(0.0f, 0.0f, 0.0f, 0.0f);
    vec2 screen_size = vec2(float(WIDTH), float(HEIGHT));
    float delta_time = 0.0;
    float last_time = 0.0;

    unsigned int a_camera_pos;
    unsigned int a_camera_rot;
    unsigned int a_screen_size;
    unsigned int a_delta_time;

    //Read shader code from GLSL files
    string vs_str = readShader("vert_pass.glsl");
    string fs_str = readShader("frag_raymarch_test.glsl");
    const char* vs_source = vs_str.c_str();
    const char* fs_source = fs_str.c_str();

    //Initialize GLFW and create window
    glfwInit();
    window = glfwCreateWindow(WIDTH, HEIGHT, "OpenGL", NULL, NULL);
    glfwMakeContextCurrent(window);
    gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
    glViewport(0, 0, WIDTH, HEIGHT);

    //Set GLFW input parameters
    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
    glfwSetInputMode(window, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE);
    glfwSetCursorPosCallback(window, mouseCallback);

    //Create VAO and VBO
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    //Compile shaders and create shader program
    vs = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vs, 1, &vs_source, NULL);
    glCompileShader(vs);

    fs = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fs, 1, &fs_source, NULL);
    glCompileShader(fs);

    shader_prog = glCreateProgram();
    glAttachShader(shader_prog, vs);
    glAttachShader(shader_prog, fs);
    glLinkProgram(shader_prog);

    glDetachShader(shader_prog, vs);
    glDetachShader(shader_prog, fs);
    glDeleteShader(vs);
    glDeleteShader(fs);

    glUseProgram(shader_prog);

    //Setup attribute arrays and uniform variables for vertex shader
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
    glEnableVertexAttribArray(0);

    a_camera_pos = glGetUniformLocation(shader_prog, "vert_camera_pos");
    a_camera_rot = glGetUniformLocation(shader_prog, "vert_camera_rot");
    a_screen_size = glGetUniformLocation(shader_prog, "vert_screen_size");
    a_delta_time = glGetUniformLocation(shader_prog, "vert_delta_time");

    //Main event loop
    while (!glfwWindowShouldClose(window)) {
        //Calculate delta time
        delta_time = glfwGetTime() - last_time;
        last_time = glfwGetTime();

        //Pass game information to shader program
        glProgramUniform3fv(shader_prog, a_camera_pos, 1, value_ptr(camera_pos));
        glProgramUniform4fv(shader_prog, a_camera_rot, 1, value_ptr(camera_rot));
        glProgramUniform2fv(shader_prog, a_screen_size, 1, value_ptr(screen_size));
        glProgramUniform1f(shader_prog, a_delta_time, delta_time);

        //Process user input
        input(window, &camera_pos, &camera_rot, delta_time);

        //Rendering procedure
        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

        glfwSwapBuffers(window);
    }

    //Cleanup and exit
    glDeleteProgram(shader_prog);
    glfwDestroyWindow(window);
    glfwTerminate();

    return 0;
}

Input.h:


# pragma once

# include <iostream>

# include <glfw/glfw3.h>

# include <glm/glm.hpp>

# define GLM_SWIZZLE_XYZW

# define SPEED 5.0

# define SENS 0.001

using namespace glm;

float camera_pitch = 0.0;
float camera_yaw = 0.0;

bool first = true;
float lastx = 0.0;
float lasty = 0.0;
float offsetx;
float offsety;

void input(GLFWwindow* window, vec3* camera_pos, quat* camera_rot, float delta_time) {
    float step = SPEED * delta_time;
    vec3 camera_fwd = vec3(0.0f, 0.0f, -1.0f);
    vec3 camera_up = vec3(0.0f, 1.0f, 0.0f);
    vec3 camera_right = vec3(-1.0f, 0.0f, 0.0f);
    quat quatx;
    quat quaty;

    glfwPollEvents();

    //Build rotation quaternion from camera angles
    quatx = angleAxis(camera_yaw, camera_up);
    quaty = angleAxis(camera_pitch, camera_right);
    *camera_rot = quatx * quaty;

    //Update camera axis positions
    camera_fwd = *camera_rot * camera_fwd * conjugate(*camera_rot);
    camera_right = *camera_rot * camera_right * conjugate(*camera_rot);

    //Check keyboard presses
    if (glfwGetKey(window, GLFW_KEY_W)) {
        *camera_pos -= camera_fwd * step;
    }

    if (glfwGetKey(window, GLFW_KEY_S)) {
        *camera_pos += camera_fwd * step;
    }

    if (glfwGetKey(window, GLFW_KEY_A)) {
        *camera_pos -= normalize(cross(camera_fwd, camera_up)) * step;
    }

    if (glfwGetKey(window, GLFW_KEY_D)) {
        *camera_pos += normalize(cross(camera_fwd, camera_up)) * step;
    }

    if (glfwGetKey(window, GLFW_KEY_SPACE)) {
        *camera_pos += camera_up * step;
    }

    if (glfwGetKey(window, GLFW_KEY_LEFT_CONTROL)) {
        *camera_pos -= camera_up * step;
    }
}

void mouseCallback(GLFWwindow* window, double posx, double posy) {
    if (first) {
        lastx = -posx;
        lasty = -posy;
        first = false;
    }

    offsetx = -posx - lastx;
    offsety = lasty + posy;
    lastx = -posx;
    lasty = -posy;
    offsetx *= SENS;
    offsety *= SENS;
    camera_yaw += offsetx;
    camera_pitch += offsety;

    if (camera_pitch > 89.0) {
        camera_pitch = 89.0;
    }

    if (camera_pitch < -89.0) {
        camera_pitch = -89.0;
    }
}

Vertex_pass.glsl:


# version 460

//Passes variables from attributes to next shader

layout(location = 0) in vec3 pos;

uniform vec3 vert_camera_pos;
uniform vec4 vert_camera_rot;
uniform vec2 vert_screen_size;
uniform float vert_delta_time;

out vec3 camera_pos;
out vec4 camera_rot;
out vec2 screen_size;
out float delta_time;

void main() {
    gl_Position = vec4(pos, 1.0);
    camera_pos = vert_camera_pos;
    camera_rot = vert_camera_rot;
    screen_size = vert_screen_size;
    delta_time = vert_delta_time;
}

Frag_raymarch_est.glsl:


# version 460

# define MAX_STEPS 100

# define MAX_DIST 10000.0

# define SURF_DIST 0.001

# define NORMAL_SAMPLE_SIZE 0.001

# define TAU 6.283185

# define PI 3.141592

in vec3 camera_pos;
in vec4 camera_rot;
in vec2 screen_size;
in float delta_time;

out vec3 color;

vec3 rotateVector(vec4 quat, vec3 vec) {
    return vec + 2.0 * cross(cross(vec, quat.xyz) + quat.w * vec, quat.xyz);
}

//SDF
float getSD(vec3 p) {
    vec4 s = vec4(0, 1, 6, 1);
    float sphere_dist = length(p - s.xyz) - s.w;
    float plane_dist = p.y;
    float d = min(sphere_dist, plane_dist);

    return d;
}

float getDist(vec3 p) {
    float dist = 0;

    //SDF
    dist = getSD(p);

    return dist;
}

float raymarch(vec3 ro, vec3 rd) {
    float dist = 0.0;

    for(int i = 0; i < MAX_STEPS; i++) {
        vec3 p = ro + rd * dist;
        dist += getDist(p);

        if(dist >= MAX_DIST || dist <= SURF_DIST) {
            break;
        }
    }

    return dist;    
}

void main() {
    vec2 uv = (gl_FragCoord.xy - 0.5 * screen_size) / screen_size.y;

    //vec3 ro = vec3(0.0, 1.0, 0.0);
    //vec3 ro = camera_pos;
    vec3 ro = camera_pos;
    vec3 fd = normalize(vec3(uv.x, uv.y, 1.0));
    vec3 rd = rotateVector(camera_rot, fd);

    color = vec3(raymarch(ro, rd) / 6.0);
}
xfb7svmp

xfb7svmp1#

我想通了。我回到了使用欧拉角而不是四元数,并使用它们来计算相机的向前向量。问题是,在碎片着色器中,我使用了Camera_fwd向量作为注视点,而我本应使用Camera_pos+Camera_fwd。

相关问题