Skip to main content
fixed typos, added code markdown to code in text, removed some fluff
Source Link
Pikalek
  • 13.4k
  • 5
  • 49
  • 54

im new around here, hope everything is going sweet for all of you. I come for theory help with a classic raycast algorithm (currently, based on DDA). The problem is not with the algorithm itself, but with the floor rendering code.

I left the code of my raycast render method below (actual DDA implementation itsis left out, iI think that's working as expected). The basic idea its use PLAYER_HEIGHTit uses PLAYER_HEIGHT (position of camera, currently set to HORIZON), and the formula PLAYER_HEIGHT/(y- HORIZON)PLAYER_HEIGHT/(y- HORIZON). In the canvas, the bottom pixel of y itsis equal to SCREEN_HEIGHTSCREEN_HEIGHT, and goes “up” until it reach HORIZON - 1reaches (canvasHORIZON - 1. Canvas element pixels goesgo from 0,0/topleftcorner (top left corner) to screen_width,screen_height/bottomrightcornerscreen_width, screen_height (bottom right corner). ThatsThat's the distance that will be used for interpolating the floor coordinates x and y according to the vector direction of the player and a camera plane perpendicular to the direction vector.

The main problem itsis in my rendering floor technique. New tiles “appears”“appear” below the walls. The desired effect would be, if there is a wall in a map position (7,4) the floor tiles around that should be always the same. But right now, as the player moves, “new” tiles slide from behind the wall, so depending ofon the player position and angle, near to (7,4) the floor tile may be appear white or blue, so itsit is not “sync”“in sync”.

I think the problem itsis the distance of the wall iI get using DDA and the distance related to the difference between the current row in the screen space and my HORIZON itsHORIZON is different, they are not “sync”“in sync” and itsit is normal because the are two different “types” of distances? I'm lost here. Thank you all for taking your time with this.

im new around here, hope everything is going sweet for all of you. I come for theory help with a classic raycast algorithm (currently, based on DDA). The problem is not with the algorithm itself, but with the floor rendering code.

I left the code of my raycast render method below (actual DDA implementation its left out, i think that's working as expected). The basic idea its use PLAYER_HEIGHT (position of camera, currently set to HORIZON), and the formula PLAYER_HEIGHT/(y- HORIZON). In the canvas, the bottom pixel of y its equal to SCREEN_HEIGHT, and goes “up” until it reach HORIZON - 1 (canvas element pixels goes from 0,0/topleftcorner to screen_width,screen_height/bottomrightcorner). Thats the distance that will be used for interpolating the floor coordinates x and y according to the vector direction of the player and a camera plane perpendicular to the direction vector.

The main problem its in my rendering floor technique. New tiles “appears” below the walls. The desired effect would be, if there is a wall in a map position (7,4) the floor tiles around that should be always the same. But right now, as the player moves, “new” tiles slide from behind the wall, so depending of the player position and angle, near to (7,4) the floor tile may be appear white or blue, so its not “sync”.

I think the problem its the distance of the wall i get using DDA and the distance related to the difference between the current row in the screen space and my HORIZON its different, they are not “sync” and its normal because the are two different “types” of distances? I'm lost here. Thank you all for taking your time with this.

I come for theory help with a classic raycast algorithm (currently, based on DDA). The problem is not with the algorithm itself, but with the floor rendering code.

I left the code of my raycast render method below (actual DDA implementation is left out, I think that's working as expected). The basic idea it uses PLAYER_HEIGHT (position of camera, currently set to HORIZON), and the formula PLAYER_HEIGHT/(y- HORIZON). In the canvas, the bottom pixel of y is equal to SCREEN_HEIGHT, and goes “up” until it reaches HORIZON - 1. Canvas element pixels go from 0,0 (top left corner) to screen_width, screen_height (bottom right corner). That's the distance that will be used for interpolating the floor coordinates x and y according to the vector direction of the player and a camera plane perpendicular to the direction vector.

The main problem is in my rendering floor technique. New tiles “appear” below the walls. The desired effect would be, if there is a wall in a map position (7,4) the floor tiles around that should be always the same. But right now, as the player moves, “new” tiles slide from behind the wall, so depending on the player position and angle, near to (7,4) the floor tile may be appear white or blue, so it is not “in sync”.

I think the problem is the distance of the wall I get using DDA and the distance related to the difference between the current row in the screen space and my HORIZON is different, they are not “in sync” and it is normal because the are two different “types” of distances? I'm lost here. Thank you all for taking your time with this.

Source Link

Raycast DDA: Wall rendering and floor rendering out of sync

im new around here, hope everything is going sweet for all of you. I come for theory help with a classic raycast algorithm (currently, based on DDA). The problem is not with the algorithm itself, but with the floor rendering code.

I left the code of my raycast render method below (actual DDA implementation its left out, i think that's working as expected). The basic idea its use PLAYER_HEIGHT (position of camera, currently set to HORIZON), and the formula PLAYER_HEIGHT/(y- HORIZON). In the canvas, the bottom pixel of y its equal to SCREEN_HEIGHT, and goes “up” until it reach HORIZON - 1 (canvas element pixels goes from 0,0/topleftcorner to screen_width,screen_height/bottomrightcorner). Thats the distance that will be used for interpolating the floor coordinates x and y according to the vector direction of the player and a camera plane perpendicular to the direction vector.

function render(canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D, currentTime: number) {
  const deltaTime = (currentTime - lastTime) / 1000;
  lastTime = currentTime;
  movePlayer(deltaTime);
  renderingActions(deltaTime);
  // Clear the canvas
  ctx.fillStyle = "black";
  ctx.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);

  const buffer = FLOOR_TEXTURE_IMAGE_DATA.data;
  const rayIncrement = FOV / SCREEN_WIDTH;
  const wallsArray: {wallHeight: number,distance:number}[] = [];
  const rayDirsArray: {rayDirX: number,rayDirY: number, distance: number, normRayAngle: number, wallHeight: number, side:number, wallStart:number}[] = [];
  
  const dirX = Math.cos(normalizeAngle(playerAngle));
  const dirY = Math.sin(normalizeAngle(playerAngle));
  const planeX = -dirY ;
  const planeY = dirX;

    nearPlaneX1 = dirX - planeX;
    nearPlaneX2 = dirX + planeX;
    nearPlaneY1 = dirY - planeY;
    nearPlaneY2 = dirY + planeY;
    const dotDirLeft = (dirX * nearPlaneX1 + dirY * nearPlaneY1);
    const dotDirRight = (dirX * nearPlaneX2 + dirY * nearPlaneY2);
    const angleLeft = Math.acos(dotDirLeft);
    const angleRight = Math.acos(dotDirRight);
    

    const normalizedLeftX = nearPlaneX1/Math.sqrt((nearPlaneX1*nearPlaneX1) + (nearPlaneY1*nearPlaneY1));
    const normalizedLeftY = nearPlaneY1/Math.sqrt((nearPlaneX1*nearPlaneX1) + (nearPlaneY1*nearPlaneY1));

    const normalizedRightX = nearPlaneX2/Math.sqrt((nearPlaneX2*nearPlaneX2) + (nearPlaneY2*nearPlaneY2));
    const normalizedRightY = nearPlaneY2/Math.sqrt((nearPlaneX2*nearPlaneX2) + (nearPlaneY2*nearPlaneY2));

  for (let x = 0; x < SCREEN_WIDTH; x++) {
      const rayAngle = playerAngle - FOV / 2 + x * rayIncrement;
      const {distance, rayDirX, rayDirY, normRayAngle, side} = castRay(rayAngle);
      
      // Calculate wall height once
      const wallHeight = Math.min(SCREEN_HEIGHT,
          (SCREEN_HEIGHT * WALL_SCALE) / (distance * DISTANCE_SCALE / WORLD_SCALE));
          

      const wallStart = (HORIZON - wallHeight) / 2  
      wallsArray.push({wallHeight, distance});  
      rayDirsArray.push({rayDirX, rayDirY, distance, normRayAngle, wallHeight, side, wallStart});
  }

  for(let y = SCREEN_HEIGHT ; y > HORIZON; y--) {

      const yDistance = ((HORIZON / (y - HORIZON)));
      const  floorXDirInc = yDistance*(normalizedRightX - normalizedLeftX)/ (SCREEN_WIDTH);
      const floorYDirInc =  yDistance*(normalizedRightY - normalizedLeftY) / (SCREEN_WIDTH);
      floorYStart = worldToGrid(playerY) + yDistance*(normalizedLeftY);
      floorXStart = worldToGrid(playerX) + yDistance*(normalizedLeftX);


      for(let x = 0; x < SCREEN_WIDTH; x++){

        const cellX = Math.floor(Math.abs(floorXStart));
        const cellY = Math.floor(Math.abs(floorYStart));


        floorXStart+= floorXDirInc;
        floorYStart+=floorYDirInc;


        const pixelDestIndex = (y * SCREEN_WIDTH + x) * 4;

        if (debug) {
          console.log(`FloorStartX ${floorXStart} FloorStartY ${floorYStart}`)
          console.log(`CellX ${cellX} CellY ${cellY}`)
          console.log(`WORLD posX ${playerX} posY${playerY} GRID posX ${worldToGrid(playerX)} posY ${worldToGrid(playerY)}`)
          console.log(`FloorXInd ${floorXDirInc} FloorYInc ${floorYDirInc}`)
          console.log(`MapRatio ${mapRatio} MapAcc ${mapAcc}`)
          debug = false;
        }
        if((cellX + cellY) % 2){

            buffer[pixelDestIndex] = 0;     // Using fixed color for testing
            buffer[pixelDestIndex + 1] = 0;
            buffer[pixelDestIndex + 2] = 0;
            buffer[pixelDestIndex + 3] = 255;
        }else
            buffer[pixelDestIndex] = 255;     // Using fixed color for testing
            buffer[pixelDestIndex + 1] = 255;
            buffer[pixelDestIndex + 2] = 255;
            buffer[pixelDestIndex + 3] = 255;
        
      }
  }
  ctx.putImageData(FLOOR_TEXTURE_IMAGE_DATA, 0,0);
  if(RENDER_WALLS)
    wallsArray.forEach((wallProperties, index) => {
      const brightness = Math.max(255 - (wallProperties.distance * DISTANCE_SCALE / WORLD_SCALE) *  BRIGHT_FACTOR, 0);
      ctx.fillStyle = `rgb(${brightness}, 0, 0)`;
      ctx.fillRect(index, (SCREEN_HEIGHT - wallProperties.wallHeight) / 2, 1, wallProperties.wallHeight);
    })
  requestAnimationFrame((time) => render(canvas, ctx, time));
}             

Walls and floors

enter image description here

The main problem its in my rendering floor technique. New tiles “appears” below the walls. The desired effect would be, if there is a wall in a map position (7,4) the floor tiles around that should be always the same. But right now, as the player moves, “new” tiles slide from behind the wall, so depending of the player position and angle, near to (7,4) the floor tile may be appear white or blue, so its not “sync”.

I think the problem its the distance of the wall i get using DDA and the distance related to the difference between the current row in the screen space and my HORIZON its different, they are not “sync” and its normal because the are two different “types” of distances? I'm lost here. Thank you all for taking your time with this.