Update ray_tracing.cpp
1. working raytracing 2. navigation setup with raytracing to-do; bounce lighting
This commit is contained in:
parent
85cd3712f7
commit
5ab597aabb
1 changed files with 229 additions and 23 deletions
252
ray_tracing.cpp
252
ray_tracing.cpp
|
|
@ -5,30 +5,169 @@
|
|||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
using namespace glm;
|
||||
|
||||
// vars
|
||||
const int WIDTH = 800;
|
||||
const int HEIGHT = 600;
|
||||
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 1.0f);
|
||||
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
|
||||
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
|
||||
float lastX = 400.0, lastY = 300.0;
|
||||
float cameraYaw = -90;
|
||||
float cameraPitch = 0.0;
|
||||
float deltaTime = 0.0;
|
||||
float lastFrame = 0.0;
|
||||
|
||||
// functions
|
||||
GLFWwindow* StartGLU();
|
||||
GLuint CreateShaderProgram();
|
||||
GLuint setupQuad();
|
||||
void renderScene(GLFWwindow* &window, GLuint &quadVAO, GLuint &texture, GLuint &shaderProgram, std::vector<unsigned char> &pixels);
|
||||
GLuint loadTexture();
|
||||
|
||||
void UpdateCam(GLuint shaderProgram, glm::vec3 cameraPos);
|
||||
void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
|
||||
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
|
||||
|
||||
// structures and classes :D
|
||||
struct Ray{
|
||||
vec3 direction;
|
||||
vec3 origin;
|
||||
Ray(vec3 direction, vec3 origin) : direction(direction), origin(origin){}
|
||||
};
|
||||
struct Object{
|
||||
vec3 centre;
|
||||
float radius;
|
||||
vec3 color;
|
||||
Object(vec3 centre, float radius, vec3 color) : centre(centre), radius(radius), color(color){}
|
||||
bool intersect(const Ray &ray, float& t){
|
||||
vec3 oc = ray.origin - centre;
|
||||
double a = dot(ray.direction, ray.direction);
|
||||
double b = 2.0 * dot(oc, ray.direction);
|
||||
double c = dot(oc, oc) - radius * radius;
|
||||
|
||||
double discriminant = b*b - 4 * a * c;
|
||||
if (discriminant < 0) return false;
|
||||
|
||||
float temp = (-b - sqrt(discriminant)) / (2.0f*a);
|
||||
if (temp < 0) {
|
||||
temp = (-b + sqrt(discriminant)) / (2.0f*a);
|
||||
if (temp < 0) return false;
|
||||
}
|
||||
t = temp;
|
||||
return true;
|
||||
}
|
||||
|
||||
vec3 getNormal(const glm::vec3& point) const {
|
||||
return normalize(point - centre);
|
||||
}
|
||||
};
|
||||
class Scene{
|
||||
public:
|
||||
std::vector<Object> objs;
|
||||
vec3 lightPos;
|
||||
Scene() : lightPos(5.0f, 5.0f, 5.0f) {}
|
||||
|
||||
vec3 trace(const Ray& ray) const{
|
||||
float closest = INFINITY;
|
||||
const Object* hitObject = nullptr;
|
||||
for(const auto& obj : objs){
|
||||
float t; // distance to intersection
|
||||
// Create non-const copy to call intersect
|
||||
Object mutableObj = obj;
|
||||
if(mutableObj.intersect(ray, t)) {
|
||||
if(t < closest) {
|
||||
closest = t;
|
||||
hitObject = &obj;
|
||||
}
|
||||
}
|
||||
};
|
||||
if (hitObject) {
|
||||
vec3 hitPoint = ray.origin + ray.direction * closest;
|
||||
vec3 normal = hitObject->getNormal(hitPoint);
|
||||
vec3 lightDir = normalize(lightPos - hitPoint);
|
||||
|
||||
float diff = std::max(glm::dot(normal, lightDir), 0.0f);
|
||||
Ray shadowRay(lightDir, hitPoint + normal * 0.001f);
|
||||
bool inShadow = false;
|
||||
for (const auto& obj : objs) {
|
||||
float t;
|
||||
Object mutableObj = obj; // Create non-const copy
|
||||
if(mutableObj.intersect(shadowRay, t)) {
|
||||
inShadow = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 color = hitObject->color;
|
||||
float ambient = 0.1f;
|
||||
|
||||
if (inShadow) {
|
||||
return color * ambient;
|
||||
}
|
||||
|
||||
return color * (ambient + diff * 0.9f);
|
||||
}
|
||||
return vec3(0.0f);
|
||||
}
|
||||
};
|
||||
|
||||
// --------- main --------- //
|
||||
int main() {
|
||||
// setup
|
||||
GLFWwindow* window = StartGLU();
|
||||
Scene scene;
|
||||
GLuint shaderProgram = CreateShaderProgram(); // compile shader program
|
||||
GLuint quadVAO = setupQuad(); // create quad background
|
||||
GLuint texture = loadTexture();
|
||||
glfwSetKeyCallback(window, keyCallback);
|
||||
glfwSetCursorPosCallback(window, mouse_callback);
|
||||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
|
||||
|
||||
std::vector<unsigned char> pixels(WIDTH * HEIGHT * 3);
|
||||
scene.objs = {
|
||||
Object(glm::vec3(-1.0f, 0.0f, -5.0f), 1.0f, vec3(1.0f, 0.0, 0.0)),
|
||||
Object(glm::vec3(2.0f, 0.0f, -6.0f), 1.0f, vec3(0.0f, 1.0, 1.0))
|
||||
};
|
||||
|
||||
while(!glfwWindowShouldClose(window)){
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
UpdateCam(shaderProgram, cameraPos);
|
||||
|
||||
glUseProgram(shaderProgram);
|
||||
glBindVertexArray(quadVAO);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
// ray tracing
|
||||
for(int y = 0; y < HEIGHT; ++y){
|
||||
for(int x = 0; x < WIDTH; ++x){
|
||||
float u = float(x) / float(WIDTH); // normalize 0-1
|
||||
float v = float(y) / float(HEIGHT); // normalize 0-1
|
||||
vec3 cameraRight = normalize(cross(cameraFront, cameraUp));
|
||||
|
||||
float aspectRatio = float(WIDTH) / float(HEIGHT);
|
||||
float fov = 45.0f;
|
||||
float halfHeight = tan(radians(fov / 2.0f));
|
||||
float halfWidth = aspectRatio * halfHeight;
|
||||
|
||||
vec3 direction = normalize(
|
||||
cameraFront
|
||||
+ (2.0f * u - 1.0f) * halfWidth * cameraRight
|
||||
+ (1.0f - 2.0f * v) * halfHeight * cameraUp
|
||||
);
|
||||
|
||||
Ray ray(glm::normalize(direction), cameraPos);
|
||||
vec3 color = scene.trace(ray);
|
||||
|
||||
int index = (y * WIDTH + x) * 3;
|
||||
pixels[index + 0] = static_cast<unsigned char>(color.r * 255);
|
||||
pixels[index + 1] = static_cast<unsigned char>(color.g * 255);
|
||||
pixels[index + 2] = static_cast<unsigned char>(color.b * 255);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// actualize scene
|
||||
renderScene(window, quadVAO, texture, shaderProgram, pixels);
|
||||
|
||||
glfwSwapBuffers(window);
|
||||
glfwPollEvents();
|
||||
}
|
||||
glfwTerminate();
|
||||
}
|
||||
|
|
@ -40,7 +179,7 @@ GLFWwindow* StartGLU() {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
GLFWwindow* window = glfwCreateWindow(800, 600, "RAY_TRACING", nullptr, nullptr);
|
||||
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "RAY_TRACING", nullptr, nullptr);
|
||||
if (!window) {
|
||||
std::cerr << "Failed to create GLFW window" << std::endl;
|
||||
glfwTerminate();
|
||||
|
|
@ -55,26 +194,29 @@ GLFWwindow* StartGLU() {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
glViewport(0, 0, 800, 600);
|
||||
glViewport(0, 0, WIDTH, HEIGHT);
|
||||
return window;
|
||||
}
|
||||
GLuint CreateShaderProgram(){
|
||||
|
||||
const char* vertexShaderSource = R"(
|
||||
#version 330 core
|
||||
layout (location = 0) in vec2 aPos;
|
||||
void main() {
|
||||
gl_Position = vec4(aPos, 0.0, 1.0);
|
||||
}
|
||||
)";
|
||||
#version 330 core
|
||||
layout (location = 0) in vec3 aPos;
|
||||
layout (location = 1) in vec2 aTexCoord;
|
||||
out vec2 TexCoord;
|
||||
void main() {
|
||||
gl_Position = vec4(aPos, 1.0);
|
||||
TexCoord = aTexCoord;
|
||||
})";
|
||||
|
||||
const char* fragmentShaderSource = R"(
|
||||
#version 330 core
|
||||
in vec2 TexCoord;
|
||||
out vec4 FragColor;
|
||||
uniform sampler2D screenTexture;
|
||||
void main() {
|
||||
FragColor = vec4(1.0, 0.0, 0.0, 1.0); // 🔴 Full Red
|
||||
}
|
||||
)";
|
||||
FragColor = texture(screenTexture, TexCoord);
|
||||
})";
|
||||
|
||||
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr);
|
||||
|
|
@ -96,12 +238,13 @@ GLuint CreateShaderProgram(){
|
|||
}
|
||||
GLuint setupQuad() {
|
||||
float quadVertices[] = {
|
||||
-1.0f, 1.0f, // top left
|
||||
-1.0f, -1.0f, // bottom left
|
||||
1.0f, -1.0f, // bottom right
|
||||
-1.0f, 1.0f, // top right
|
||||
1.0f, -1.0f, // bottom right
|
||||
1.0f, 1.0f // top right
|
||||
// positions // texCoords
|
||||
-1.0f, 1.0f, 0.0f, 1.0f,
|
||||
-1.0f, -1.0f, 0.0f, 0.0f,
|
||||
1.0f, -1.0f, 1.0f, 0.0f,
|
||||
-1.0f, 1.0f, 0.0f, 1.0f,
|
||||
1.0f, -1.0f, 1.0f, 0.0f,
|
||||
1.0f, 1.0f, 1.0f, 1.0f
|
||||
};
|
||||
|
||||
GLuint VAO, VBO;
|
||||
|
|
@ -112,10 +255,73 @@ GLuint setupQuad() {
|
|||
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), quadVertices, GL_STATIC_DRAW);
|
||||
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
|
||||
glEnableVertexAttribArray(1);
|
||||
|
||||
return VAO;
|
||||
}
|
||||
GLuint loadTexture(){
|
||||
GLuint texture;
|
||||
glGenTextures(1, &texture);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
return texture;
|
||||
};
|
||||
void renderScene(GLFWwindow* &window, GLuint &quadVAO, GLuint &texture, GLuint &shaderProgram, std::vector<unsigned char> &pixels){
|
||||
// Update texture with ray traced result
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, WIDTH, HEIGHT, 0, GL_RGB,
|
||||
GL_UNSIGNED_BYTE, pixels.data());
|
||||
glUseProgram(shaderProgram);
|
||||
glBindVertexArray(quadVAO);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
glfwSwapBuffers(window);
|
||||
glfwPollEvents();
|
||||
}
|
||||
|
||||
void UpdateCam(GLuint shaderProgram, glm::vec3 cameraPos) {
|
||||
// Calculate current frame time for smooth movement
|
||||
float currentFrame = glfwGetTime();
|
||||
deltaTime = currentFrame - lastFrame;
|
||||
lastFrame = currentFrame;
|
||||
}
|
||||
void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
|
||||
float cameraSpeed = 1.0f * deltaTime;
|
||||
|
||||
if (key == GLFW_KEY_W && (action == GLFW_PRESS || action == GLFW_REPEAT))
|
||||
cameraPos += cameraSpeed * cameraFront;
|
||||
if (key == GLFW_KEY_S && (action == GLFW_PRESS || action == GLFW_REPEAT))
|
||||
cameraPos -= cameraSpeed * cameraFront;
|
||||
if (key == GLFW_KEY_A && (action == GLFW_PRESS || action == GLFW_REPEAT))
|
||||
cameraPos -= normalize(cross(cameraFront, cameraUp)) * cameraSpeed;
|
||||
if (key == GLFW_KEY_D && (action == GLFW_PRESS || action == GLFW_REPEAT))
|
||||
cameraPos += normalize(cross(cameraFront, cameraUp)) * cameraSpeed;
|
||||
if (key == GLFW_KEY_Q && action == GLFW_PRESS)
|
||||
glfwSetWindowShouldClose(window, true);
|
||||
}
|
||||
void mouse_callback(GLFWwindow* window, double xpos, double ypos) {
|
||||
|
||||
float xoffset = xpos - lastX;
|
||||
float yoffset = lastY - ypos;
|
||||
lastX = xpos;
|
||||
lastY = ypos;
|
||||
|
||||
float sensitivity = 0.1f;
|
||||
xoffset *= sensitivity;
|
||||
yoffset *= sensitivity;
|
||||
|
||||
cameraYaw += xoffset;
|
||||
cameraPitch += -yoffset;
|
||||
|
||||
if(cameraPitch > 89.0f) cameraPitch = 89.0f;
|
||||
if(cameraPitch < -89.0f) cameraPitch = -89.0f;
|
||||
|
||||
glm::vec3 front;
|
||||
front.x = cos(glm::radians(cameraYaw)) * cos(glm::radians(cameraPitch));
|
||||
front.y = sin(glm::radians(cameraPitch));
|
||||
front.z = sin(glm::radians(cameraYaw)) * cos(glm::radians(cameraPitch));
|
||||
cameraFront = glm::normalize(front);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue