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 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>;
|
||||||
|
|
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 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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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_);
|
||||||
|
|
|
@ -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>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_;
|
||||||
|
|
Loading…
Reference in New Issue