о том, как он построен, и от каких переменных камеры это зависит.

исал программу, которая вводит некоторые точки, выраженные в трехмерных координатах, и которые должны быть нарисованы на двухмерном холсте. Я использую перспективную проекцию, однородные координаты и подобные треугольники, чтобы сделать это. Однако моя программа не работает, и я на самом деле не знаю, почему.

Я следовал двум урокам. Я действительно понял геометрические определения и свойства, которые я прочитал. Однако моя реализация терпит неудачу ... Я буду писать ссылки на эти оба курса понемногу, чтобы сделать ваше чтение более удобным :).

Обзор: геометрические напоминания

Перспективная проекция выполняется в соответствии с этим рабочим процессом (см. Эти 2 курса - я написал соответствующие ссылки (якоря HTML) ниже, в этом посте):

Определение точек для рисования, выраженных в соответствии с мировой системой координат; Определение матрицы проекции, которая представляет собой матрицу преобразования, которая «преобразует» точку, выраженную в соответствии с мировой системой координат, в точку, выраженную в соответствии с системой координат камеры (примечание: эту матрицу также можно понимать как камеру)

Произведение этих точек с этой матрицей (как определено в соответствующей части ниже): произведение этих точек приводит к преобразованию этих точек в систему координат камеры. Обратите внимание, что точки и матрица выражены в 4D (концепция однородных координат).

Использование аналогичной концепции треугольников для проецирования (на этом этапе выполняется только вычисление) на холст выраженные в камере точки (с использованием их четырехмерных координат): теперь они выражаются в трехмерном формате (третья координата вычисляется, но фактически не используется в холст)

Последний шаг: растеризация, чтобы на самом деле нарисовать пиксели на холсте (на этом этапе выполняется другое вычисление И отображение).

Во-первых, проблема

Ну, я хочу нарисовать куб, но он не появляется. Спроецированные точки, кажется, нарисованы на тех же координатах.

Вместо моего куба виден только один черный пиксель.

Scastie (фрагмент)

Примечание: поскольку X11 не активирован в Scastie, окно, которое я хочу создать, не будет показано.

https://scastie.scala-lang.org/2LQ1wSMBTWqQQ7hql35sOg

Записи

Возможно, проблема связана с записями? Ну, я даю вам их.

Очки куба

Ссылка : себя

val world_cube_points : Seq[Seq[Double]] = Seq(
  Seq(0, 40, 0, 1),
  Seq(0, 40, 10, 1),
  Seq(0, 0, 0, 1),
  Seq(0, 0, 10, 1),
  Seq(20, 40, 0, 1),
  Seq(20, 40, 10, 1),
  Seq(20, 0, 0, 1),
  Seq(20, 0, 10, 1)
)
Матрица преобразования (проекции)

Ссылка :https://github.com/ssloy/tinyrenderer/wiki/Lesson-4:-Perspective-projection#time-to-work-in-full-3d

val matrix_world_to_camera : Matrix = new Matrix(Seq(
  Seq(1, 0, 0, 0),
  Seq(0, 1, 0, 0),
  Seq(0, 0, 1, 0),
  Seq(0, 0, -1, 1)
))
Во-вторых, первая операция, которую выполняет моя программа: простое произведение точки с матрицей.

Ссылка :https://github.com/ssloy/tinyrenderer/wiki/Lesson-4:-Perspective-projection#homogeneous-coordinates

/**
  * Matrix in the shape of (use of homogeneous coordinates) :
  * c00 c01 c02 c03
  * c10 c11 c12 c13
  * c20 c21 c22 c23
  *   0   0   0   1
  *
  * @param content the content of the matrix
  */
class Matrix(val content : Seq[Seq[Double]]) {

  /**
    * Computes the product between a point P(x ; y ; z) and the matrix.
    *
    * @param point a point P(x ; y ; z ; 1)
    * @return a new point P'(
    *         x * c00 + y * c10 + z * c20
    *         ;
    *         x * c01 + y * c11 + z * c21
    *         ;
    *         x * c02 + y * c12 + z * c22
    *         ;
    *         1
    *         )
    */
  def product(point : ,Seq[Double]) : Seq[Double] = {
    (0 to 3).map(
      i => content(i).zip(point).map(couple2 => couple2._1 * couple2._2).sum
    )
  }

}
Затем используйте похожие треугольники

Ссылка 1/2: часть «Важность преобразования точек в пространство камеры»https://www.scratchapixel.com/lessons/3d-basic-rendering/computing-pixel-coordinates-of-3d-point/mathematics-computing-2d-coordinates-of-3d-points

Ссылка 2/2:https://github.com/ssloy/tinyrenderer/wiki/Lesson-4:-Perspective-projection#time-to-work-in-full-3d

NB: на этом этапе записи являются точками, выраженными в соответствии с камерой (то есть: они являются результатом предварительно определенного продукта с предварительно определенной матрицей).

class Projector {

  /**
    * Computes the coordinates of the projection of the point P on the canvas.
    * The canvas is assumed to be 1 unit forward the camera.
    * The computation uses the definition of the similar triangles.
    *
    * @param points the point P we want to project on the canvas. Its coordinates must be expressed in the coordinates
    *          system of the camera before using this function.
    * @return the point P', projection of P.
    */
  def drawPointsOnCanvas(points : Seq[Seq[Double]]) : Seq[Seq[Double]] = {
    points.map(point => {
      point.map(coordinate => {
        coordinate / -point(3)
      }).dropRight(1)
    })

  }

}
Наконец, рисование проецируемых точек на холсте.

Ссылка : Часть. "Из пространства экрана в пространство растра"https://www.scratchapixel.com/lessons/3d-basic-rendering/computing-pixel-coordinates-of-3d-point/mathematics-computing-2d-coordinates-of-3d-points

import java.awt.Graphics
import javax.swing.JFrame

/**
  * Assumed to be 1 unit forward the camera.
  * Contains the drawn points.
  */
class Canvas(val drawn_points : Seq[Seq[Double]]) extends JFrame {

  val CANVAS_WIDTH = 60
  val CANVAS_HEIGHT = 60
  val IMAGE_WIDTH = 55
  val IMAGE_HEIGHT = 55

  def display = {
    setTitle("Perlin")
    setSize(CANVAS_WIDTH, CANVAS_HEIGHT)
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
    setVisible(true)
  }

  override def paint(graphics : Graphics): Unit = {
    super.paint(graphics)
    drawn_points.foreach(point => {

      if(!(Math.abs(point.head) <= CANVAS_WIDTH / 2 || Math.abs(point(1)) <= CANVAS_HEIGHT / 2)) {
        println("WARNING : the point (" + point.head + " ; " + point(1) + ") can't be drawn in this canvas.")
      } else {
        val normalized_drawn_point = Seq((point.head + (CANVAS_WIDTH / 2)) / CANVAS_WIDTH, (point(1) + (CANVAS_HEIGHT / 2)) / CANVAS_HEIGHT)
        graphics.drawRect(normalized_drawn_point.head.toInt * IMAGE_WIDTH, (1 - normalized_drawn_point(1).toInt) * IMAGE_HEIGHT, 1, 1)
      }
    })
  }

}
... и пусковая установка
object Main {
  def main(args : Array[String]) : Unit = {
    val projector = new Projector()

    val world_cube_points : Seq[Seq[Double]] = Seq(
      Seq(0, 40, 0, 1),
      Seq(0, 40, 10, 1),
      Seq(0, 0, 0, 1),
      Seq(0, 0, 10, 1),
      Seq(20, 40, 0, 1),
      Seq(20, 40, 10, 1),
      Seq(20, 0, 0, 1),
      Seq(20, 0, 10, 1)
    )

    val matrix_world_to_camera : Matrix = new Matrix(Seq(
      Seq(1, 0, 0, 0),
      Seq(0, 1, 0, 0),
      Seq(0, 0, 1, 0),
      Seq(0, 0, -1, 1)
    ))

    val points_to_draw_on_canvas = projector.drawPointsOnCanvas(world_cube_points.map(point => {
      matrix_world_to_camera.product(point)
    }))
    new Canvas(points_to_draw_on_canvas).display

  }
}
Вопрос

Что не так с моей программой? Я понял геометрические концепции, объясненные этими обоими уроками, которые я внимательно прочитал. Я уверен, что мой продукт работает. Я думаю, что или растеризация, или записи (матрица) могут быть неправильными ...

Ответы на вопрос(1)

Ваш ответ на вопрос