add projection transform.
This commit is contained in:
parent
a063b29d07
commit
da941c0fd0
|
@ -12,3 +12,4 @@ using Point2d = Eigen::Vector2d;
|
|||
using Point3d = Eigen::Vector3d;
|
||||
using BBox = cv::Rect2i;
|
||||
using PixelProperty = Eigen::Vector4d;
|
||||
using TransformMatrix = Eigen::Matrix<double, 4, 4>;
|
||||
|
|
15
src/main.cc
15
src/main.cc
|
@ -17,12 +17,12 @@ int main(int argc, char *argv[]) {
|
|||
const int resolution_height = 180;
|
||||
const int far = -1000;
|
||||
const int near = -10;
|
||||
const float fov = 120. / 360. * M_PI;
|
||||
const float fov = 120. / 180. * M_PI;
|
||||
const float aspect_ratio = static_cast<float>(resolution_width) /
|
||||
static_cast<float>(resolution_height);
|
||||
|
||||
std::vector<Triangle> primitives{
|
||||
{Point3d{90, 45, -2}, Point3d{180, 135, -2}, Point3d{270, 45, -2}}};
|
||||
{Point3d{10, 5, -20}, Point3d{30, 25, -20}, Point3d{55, 5, -20}}};
|
||||
|
||||
cv::namedWindow("MinusRenderer", cv::WINDOW_AUTOSIZE);
|
||||
const auto start = std::chrono::steady_clock::now();
|
||||
|
@ -31,13 +31,16 @@ int main(int argc, char *argv[]) {
|
|||
const auto elapse = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - start)
|
||||
.count();
|
||||
renderer.model_transform(
|
||||
Eigen::AngleAxisd(0.125 * M_PI, Eigen::Vector3d::UnitY())
|
||||
.toRotationMatrix());
|
||||
TransformMatrix m{
|
||||
Eigen::Transform<double, 3, Eigen::Affine>(
|
||||
Eigen::AngleAxisd(0.125 * M_PI, Eigen::Vector3d::UnitZ())
|
||||
.toRotationMatrix())
|
||||
.matrix()};
|
||||
renderer.model_transform(m);
|
||||
const auto &color_image =
|
||||
renderer.render(resolution_width, resolution_height);
|
||||
cv::imshow("MinusRenderer", color_image);
|
||||
} while (cv::waitKey(50) == -1);
|
||||
} while (cv::waitKey(25) == -1);
|
||||
cv::destroyWindow("MinusRenderer");
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -1,27 +1,72 @@
|
|||
// Copyright 2024 Bytedance Inc. All Rights Reserved.
|
||||
// Author: tianlei.richard@qq.com (tianlei.richard)
|
||||
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
|
||||
#include "minus_renderer.h"
|
||||
#include "rasterizer.h"
|
||||
|
||||
#include "spdlog/spdlog.h"
|
||||
#include <cmath>
|
||||
|
||||
MinusRenderer::MinusRenderer(float near, float far, float fov,
|
||||
float aspect_ratio,
|
||||
std::vector<Triangle> &&primitives)
|
||||
: near_(near), far_(far), fov_(fov), aspect_ratio_(aspect_ratio),
|
||||
height_(calculate_height(fov, near)),
|
||||
width_(calculate_width(height_, aspect_ratio)), primitives_(primitives) {}
|
||||
width_(calculate_width(height_, aspect_ratio)), primitives_(primitives) {
|
||||
spdlog::info("fov: {}, aspect ratio: {}, width: {}, height: {}", fov_,
|
||||
aspect_ratio_, width_, height_);
|
||||
}
|
||||
|
||||
int MinusRenderer::calculate_height(const float fov, const float near) {
|
||||
float MinusRenderer::calculate_height(const float fov, const float near) {
|
||||
return std::fabs(near) * std::tan(fov * 0.5) * 2;
|
||||
}
|
||||
|
||||
int MinusRenderer::calculate_width(const float height, const float ratio) {
|
||||
float MinusRenderer::calculate_width(const float height, const float ratio) {
|
||||
return height * ratio;
|
||||
}
|
||||
|
||||
void MinusRenderer::model_transform(const Triangle::AffineTransformType &m) {
|
||||
TransformMatrix MinusRenderer::squish_tranform() {
|
||||
// Frustum to Cuboid
|
||||
return TransformMatrix{{near_, 0, 0, 0},
|
||||
{0, near_, 0, 0},
|
||||
{0, 0, near_ + far_, -near_ * far_},
|
||||
{0, 0, 1, 0}};
|
||||
}
|
||||
|
||||
TransformMatrix MinusRenderer::orthographic_tranform() {
|
||||
|
||||
const auto right = width_ * 0.5;
|
||||
const auto left = -right;
|
||||
const auto top = height_ * 0.5;
|
||||
const auto bottom = -top;
|
||||
spdlog::info("near: {}, far: {}, top: {}, bottom: {}, left: {}, right: {}",
|
||||
near_, far_, top, bottom, left, right);
|
||||
|
||||
TransformMatrix m{{1, 0, 0, -0.5 * (right - left)},
|
||||
{0, 1, 0, -0.5 * (top - bottom)},
|
||||
{0, 0, 1, -0.5 * (far_ - near_)},
|
||||
{0, 0, 0, 1}};
|
||||
|
||||
m = TransformMatrix{{2 / (right - left), 0, 0, 0},
|
||||
{0, 2 / (top - bottom), 0, 0},
|
||||
{0, 0, 2 / std::fabs(far_ - near_), 0},
|
||||
{0, 0, 0, 1}} *
|
||||
m;
|
||||
|
||||
std::cout << m << '\n';
|
||||
return m;
|
||||
}
|
||||
|
||||
TransformMatrix MinusRenderer::view_port_transform() {
|
||||
return TransformMatrix{{width_ * 0.5, 0, 0, width_ * 0.5},
|
||||
{0, height_ * 0.5, 0, height_ * 0.5},
|
||||
{0, 0, 1, 0},
|
||||
{0, 0, 0, 1}};
|
||||
}
|
||||
|
||||
void MinusRenderer::model_transform(const TransformMatrix &m) {
|
||||
for (auto &t : primitives_) {
|
||||
t.affine_transform(m);
|
||||
}
|
||||
|
@ -29,8 +74,18 @@ void MinusRenderer::model_transform(const Triangle::AffineTransformType &m) {
|
|||
|
||||
cv::Mat MinusRenderer::render(const int resolution_width,
|
||||
const int resolution_height) {
|
||||
std::vector<Triangle> primitives;
|
||||
for (const auto &t : primitives_) {
|
||||
primitives.push_back(t);
|
||||
}
|
||||
for (auto &t : primitives) {
|
||||
t.projective_transform(squish_tranform());
|
||||
t.affine_transform(orthographic_tranform());
|
||||
t.affine_transform(view_port_transform());
|
||||
}
|
||||
|
||||
Rasterizer rasterizer{resolution_width, resolution_height};
|
||||
const auto &pixels = rasterizer.rasterize(primitives_);
|
||||
const auto &pixels = rasterizer.rasterize(primitives);
|
||||
assert(!pixels.empty());
|
||||
cv::Mat color_image(pixels.size(), (pixels[0]).size(), CV_8UC3);
|
||||
|
||||
|
|
|
@ -15,11 +15,16 @@ public:
|
|||
cv::Mat render(const int resolution_width, const int resolution_height);
|
||||
|
||||
public:
|
||||
void model_transform(const Triangle::AffineTransformType &m);
|
||||
void model_transform(const TransformMatrix &m);
|
||||
|
||||
private:
|
||||
static int calculate_height(const float fov, const float near);
|
||||
static int calculate_width(const float height, const float ratio);
|
||||
static float calculate_height(const float fov, const float near);
|
||||
static float calculate_width(const float height, const float ratio);
|
||||
|
||||
private:
|
||||
TransformMatrix squish_tranform();
|
||||
TransformMatrix orthographic_tranform();
|
||||
TransformMatrix view_port_transform();
|
||||
|
||||
private:
|
||||
float near_;
|
||||
|
@ -27,8 +32,8 @@ private:
|
|||
float fov_; // In radian
|
||||
float aspect_ratio_;
|
||||
|
||||
int height_;
|
||||
int width_;
|
||||
float height_;
|
||||
float width_;
|
||||
|
||||
std::vector<Triangle> primitives_;
|
||||
};
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "rasterizer.h"
|
||||
#include "spdlog/fmt/ostr.h" // github.com/gabime/spdlog/issues/1638
|
||||
#include "spdlog/spdlog.h"
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
|
||||
Rasterizer::Rasterizer(const int width, const int height)
|
||||
|
@ -17,6 +18,10 @@ Rasterizer::Rasterizer(const int width, const int height)
|
|||
std::vector<std::vector<PixelProperty>>
|
||||
Rasterizer::rasterize(const std::vector<Triangle> &primitives) {
|
||||
for (const auto &t : primitives) {
|
||||
const auto &triangle_points = t.get_points<3>();
|
||||
std::cout << "triangle: " << triangle_points[0] << ", "
|
||||
<< triangle_points[1] << ", " << triangle_points[2] << '\n';
|
||||
|
||||
const auto &aabb = t.axis_align_bbox();
|
||||
const int x_min = std::min(std::max(0, aabb.x), width_);
|
||||
const int x_max = std::min(std::max(0, aabb.x + aabb.width), width_);
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
// Author: tianlei.richard@qq.com (tianlei.richard)
|
||||
|
||||
#include "triangle.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
Triangle::Triangle(const Point3d &a, const Point3d &b, const Point3d &c)
|
||||
: points_({a, b, c}) {}
|
||||
|
@ -26,15 +28,19 @@ Vector3d Triangle::normal_vector() const {
|
|||
return v1.cross(v2).normalized();
|
||||
}
|
||||
|
||||
void Triangle::affine_transform(const AffineTransformType &m) {
|
||||
Eigen::Transform<double, 3, Eigen::Affine> affine_matrix(m);
|
||||
void Triangle::affine_transform(const TransformMatrix &m) {
|
||||
for (auto &p : points_) {
|
||||
p = (affine_matrix * Eigen::Vector4d(p.x(), p.y(), p.z(), 1)).head(3);
|
||||
p = (m * Eigen::Vector4d(p.x(), p.y(), p.z(), 1.)).head<3>();
|
||||
}
|
||||
}
|
||||
|
||||
void Triangle::projective_transform(const ProjectiveTransformType &m) {
|
||||
void Triangle::projective_transform(const TransformMatrix &m) {
|
||||
// std::cout << "triangle: " << points_[0] << ", " << points_[1] << ", "
|
||||
// << points_[2] << '\n';
|
||||
for (auto &p : points_) {
|
||||
p = (m * Eigen::Vector4d(p.x(), p.y(), p.z(), 1)).head(3);
|
||||
auto p_homo = m * Eigen::Vector4d(p.x(), p.y(), p.z(), 1.);
|
||||
// std::cout << "triangle: " << p_homo << '\n';
|
||||
// spdlog::info("w: {}", p_homo.w());
|
||||
p = (p_homo / p_homo.w()).head<3>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,11 +8,6 @@
|
|||
#include <array>
|
||||
|
||||
class Triangle {
|
||||
public:
|
||||
using AffineTransformType = Eigen::Matrix<double, 3, 3>;
|
||||
using ProjectiveTransformType =
|
||||
Eigen::Transform<double, 3, Eigen::Projective>;
|
||||
|
||||
private:
|
||||
using HomoPointType = Eigen::Vector4d;
|
||||
|
||||
|
@ -34,8 +29,8 @@ public:
|
|||
BBox axis_align_bbox() const;
|
||||
Vector3d normal_vector() const;
|
||||
|
||||
void affine_transform(const AffineTransformType &m);
|
||||
void projective_transform(const ProjectiveTransformType &m);
|
||||
void affine_transform(const TransformMatrix &m);
|
||||
void projective_transform(const TransformMatrix &m);
|
||||
|
||||
private:
|
||||
std::array<Point3d, 3> points_;
|
||||
|
|
Loading…
Reference in New Issue