Hi, I' m pretty new to C++ and OpenGL and was coding a C++ OpenGL version of the 2d Raycasting Challenge from the Coding Train YouTube channel(ep.145). The entire thing seems to work well except for one thing. In the project whenever the 0 deg ray (the ray which points directly to the right) doesn't cast itself i.e. it doesn't touch a boundary(wall), a random ray appears out of nowhere which goes on till infinity.
Here is the code so that you can see this.
main.cpp
#include "Raycasting.hpp"
#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <cmath>
void framebuffer_size_callback(GLFWwindow* window, int w, int h);
int width, height;
std::vector<Boundary> walls;
Particle particle = Particle(width, height);
double mx, my;
int main()
{
srand(time(NULL));
GLFWwindow* window;
if (!glfwInit())
return 1;
width = 600;
height = 600;
window = glfwCreateWindow(width, height, "Window", NULL, NULL);
if (!window) {
glfwTerminate();
return 1;
}
for(int i = 0; i < 5; i++){
walls.push_back(Boundary(rand()%width, rand()%width, rand()%height, rand()%height));
}
glfwMakeContextCurrent(window);
if(glewInit()!=GLEW_OK)
std::cout<<"Error"<<std::endl;
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glfwGetFramebufferSize(window, &width, &height);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
Particle particle = Particle(width, height);
glOrtho(0, width*(width/height), height, 0, -2, 2);
while(!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glClearColor(0.11, 0.14, 0.17, 1);
glfwGetCursorPos(window, &mx, &my);
for(Boundary &wall : walls)
wall.show();
particle.update((float)mx, (float)my);
particle.show();
particle.look(walls);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
}
void framebuffer_size_callback(GLFWwindow* window, int w, int h)
{
width = w;
height = h;
float ratio = width/height;
if(width<height)
ratio = height/width;
else
ratio = width/height;
glViewport(0,0,width,height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(width>height)
glOrtho(0, width*ratio, height, 0, -2, 2);
else
glOrtho(0, width, height*ratio, 0, -2, 2);
}
Raycasting.hpp
#ifndef RAYCASTING
#define RAYCASTING
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <cmath>
#include <vector>
void DrawEllipse(float cx, float cy, float rx, float ry, int num_segments)
{
float theta = 2 * 3.1415926 / float(num_segments);
float c = cosf(theta); float s = sinf(theta);
float t;
float x = 1; float y = 0;
glBegin(GL_LINE_LOOP);
for(int ii = 0; ii < num_segments; ii++)
{
glVertex2f(x * rx + cx, y * ry + cy);
t = x;
x = c * x - s * y;
y = s * t + c * y;
}
glEnd();
}
void stroke(int value){
float v = (float)value/255;
glColor3f(v,v,v);
}
void line(float x1, float y1, float x2, float y2){
glBegin(GL_LINES);
glVertex2f(x1,y1);
glVertex2f(x2,y2);
glEnd();
}
void ellipse(float x, float y, float width, float height){
DrawEllipse(x, y, width/2, height/2, 10800);
}
class V2D{
public:
V2D(){}
V2D(float _x, float _y){
x = _x;
y = _y;
}
V2D(long int n){
isNull = true;
}
bool isNull = false;
float x;
float y;
float magnitude(){
return sqrt(x*x + y*y);
}
void normalize(){
float mag = magnitude();
x /= mag;
y /= mag;
}
};
float dist(V2D start, V2D end){
return sqrt((start.x-end.x)*(start.x-end.x) + (start.y-end.y)*(start.y-end.y));
}
class Boundary{
public:
Boundary(float x1, float y1, float x2, float y2){
a = V2D(x1, y1);
b = V2D(x2, y2);
}
V2D a,b;
void show(){
stroke(255);
line(a.x, a.y, b.x, b.y);
}
};
class Ray{
public:
Ray(V2D _pos, float angle){
pos = _pos;
dir = V2D(cos(angle), sin(angle));
}
V2D pos,dir;
void lookAt(float x, float y){
dir.x = x - pos.x;
dir.y = y - pos.y;
dir.normalize();
}
void show(){
stroke(255);
line(pos.x, pos.y, pos.x + dir.x * 10, pos.y + dir.y * 10);
}
V2D cast(Boundary wall){
const float x1 = wall.a.x;
const float y1 = wall.a.y;
const float x2 = wall.b.x;
const float y2 = wall.b.y;
const float x3 = pos.x;
const float y3 = pos.y;
const float x4 = pos.x + dir.x;
const float y4 = pos.y + dir.y;
const float den = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
if(den==0){
return V2D(NULL);
}
const float t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / den;
const float u = -((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3)) / den;
if(t > 0 && t < 1 && u > 0){
float X = x1 + t * (x2 - x1);
float Y = y1 + t * (y2 - y1);
return V2D(X, Y);
}
else
return V2D(NULL);
}
};
class Particle{
public:
Particle(int width, int height){
pos = V2D(width/2, height/2);
rays = {};
for(int i = 0; i < 360; i+=1){
rays.push_back(Ray(pos, i*M_PI/180));
}
}
V2D pos;
std::vector<Ray> rays = {};
void update(float x, float y){
for(Ray &ray : rays){
ray.pos = V2D(x,y);
}
}
void show(){
for(int i = 0; i <rays.size(); i++){
rays[i].show();
}
}
void look(std::vector<Boundary> walls){
for(int i = 0; i < rays.size(); i++){
V2D closest;
float record = 100000;
for(Boundary &wall : walls){
V2D pt = rays[i].cast(wall);
if(!pt.isNull){
const float d = dist(rays[i].pos, pt);
if(d < record){
record = d;
closest = pt;
}
}
}
if(!closest.isNull){
line(rays[i].pos.x, rays[i].pos.y, closest.x, closest.y);
}
}
}
};
#endif
Makefile
main.o: main.cpp
g++ main.cpp -lglfw -I/usr/include/libdrm -L/usr/lib64 -lGLEW -lGLU -lGL -o app
What I have tried:
I do not know what to do in particular, but any sort of help/explanation will be thoroughly appreciated