add projection transform.

This commit is contained in:
tianlei.richard 2024-03-06 22:23:48 +08:00
parent a063b29d07
commit da941c0fd0
7 changed files with 99 additions and 29 deletions

View File

@ -12,3 +12,4 @@ using Point2d = Eigen::Vector2d;
using Point3d = Eigen::Vector3d; using Point3d = Eigen::Vector3d;
using BBox = cv::Rect2i; using BBox = cv::Rect2i;
using PixelProperty = Eigen::Vector4d; using PixelProperty = Eigen::Vector4d;
using TransformMatrix = Eigen::Matrix<double, 4, 4>;

View File

@ -17,12 +17,12 @@ int main(int argc, char *argv[]) {
const int resolution_height = 180; const int resolution_height = 180;
const int far = -1000; const int far = -1000;
const int near = -10; 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) / const float aspect_ratio = static_cast<float>(resolution_width) /
static_cast<float>(resolution_height); static_cast<float>(resolution_height);
std::vector<Triangle> primitives{ 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); cv::namedWindow("MinusRenderer", cv::WINDOW_AUTOSIZE);
const auto start = std::chrono::steady_clock::now(); 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>( const auto elapse = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - start) std::chrono::steady_clock::now() - start)
.count(); .count();
renderer.model_transform( TransformMatrix m{
Eigen::AngleAxisd(0.125 * M_PI, Eigen::Vector3d::UnitY()) Eigen::Transform<double, 3, Eigen::Affine>(
.toRotationMatrix()); Eigen::AngleAxisd(0.125 * M_PI, Eigen::Vector3d::UnitZ())
.toRotationMatrix())
.matrix()};
renderer.model_transform(m);
const auto &color_image = const auto &color_image =
renderer.render(resolution_width, resolution_height); renderer.render(resolution_width, resolution_height);
cv::imshow("MinusRenderer", color_image); cv::imshow("MinusRenderer", color_image);
} while (cv::waitKey(50) == -1); } while (cv::waitKey(25) == -1);
cv::destroyWindow("MinusRenderer"); cv::destroyWindow("MinusRenderer");
return 0; return 0;

View File

@ -1,27 +1,72 @@
// Copyright 2024 Bytedance Inc. All Rights Reserved. // Copyright 2024 Bytedance Inc. All Rights Reserved.
// Author: tianlei.richard@qq.com (tianlei.richard) // Author: tianlei.richard@qq.com (tianlei.richard)
#include <cmath>
#include <iostream>
#include "minus_renderer.h" #include "minus_renderer.h"
#include "rasterizer.h" #include "rasterizer.h"
#include "spdlog/spdlog.h" #include "spdlog/spdlog.h"
#include <cmath>
MinusRenderer::MinusRenderer(float near, float far, float fov, MinusRenderer::MinusRenderer(float near, float far, float fov,
float aspect_ratio, float aspect_ratio,
std::vector<Triangle> &&primitives) std::vector<Triangle> &&primitives)
: near_(near), far_(far), fov_(fov), aspect_ratio_(aspect_ratio), : near_(near), far_(far), fov_(fov), aspect_ratio_(aspect_ratio),
height_(calculate_height(fov, near)), 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; 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; 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_) { for (auto &t : primitives_) {
t.affine_transform(m); t.affine_transform(m);
} }
@ -29,8 +74,18 @@ void MinusRenderer::model_transform(const Triangle::AffineTransformType &m) {
cv::Mat MinusRenderer::render(const int resolution_width, cv::Mat MinusRenderer::render(const int resolution_width,
const int resolution_height) { 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}; Rasterizer rasterizer{resolution_width, resolution_height};
const auto &pixels = rasterizer.rasterize(primitives_); const auto &pixels = rasterizer.rasterize(primitives);
assert(!pixels.empty()); assert(!pixels.empty());
cv::Mat color_image(pixels.size(), (pixels[0]).size(), CV_8UC3); cv::Mat color_image(pixels.size(), (pixels[0]).size(), CV_8UC3);

View File

@ -15,11 +15,16 @@ public:
cv::Mat render(const int resolution_width, const int resolution_height); cv::Mat render(const int resolution_width, const int resolution_height);
public: public:
void model_transform(const Triangle::AffineTransformType &m); void model_transform(const TransformMatrix &m);
private: private:
static int calculate_height(const float fov, const float near); static float calculate_height(const float fov, const float near);
static int calculate_width(const float height, const float ratio); static float calculate_width(const float height, const float ratio);
private:
TransformMatrix squish_tranform();
TransformMatrix orthographic_tranform();
TransformMatrix view_port_transform();
private: private:
float near_; float near_;
@ -27,8 +32,8 @@ private:
float fov_; // In radian float fov_; // In radian
float aspect_ratio_; float aspect_ratio_;
int height_; float height_;
int width_; float width_;
std::vector<Triangle> primitives_; std::vector<Triangle> primitives_;
}; };

View File

@ -4,6 +4,7 @@
#include "rasterizer.h" #include "rasterizer.h"
#include "spdlog/fmt/ostr.h" // github.com/gabime/spdlog/issues/1638 #include "spdlog/fmt/ostr.h" // github.com/gabime/spdlog/issues/1638
#include "spdlog/spdlog.h" #include "spdlog/spdlog.h"
#include <iostream>
#include <limits> #include <limits>
Rasterizer::Rasterizer(const int width, const int height) 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>> std::vector<std::vector<PixelProperty>>
Rasterizer::rasterize(const std::vector<Triangle> &primitives) { Rasterizer::rasterize(const std::vector<Triangle> &primitives) {
for (const auto &t : 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 auto &aabb = t.axis_align_bbox();
const int x_min = std::min(std::max(0, aabb.x), width_); 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_); const int x_max = std::min(std::max(0, aabb.x + aabb.width), width_);

View File

@ -2,7 +2,9 @@
// Author: tianlei.richard@qq.com (tianlei.richard) // Author: tianlei.richard@qq.com (tianlei.richard)
#include "triangle.h" #include "triangle.h"
#include "spdlog/spdlog.h"
#include <algorithm> #include <algorithm>
#include <iostream>
Triangle::Triangle(const Point3d &a, const Point3d &b, const Point3d &c) Triangle::Triangle(const Point3d &a, const Point3d &b, const Point3d &c)
: points_({a, b, c}) {} : points_({a, b, c}) {}
@ -26,15 +28,19 @@ Vector3d Triangle::normal_vector() const {
return v1.cross(v2).normalized(); return v1.cross(v2).normalized();
} }
void Triangle::affine_transform(const AffineTransformType &m) { void Triangle::affine_transform(const TransformMatrix &m) {
Eigen::Transform<double, 3, Eigen::Affine> affine_matrix(m);
for (auto &p : points_) { 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_) { 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>();
} }
} }

View File

@ -8,11 +8,6 @@
#include <array> #include <array>
class Triangle { class Triangle {
public:
using AffineTransformType = Eigen::Matrix<double, 3, 3>;
using ProjectiveTransformType =
Eigen::Transform<double, 3, Eigen::Projective>;
private: private:
using HomoPointType = Eigen::Vector4d; using HomoPointType = Eigen::Vector4d;
@ -34,8 +29,8 @@ public:
BBox axis_align_bbox() const; BBox axis_align_bbox() const;
Vector3d normal_vector() const; Vector3d normal_vector() const;
void affine_transform(const AffineTransformType &m); void affine_transform(const TransformMatrix &m);
void projective_transform(const ProjectiveTransformType &m); void projective_transform(const TransformMatrix &m);
private: private:
std::array<Point3d, 3> points_; std::array<Point3d, 3> points_;