【问题标题】:How do I fix warped walls in my raycaster? (I have tried using cosine correction)如何在我的光线投射器中修复扭曲的墙壁? (我尝试过使用余弦校正)
【发布时间】:2021-05-28 03:51:11
【问题描述】:

我知道这里有许多已回答的问题都在问完全相同的问题。但是,我尝试实施解决方案(余弦校正)并且收效甚微。注:本版本代码未实现。

就我的代码而言,我将上传整个内容,但可能需要修复的部分是 Player 类。其余的都是相当无聊的东西。我也知道它是基于您不会拥有的图像运行的,但是对于测试,请随意使用任何只有黑白的 600x600 图像。或者联系我获取我的。白色表示墙壁。我还将上传扭曲墙壁的屏幕截图。控件是用于移动的 WASD,加上一些用于更改视图的故障鼠标控件(将被修复)以及按住 m 以查看当前级别的地图。 Screenshot of it running

PImage maze;
int stepSize, renderDistance;
float viewStep, fov, moveSpeed;
float minLine, maxLine;
Player p;
boolean w, s, a, d, map;

void setup() {
  size(600, 600);
  background(0);
  strokeWeight(3);
  
  maze = loadImage("testmaze3.png");
  
  stepSize = 1;
  fov = PI/4;
  viewStep = fov/(width/4);
  renderDistance = 300;
  moveSpeed = 2;
  minLine = 0;
  maxLine = 200;
  
  colorMode(RGB, renderDistance);
  p = new Player(width/2, height/2, 0);
  
  w = false;
  s = false;
  a = false;
  d = false;
}

void draw() {
  maze.loadPixels();
  
  if (map) {
    pushStyle();
    
    background(maze);
    
    fill(255, 0, 0);
    noStroke();
    ellipse(p.x, p.y, 10,10);
    stroke(renderDistance);
    
    pushMatrix();
    translate(p.x, p.y);
    
    line(0, 0, renderDistance*cos(p.direction), renderDistance*sin(p.direction));
    
    popMatrix();
    popStyle();
  }
  
  pushMatrix();
  translate(p.x, p.y);
  
  if (w) {
    if (maze.get(int(p.x + moveSpeed*cos(p.direction)), int(p.y + moveSpeed*sin(p.direction))) != color(renderDistance)) {
      p.x += moveSpeed*cos(p.direction);
      p.y += moveSpeed*sin(p.direction);
    }
  }
  if (s) {
    if (maze.get(int(p.x - moveSpeed*cos(p.direction)), int(p.y - moveSpeed*sin(p.direction))) != color(renderDistance)) {
      p.x -= moveSpeed*cos(p.direction);
      p.y -= moveSpeed*sin(p.direction);
    }
  }
  if (d) {
    if (maze.get(int(p.x - moveSpeed*cos(p.direction-PI/2)), int(p.y - moveSpeed*sin(p.direction-PI/2))) != color(renderDistance)) {
      p.x -= moveSpeed*cos(p.direction-PI/2);
      p.y -= moveSpeed*sin(p.direction-PI/2);
    }
  }
  if (a) {
    if (maze.get(int(p.x - moveSpeed*cos(p.direction+PI/2)), int(p.y - moveSpeed*sin(p.direction+PI/2))) != color(renderDistance)) {
      p.x -= moveSpeed*cos(p.direction+PI/2);
      p.y -= moveSpeed*sin(p.direction+PI/2);
    }
  }
  
  popMatrix();
  
  p.direction += ((float)mouseX-(float)pmouseX)/100;
  
  if (!map) {
    pushStyle();

    noStroke();
    fill(0, 0, renderDistance);
    rect(0, 0, width, height/2);
    fill(0, 0, renderDistance*0.6);
    rect(0, height/2, width, height);

    popStyle();

    p.display();
  }   
}

void keyPressed() {
  if (key == 'w') {
    w = true;
  }
  if (key == 's') {
    s = true;
  }
  if (key == 'a') {
    a = true;
  }
  if (key == 'd') {
    d = true;
  }
  if (key == 'm') {
    map = true;
  }
}
void keyReleased() {
  if (key == 'w') {
    w = false;
  }
  if (key == 's') {
    s = false;
  }
  if (key == 'a') {
    a = false;
  }
  if (key == 'd') {
    d = false;
  }
  if (key == 'm') {
    map = false;
  }
}

class Player {
  float x, y, direction;
  
  Player(int x, int y, float direction) {
    this.x = x;
    this.y = y;    
    this.direction = direction;
  }
  
  void display() {
    maze.loadPixels();
    
    for (float i = direction - fov; i < direction + fov; i += viewStep) {
      FloatList line = new FloatList();
      line = rayCast(i);
                                   
      float length_ = (height - maxLine - minLine - map(line.get(2), 0, renderDistance, minLine, maxLine));
      
      stroke(renderDistance - line.get(2), 0, 0);
      
      if (line.get(3) == 1){
        stroke(renderDistance - line.get(2));
      }
      
      if (renderDistance - line.get(2) > 1) {
        line(map(i, direction - fov/2, direction + fov, 0, width), height/2 + length_/2, map(i, direction - fov/2, direction + fov, 0, width), height/2 - length_/2); 
      }
    }
  }
  
  FloatList rayCast(float direction) {
    
    FloatList out = new FloatList();
    float rayx = x;
    float rayy = y;
    int steps = 0;
    
    for (int i = 0; i < renderDistance; i++) {
      if (maze.get(int(rayx), int(rayy)) != color(0)) {
        break;
      }
      
      rayx += stepSize * cos(direction);
      rayy += stepSize * sin(direction);

      steps++;
    }

    out.append(rayx);
    out.append(rayy);
    out.append(steps);
    if (rayx < 0 || rayx > width || rayy > height || rayy < 0) {
      out.append(1);
    } else {
      out.append(0);
    }
    return out;
  }
}

【问题讨论】:

    标签: processing


    【解决方案1】:

    您的光线投射算法会计算从墙壁到相机中无限小的焦点的距离。当我们尝试将其投影到我们的屏幕上时,我们会得到一个扭曲的图像,因为我们的屏幕是一个平面,而不是一个点或球体。 为了修复失真,我们必须计算从墙壁到屏幕的距离,而不是焦点。这可以通过简单的三角函数来完成:

    将原始(欧几里得)距离乘以 cos(angle) 即可得到到屏幕的距离。

    drawing

    所以在清理代码并添加更正后,它看起来像这样:

       void display() {
            maze.loadPixels();
            
            float wallHalfHeight = 50;
            float distanceFocusProjection = (height / 2) / tan(fov);
    
            for (float angle = -fov; angle < fov; angle += viewStep) {
                float euclideanDist = rayCast(direction + angle);
    
                if (euclideanDist < renderDistance) {
                    float distToScreen = euclideanDist * cos(angle);
                    float scanLineHalfHeight = wallHalfHeight * (distanceFocusProjection / distToScreen);
                    float scanLineX = map(angle, -fov, fov, 0, width);
                    
                    stroke(renderDistance - distToScreen, 0, 0);
                    line(scanLineX, height/2 + scanLineHalfHeight, scanLineX, height/2 - scanLineHalfHeight);
                }
            }
        }
    
        float rayCast(float angle) {
            PVector position = new PVector(x, y);
            PVector direction = PVector.fromAngle(angle); //new PVector(cos(angle), sin(angle));
    
            int distance;
            for(distance = 0; distance < renderDistance; distance++) {
                if (maze.get(round(position.x), round(position.y)) != color(0)) {
                    break;
                }
                position.add(direction);
            }
            return distance;
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-09
      • 2021-08-05
      • 2015-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-09-22
      相关资源
      最近更新 更多