6

I have been working on a doom/wolfenstein style raycaster for a while now. I implemented the "floor raycasting" to the best of my ability, roughly following a well known raycaster tutorial. It almost works, but the floor tiles seem slightly bigger than they should be, and they don't "stick", as in they don't seem to align properly and they slide slightly as the player moves/rotates. Additionally, the effect seems worsened as the FOV is increased. I cannot figure out where my floor casting is going wrong, so any help is appreciated.

Here is a (crappy) gif of the glitch happening

Here is the most relevant part of my code:

void render(PVector pos, float dir) {
    ArrayList<FloatList> dists = new ArrayList<FloatList>();
    
    for (int i = 0; i < numColumns; i++) {
      float curDir = atan((i - (numColumns/2.0)) / projectionDistance) + dir;
      
      // FloatList because it returns a few pieces of data
      FloatList curHit = cast(pos, curDir);
      
      // normalize distances with cos
      curHit.set(0, curHit.get(0) * cos(curDir - dir));
      dists.add(curHit);
    }
    
    screen.beginDraw();
    
    screen.background(50);
    screen.fill(0, 30, 100);
    screen.noStroke();
    screen.rect(0, 0, screen.width, screen.height/2);
    
    screen.loadPixels();
    
    PImage floor = textures.get(4);
    
    // DRAW FLOOR
    for (int y = screen.height/2 + 1; y < screen.height; y++) {
      float rowDistance = 0.5 * projectionDistance / ((float)y - (float)rY/2);
      
      // leftmost and rightmost (on screen) floor positions
      PVector left = PVector.fromAngle(dir - fov/2).mult(rowDistance).add(p.pos);
      PVector right = PVector.fromAngle(dir + fov/2).mult(rowDistance).add(p.pos);
      
      // current position on the floor
      PVector curPos = left.copy();
      PVector stepVec = right.sub(left).div(screen.width);
      
      float b = constrain(map(rowDistance, 0, maxDist, 1, 0), 0, 1);        

      for (int x = 0; x < screen.width; x++) {        
        color sample = floor.get(floor((curPos.x - floor(curPos.x)) * floor.width), floor((curPos.y - floor(curPos.y)) * floor.height));
        
        screen.pixels[x + y*screen.width] = color(red(sample) * b, green(sample) * b, blue(sample) * b);
        
        curPos.add(stepVec);
      }
    }
    updatePixels();
  }

If anyone wants to look at the full code or has any questions, ask away.

  • Looks like you've done a good job there. There is some issue with the coordinate system you're using to index into the floor texture. It looks as if the location of the camera is somehow scaled wrongly (perhaps by a factor of two) so a movement of X units looks like it's magnified 2X units in the texture coordinates. (Is the scale of the floor tile pattern the expected one, or does it appear magnified relative to what it should be?) – Kaz Aug 23 '22 at 21:31
  • The floor tiles appear larger than they should. They should match up perfectly with the width of the walls. I've been doing some testing, and it appears that my "rowDistance" variable controls all of the skew that I am seeing. I think I might have an incorrect formula for that, or something along those lines. I find all of the different coordinates quite confusing to be honest. For example, if I replace that line with float rowDistance = 282 / ((float)y - (float)rY/2); it works perfectly with an FOV of 90 degrees. – declandeclandeclan Aug 23 '22 at 22:05

1 Answers1

1

Ok, I seem to have found a "solution". I will be the first to admit that I do not understand why it works, but it does work. As per my comment above, I noticed that my rowDistance variable was off, which caused all of the problems. In desperation, I changed the FOV and then hardcoded the rowDistance until things looked right. I plotted the ratio between the projectionDistance and the numerator of the rowDistance. I noticed that it neatly conformed to a scaled cos function. So after some simplification, here is the formula I came up with:

float rowDistance = (rX / (4*sin(fov/2))) / ((float)y - (float)rY/2); 

where rX is the width of the screen in pixels.

If anyone has an intuitive explanation as to why this formula makes sense, PLEASE enlighten me. I hope this helps anyone else who may have this problem.