The SDL forums have moved to discourse.libsdl.org.
This is just a read-only archive of the previous forums, to keep old links working.


SDL Forum Index
SDL
Simple Directmedia Layer Forums
RayCasting
vastrolorde


Joined: 20 Mar 2015
Posts: 11
Can anyone give me a working example of raycasting in C++ using SDL2. I have tried different tutorials but none of them work. Example in below is my latest try. Expected result is that all the points(screen and obstacles) are static and dont move around, but the reality is the vision polygon that comes from calculating the intersections is weird shape and covers maximum 1/4 of the entire visible area. Oddly enough best result currently comes when i just add all the points(without intersection test) in correct order to the polygon point list. It almost is perfect, but the obvious comes out when at some point the polygon does some weird jumps it shouldnt. Can someone tell me where my math goes wrong?

Code:

typedef struct point{
   float x;
   float y;
   float angle;
   float T;
}Point;

typedef struct ray{
   float x;
   float y;
   float angle;
}RAY;


Point* getIntesection(RAY ray, LINE segment){
   float r_px = ray.x;
   float r_py = ray.y;
   float r_dx = cos(ray.angle);
   float r_dy = sin(ray.angle);
   // SEGMENT in parametric: Point + Delta*T2
   float s_px = segment.a.x;
   float s_py = segment.a.y;
   float s_dx = segment.b.x - segment.a.x;
   float s_dy = segment.b.y - segment.a.y;

   // Are they parallel? If so, no intersect
   float r_mag = sqrt(r_dx*r_dx + r_dy*r_dy);
   float s_mag = sqrt(s_dx*s_dx + s_dy*s_dy);
   if (r_dx / r_mag == s_dx / s_mag && r_dy / r_mag == s_dy / s_mag){
      // Unit vectors are the same.
      return NULL;
   }

   float T2 = (r_dx*(s_py - r_py) + r_dy*(r_px - s_px)) / (s_dx*r_dy - s_dy*r_dx);
   float T1 = (s_px + s_dx*T2 - r_px) / r_dx;
   // Must be within parametic whatevers for RAY/SEGMENT
   if (T1<0) return NULL;
   if (T2<0 || T2>1) return NULL;

   Point* p = new Point;
   p->x = r_px + r_dx*T1;
   p->y = r_py + r_dy*T1;
   p->T = T1;
   return p;
}

void render_polygon(std::vector<Point*> polygon){
   std::vector<Point*>::iterator it = polygon.begin();
   Point* p = *it;
   SDL_SetRenderDrawColor(gRenderer, 255, 0, 0, 255);
   it++;
   Point* t = p;
   for (; it != polygon.end(); it++){
      SDL_RenderDrawLine(gRenderer, t->x, t->y, (*it)->x, (*it)->y);
      t = *it;
   }
   SDL_RenderDrawLine(gRenderer, t->x, t->y, p->x, p->y);
}
struct PointerCompare {
   bool operator()(const Point* l, const Point* r) {
      return l->angle < r->angle;
   }
};

void raycast(Circle* c, std::set<SDL_Point*>* points, std::set<LINE*>* lines){
   float centerX = (c->getCenterX());
   float centerY = (c->getCenterY());
   std::vector<Point*> polygon;
   for (std::set<SDL_Point*>::iterator it = points->begin(); it != points->end(); ++it){
      float angle = 0;
      float tempdx = (*it)->x - centerX;
      float tempdy = (*it)->y - centerY;
      angle = atan2(tempdy,tempdx);

      float dx = cos(angle);
      float dy = sin(angle);

      RAY r{ centerX, centerY ,angle};

      Point* closest = NULL;
      for (std::set<LINE*>::iterator it2 = lines->begin(); it2 != lines->end(); ++it2){
         Point* D = getIntesection(r, *(*it2));
         if (D == NULL) continue;
         if (closest == NULL || D->T < closest->T) closest = D;
      }

   //   if (closest == NULL){
   //      std::cout << "End" << std::endl;
   //      Point* t = new Point;
   //      t->x = p2.x;
   //      t->y = p2.y;
   //      t->angle = angle;
   //      polygon.push_back(t);
   //   }
   //   else{
         if (closest == NULL) continue;
      //      std::cout << closest->x << " " << closest->y << std::endl;
         closest->angle = angle;
         polygon.push_back(closest);
   //   }
   }

   std::sort(polygon.begin(), polygon.end(), PointerCompare());

   render_polygon(polygon);
}
vastrolorde


Joined: 20 Mar 2015
Posts: 11
I found the previous error i had. i had set the line segments bit wrong. But the new problem i ran into is that when i added more objects to the playfield, some corners went wrong. Each point is processed with small deviation in angle on both sides to hit the walls behind. But when added more objects the orded of witch it draw the polygon lines gets mixed up and some random point appear that shouldnt be there.

Code:
void raycast(Circle* c, std::set<SDL_Point*>* points, std::set<LINE*>* lines){
   float centerX = (c->getCenterX());
   float centerY = (c->getCenterY());
   std::vector<Point*> polygon;
   for (std::set<SDL_Point*>::iterator it = points->begin(); it != points->end(); ++it){
      float tempdx = (*it)->x - centerX;
      float tempdy = (*it)->y - centerY;
      float angle = atan2(tempdy, tempdx);

      float angles[3] = {angle-0.00001, angle, angle+0.00001};
      for (int i = 0; i < 3; i++){
         RAY r{ centerX, centerY, angles[i] };

         Point* closest = NULL;
         for (std::set<LINE*>::iterator it2 = lines->begin(); it2 != lines->end(); ++it2){
            Point* D = getIntesection(r, *(*it2));
            if (D == NULL) continue;
            if (closest == NULL || D->T < closest->T) closest = D;
         }

         if (closest == NULL) continue;
         closest->angle = angle;

         polygon.push_back(closest);
      }
   }

   std::sort(polygon.begin(), polygon.end(), PointerCompare());

   render_polygon(polygon);
}
vastrolorde


Joined: 20 Mar 2015
Posts: 11
Image of raycast gone wrong. Redboxes are static and blue is the one i move.
vastrolorde


Joined: 20 Mar 2015
Posts: 11
FIxed it. Problem was that i calculate an angle and get 2 offsets from it. But when i save the closes tpoint to array i use only the calculated angle not the offset, so the sorting alroithm doesent gonow whits order they should be. So i now save the ofsetted angles also and it works.