From a30c41dc46ab021daf04751a1619b8d5357b7b1b Mon Sep 17 00:00:00 2001 From: "tianlei.richard" Date: Wed, 3 Apr 2024 17:50:32 +0800 Subject: [PATCH] add very simple frustum culling. --- src/main.cc | 2 +- src/minus_renderer.cc | 75 +++++++++++++++++++++++++------------------ src/minus_renderer.h | 4 +++ src/triangle.cc | 5 +++ src/triangle.h | 1 + 5 files changed, 54 insertions(+), 33 deletions(-) diff --git a/src/main.cc b/src/main.cc index a06f8a9..41d913d 100644 --- a/src/main.cc +++ b/src/main.cc @@ -15,7 +15,7 @@ #include "minus_renderer.h" int main(int argc, char *argv[]) { - spdlog::set_level(spdlog::level::trace); + spdlog::set_level(spdlog::level::debug); cxxopts::Options options("Minus Renderer", "A minus soft rasterize renderer."); diff --git a/src/minus_renderer.cc b/src/minus_renderer.cc index a65468d..e960375 100644 --- a/src/minus_renderer.cc +++ b/src/minus_renderer.cc @@ -132,6 +132,43 @@ void MinusRenderer::view_transform(const TransformMatrix &mtx) { } } +cv::Vec3b MinusRenderer::fragment_shader(const RasterizerResult &fragment, + const Point3d &position, + const Mesh &mesh) { + const auto &triangle = mesh.get_primitive(fragment.triangle.triangle_index); + const auto &[alpha, beta, gamma] = + calculate_barycentric_coordinate(triangle, position); + + cv::Vec3b res{0, 0, 0}; + if (alpha >= 0. && alpha <= 1. && beta >= 0. && beta <= 1. && gamma >= 0. && + gamma <= 1.) { + std::vector triangle_uv; + std::vector triangle_normal; + for (const auto vertex_index : triangle.get_vertex_index()) { + triangle_uv.push_back(mesh.get_texture_coordinate(vertex_index)); + triangle_normal.push_back(mesh.get_normal_vector(vertex_index)); + } + + Point2d uv{alpha * triangle_uv[0].x() + beta * triangle_uv[1].x() + + gamma * triangle_uv[2].x(), + alpha * triangle_uv[0].y() + beta * triangle_uv[1].y() + + gamma * triangle_uv[2].y()}; + const auto &normal = + -1. * + Point3d(alpha * triangle_normal[0].x() + beta * triangle_normal[1].x() + + gamma * triangle_normal[2].x(), + alpha * triangle_normal[0].y() + beta * triangle_normal[1].y() + + gamma * triangle_normal[2].y(), + alpha * triangle_normal[0].z() + beta * triangle_normal[1].z() + + gamma * triangle_normal[2].z()) + .normalized(); + + const auto &material = mesh.get_material(); + res = material->shade(Vertex{position, normal, uv}, Point3d{}, lamps_); + } + return res; +} + cv::Mat MinusRenderer::render(const int resolution_width, const int resolution_height) { spdlog::trace("Tick once."); @@ -146,7 +183,10 @@ cv::Mat MinusRenderer::render(const int resolution_width, ++mesh_index) { auto primitives = (meshes_[mesh_index]).get_primitives(); for (auto &t : primitives) { - t.set_points(apply_transform(ss_transform, t.get_vertex_position())); + const auto [z_min, z_max] = t.get_depth_range(); + if (z_max >= far_ && z_min <= near_) { + t.set_points(apply_transform(ss_transform, t.get_vertex_position())); + } } rasterizer_->rasterize(mesh_index, primitives); } @@ -166,42 +206,13 @@ cv::Mat MinusRenderer::render(const int resolution_width, if (fragment.triangle.mesh_index >= 0 && fragment.triangle.mesh_index < meshes_.size()) { const auto &mesh = meshes_[fragment.triangle.mesh_index]; - if (fragment.depth > -std::numeric_limits::infinity()) { + if (fragment.depth <= 1. && fragment.depth >= -1.) { const Point3d &position = (inv_ss_transform * (Point3d{x + 0.5, y + 0.5, fragment.depth}.homogeneous())) .hnormalized(); - const auto &triangle = - mesh.get_primitive(fragment.triangle.triangle_index); - const auto &[alpha, beta, gamma] = - calculate_barycentric_coordinate(triangle, position); - - std::vector triangle_uv; - std::vector triangle_normal; - for (const auto vertex_index : triangle.get_vertex_index()) { - triangle_uv.push_back(mesh.get_texture_coordinate(vertex_index)); - triangle_normal.push_back(mesh.get_normal_vector(vertex_index)); - } - - Point2d uv{alpha * triangle_uv[0].x() + beta * triangle_uv[1].x() + - gamma * triangle_uv[2].x(), - alpha * triangle_uv[0].y() + beta * triangle_uv[1].y() + - gamma * triangle_uv[2].y()}; - const auto &normal = -1. * Point3d(alpha * triangle_normal[0].x() + - beta * triangle_normal[1].x() + - gamma * triangle_normal[2].x(), - alpha * triangle_normal[0].y() + - beta * triangle_normal[1].y() + - gamma * triangle_normal[2].y(), - alpha * triangle_normal[0].z() + - beta * triangle_normal[1].z() + - gamma * triangle_normal[2].z()) - .normalized(); - - const auto &material = mesh.get_material(); - pixel_color = - material->shade(Vertex{position, normal, uv}, Point3d{}, lamps_); + pixel_color = fragment_shader(fragment, position, mesh); } } } diff --git a/src/minus_renderer.h b/src/minus_renderer.h index 68762b3..686c7a9 100644 --- a/src/minus_renderer.h +++ b/src/minus_renderer.h @@ -34,6 +34,10 @@ private: construct_transform(const int resolution_width, const int resolution_height) const; +private: + cv::Vec3b fragment_shader(const RasterizerResult &fragment, + const Point3d &position, const Mesh &mesh); + private: float near_; float far_; diff --git a/src/triangle.cc b/src/triangle.cc index ce2a429..38b6e5c 100644 --- a/src/triangle.cc +++ b/src/triangle.cc @@ -45,6 +45,11 @@ BBox Triangle::axis_align_bbox() const { return BBox{x_min, y_min, (x_max - x_min + 1), (y_max - y_min + 1)}; } +std::pair Triangle::get_depth_range() const { + return {std::min({vertices_[0].z(), vertices_[1].z(), vertices_[2].z()}), + std::max({vertices_[0].z(), vertices_[1].z(), vertices_[2].z()})}; +} + Vector3d Triangle::unit_normal_vector() const { return normal_vector().normalized(); } diff --git a/src/triangle.h b/src/triangle.h index 4fc4cbf..05a9234 100644 --- a/src/triangle.h +++ b/src/triangle.h @@ -21,6 +21,7 @@ public: public: BBox axis_align_bbox() const; + std::pair get_depth_range() const; Vector3d normal_vector() const; Vector3d unit_normal_vector() const;