invole transformation to triangle primitives.
This commit is contained in:
parent
d79d9ac1b5
commit
a063b29d07
|
@ -3,7 +3,7 @@ PROJECT(minus_renderer)
|
|||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
find_package(OpenCV REQUIRED core imgproc)
|
||||
find_package(OpenCV REQUIRED core imgproc highgui)
|
||||
|
||||
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)
|
||||
|
||||
|
|
|
@ -4,4 +4,5 @@ PROJECT(renderer)
|
|||
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} CPP_FILES)
|
||||
|
||||
add_executable(${CMAKE_PROJECT_NAME} ${CPP_FILES})
|
||||
target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE ${OpenCV_INCLUDE_DIRS})
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME} LINK_PUBLIC spdlog eigen ${OpenCV_LIBS})
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
// Copyright 2024 Bytedance Inc. All Rights Reserved.
|
||||
// Author: tianlei.richard@bytedance.com (tianlei.richard)
|
||||
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "minus_renderer.h"
|
||||
#include "triangle.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
spdlog::set_level(spdlog::level::trace);
|
||||
|
||||
const int resolution_width = 320;
|
||||
const int resolution_height = 180;
|
||||
const int far = -1000;
|
||||
const int near = -10;
|
||||
const float fov = 120. / 360. * 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}}};
|
||||
|
||||
cv::namedWindow("MinusRenderer", cv::WINDOW_AUTOSIZE);
|
||||
const auto start = std::chrono::steady_clock::now();
|
||||
MinusRenderer renderer{near, far, fov, aspect_ratio, std::move(primitives)};
|
||||
do {
|
||||
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());
|
||||
const auto &color_image =
|
||||
renderer.render(resolution_width, resolution_height);
|
||||
cv::imshow("MinusRenderer", color_image);
|
||||
} while (cv::waitKey(50) == -1);
|
||||
cv::destroyWindow("MinusRenderer");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,29 +1,51 @@
|
|||
// Copyright 2024 Bytedance Inc. All Rights Reserved.
|
||||
// Author: tianlei.richard@qq.com (tianlei.richard)
|
||||
|
||||
#include <Eigen/Dense>
|
||||
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "spdlog/fmt/ostr.h" // github.com/gabime/spdlog/issues/1638
|
||||
|
||||
#include "common.h"
|
||||
#include "minus_renderer.h"
|
||||
#include "rasterizer.h"
|
||||
#include "triangle.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
#include <cmath>
|
||||
|
||||
using namespace Eigen;
|
||||
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) {}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
const int width = 1280;
|
||||
const int height = 720;
|
||||
|
||||
Triangle t{Point3d{1, 1, -2}, Point3d{3, 1, -2}, Point3d{2, 4, -2}};
|
||||
|
||||
Rasterizer rasterizer{width, height};
|
||||
rasterizer.rasterize(t);
|
||||
|
||||
return 0;
|
||||
int 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) {
|
||||
return height * ratio;
|
||||
}
|
||||
|
||||
void MinusRenderer::model_transform(const Triangle::AffineTransformType &m) {
|
||||
for (auto &t : primitives_) {
|
||||
t.affine_transform(m);
|
||||
}
|
||||
}
|
||||
|
||||
cv::Mat MinusRenderer::render(const int resolution_width,
|
||||
const int resolution_height) {
|
||||
Rasterizer rasterizer{resolution_width, resolution_height};
|
||||
const auto &pixels = rasterizer.rasterize(primitives_);
|
||||
assert(!pixels.empty());
|
||||
cv::Mat color_image(pixels.size(), (pixels[0]).size(), CV_8UC3);
|
||||
|
||||
for (int i = 0; i < pixels.size(); ++i) {
|
||||
const auto &row = pixels[i];
|
||||
for (int j = 0; j < row.size(); ++j) {
|
||||
auto &pixel_color = color_image.at<cv::Vec3b>(pixels.size() - i - 1, j);
|
||||
pixel_color =
|
||||
cv::Vec3b{static_cast<unsigned char>(
|
||||
row[j].x() * std::numeric_limits<char>::max()),
|
||||
static_cast<unsigned char>(
|
||||
row[j].y() * std::numeric_limits<char>::max()),
|
||||
static_cast<unsigned char>(
|
||||
row[j].z() * std::numeric_limits<char>::max())};
|
||||
}
|
||||
}
|
||||
return color_image;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright 2024 Bytedance Inc. All Rights Reserved.
|
||||
// Author: tianlei.richard@bytedance.com (tianlei.richard)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "triangle.h"
|
||||
#include <opencv2/core/core.hpp>
|
||||
|
||||
class MinusRenderer {
|
||||
public:
|
||||
MinusRenderer(float near, float far, float fov, float aspect_ratio,
|
||||
std::vector<Triangle> &&primitives);
|
||||
|
||||
public:
|
||||
cv::Mat render(const int resolution_width, const int resolution_height);
|
||||
|
||||
public:
|
||||
void model_transform(const Triangle::AffineTransformType &m);
|
||||
|
||||
private:
|
||||
static int calculate_height(const float fov, const float near);
|
||||
static int calculate_width(const float height, const float ratio);
|
||||
|
||||
private:
|
||||
float near_;
|
||||
float far_;
|
||||
float fov_; // In radian
|
||||
float aspect_ratio_;
|
||||
|
||||
int height_;
|
||||
int width_;
|
||||
|
||||
std::vector<Triangle> primitives_;
|
||||
};
|
|
@ -2,43 +2,55 @@
|
|||
// Author: tianlei.richard@qq.com (tianlei.richard)
|
||||
|
||||
#include "rasterizer.h"
|
||||
#include "spdlog/fmt/ostr.h" // github.com/gabime/spdlog/issues/1638
|
||||
#include "spdlog/spdlog.h"
|
||||
#include <limits>
|
||||
|
||||
Rasterizer::Rasterizer(const int width, const int height)
|
||||
: width_(width), height_(height),
|
||||
pixels_(std::vector<std::vector<PixelProperty>>(
|
||||
height,
|
||||
std::vector<PixelProperty>(
|
||||
width, PixelProperty{0., 0., 0.,
|
||||
std::numeric_limits<double>::infinity()}))) {
|
||||
}
|
||||
height, std::vector<PixelProperty>(
|
||||
width, PixelProperty{
|
||||
0., 0., 0.,
|
||||
-std::numeric_limits<double>::infinity()}))) {}
|
||||
|
||||
void Rasterizer::rasterize(const Triangle &t) {
|
||||
std::vector<std::vector<PixelProperty>>
|
||||
Rasterizer::rasterize(const std::vector<Triangle> &primitives) {
|
||||
for (const auto &t : primitives) {
|
||||
const auto &aabb = t.axis_align_bbox();
|
||||
const int x_min = aabb.x;
|
||||
const int x_max = aabb.x + aabb.width;
|
||||
const int y_min = aabb.y;
|
||||
const int y_max = aabb.y + aabb.height;
|
||||
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 y_min = std::min(std::max(0, aabb.y), height_);
|
||||
const int y_max = std::min(std::max(0, aabb.y + aabb.height), height_);
|
||||
|
||||
for (int i = x_min; i < x_max; ++i) {
|
||||
for (int j = y_min; j < y_max; ++j) {
|
||||
auto &property = pixels_[j][i];
|
||||
const auto &[is_inside, z_screen] = inside(Point2d{i + 0.5, j + 0.5}, t);
|
||||
spdlog::info("Triangle range, ({},{},{},{})", x_min, x_max, y_min, y_max);
|
||||
for (int i = y_min; i < y_max; ++i) {
|
||||
for (int j = x_min; j < x_max; ++j) {
|
||||
auto &property = pixels_[i][j];
|
||||
const auto &[is_inside, z_screen] =
|
||||
inside(Point2d{j + 0.5, i + 0.5}, t);
|
||||
// spdlog::debug("is_inside: {}, current depth: {}, closest depth: {}",
|
||||
// is_inside, z_screen, property[3]);
|
||||
if (is_inside && z_screen > property[3]) {
|
||||
property[0] = 1;
|
||||
property[1] = 0;
|
||||
property[0] = 0;
|
||||
property[1] = 1;
|
||||
property[2] = 0;
|
||||
property[3] = z_screen;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return pixels_;
|
||||
}
|
||||
|
||||
std::pair<bool, double> Rasterizer::inside(const Point2d &p_screen,
|
||||
const Triangle &t) {
|
||||
const auto points = t.get_points<3>();
|
||||
|
||||
const auto plane_normal = t.normal_vector();
|
||||
// spdlog::debug("normal vector: ({},{},{})", plane_normal.x(),
|
||||
// plane_normal.y(),
|
||||
// plane_normal.z());
|
||||
const auto plane_point = points[0];
|
||||
const auto z_screen =
|
||||
plane_point.z() - (plane_normal.x() * (p_screen.x() - plane_point.x()) +
|
||||
|
@ -58,5 +70,6 @@ std::pair<bool, double> Rasterizer::inside(const Point2d &p_screen,
|
|||
const auto r2 = c1.dot(c3);
|
||||
const auto r3 = c2.dot(c3);
|
||||
|
||||
// spdlog::debug("r1: {}, r2: {}, r3: {}", r1, r2, r3);
|
||||
return {r1 > 0 && r2 > 0 && r3 > 0, z_screen};
|
||||
}
|
||||
|
|
|
@ -18,7 +18,8 @@ public:
|
|||
Rasterizer(const int width, const int height);
|
||||
|
||||
public:
|
||||
void rasterize(const Triangle &t);
|
||||
std::vector<std::vector<PixelProperty>>
|
||||
rasterize(const std::vector<Triangle> &primitives);
|
||||
|
||||
private:
|
||||
static std::pair<bool, double> inside(const Point2d &p_screen,
|
||||
|
|
|
@ -21,12 +21,15 @@ BBox Triangle::axis_align_bbox() const {
|
|||
}
|
||||
|
||||
Vector3d Triangle::normal_vector() const {
|
||||
return points_[0].cross(points_[1]).normalized();
|
||||
const auto v1 = points_[1] - points_[0];
|
||||
const auto v2 = points_[2] - points_[1];
|
||||
return v1.cross(v2).normalized();
|
||||
}
|
||||
|
||||
void Triangle::affine_transform(const AffineTransformType &m) {
|
||||
Eigen::Transform<double, 3, Eigen::Affine> affine_matrix(m);
|
||||
for (auto &p : points_) {
|
||||
p = (m * Eigen::Vector4d(p.x(), p.y(), p.z(), 1)).head(3);
|
||||
p = (affine_matrix * Eigen::Vector4d(p.x(), p.y(), p.z(), 1)).head(3);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
class Triangle {
|
||||
public:
|
||||
using AffineTransformType = Eigen::Transform<double, 3, Eigen::Affine>;
|
||||
using AffineTransformType = Eigen::Matrix<double, 3, 3>;
|
||||
using ProjectiveTransformType =
|
||||
Eigen::Transform<double, 3, Eigen::Projective>;
|
||||
|
||||
|
|
Loading…
Reference in New Issue