MVP 变换 + 补全依赖

This commit is contained in:
SepComet 2026-03-16 16:38:54 +08:00
parent d550baa11e
commit 4ad6349a59
14 changed files with 223 additions and 79 deletions

96
.gitignore vendored
View File

@ -1,49 +1,47 @@
# Visual Studio user-specific files # Visual Studio user-specific files
*.user *.user
*.suo *.suo
*.userosscache *.userosscache
*.sln.docstates *.sln.docstates
# Visual Studio build artifacts # Visual Studio build artifacts
.vs/ .vs/
[Dd]ebug/ [Dd]ebug/
[Rr]elease/ [Rr]elease/
x64/ [Aa][Rr][Mm]/
x86/ [Aa][Rr][Mm]64/
[Aa][Rr][Mm]/ out/
[Aa][Rr][Mm]64/ bin/
out/ obj/
bin/
obj/ # MSVC intermediate and debug files
*.obj
# MSVC intermediate and debug files *.ipdb
*.obj *.iobj
*.ipdb *.ilk
*.iobj *.pdb
*.ilk *.idb
*.pdb *.tlog
*.idb *.lastbuildstate
*.tlog *.recipe
*.lastbuildstate *.log
*.recipe
*.log # CMake / generated project files
CMakeFiles/
# CMake / generated project files CMakeCache.txt
CMakeFiles/ cmake-build-*/
CMakeCache.txt compile_commands.json
cmake-build-*/
compile_commands.json # Test and coverage output
*.gcno
# Test and coverage output *.gcda
*.gcno *.profraw
*.gcda *.profdata
*.profraw *.coverage
*.profdata
*.coverage # OS / editor noise
.DS_Store
# OS / editor noise Thumbs.db
.DS_Store SDL2-2.32.10-win32-x64.zip
Thumbs.db SDL2-devel-2.32.10-VC.zip
SDL2-2.32.10-win32-x64.zip CPU-Software-Renderer/TODO.md
SDL2-devel-2.32.10-VC.zip
CPU-Software-Renderer/TODO.md

View File

@ -16,7 +16,7 @@ namespace Math
1, 0, 0, translation.x, 1, 0, 0, translation.x,
0, 1, 0, translation.y, 0, 1, 0, translation.y,
0, 0, 1, translation.z, 0, 0, 1, translation.z,
0, 0, 0, 0 0, 0, 0, 1
); );
} }
@ -98,4 +98,4 @@ namespace Math
return vec1.cross(vec2); return vec1.cross(vec2);
} }
}; };
} }

View File

@ -23,16 +23,7 @@ namespace Scene
); );
} }
Math::Matrix4x4 Camera::get_orthographic_projection_matrix(float aspectRatio) const Math::Matrix4x4 Camera::get_orthographic_projection_matrix(float width, float height) const
{
using namespace Math;
return Matrix4x4(
);
}
Math::Matrix4x4 Camera::get_perspective_projection_matrix(float width, float height) const
{ {
using namespace Math; using namespace Math;
@ -42,13 +33,27 @@ namespace Scene
const float t = height * 0.5f; const float t = height * 0.5f;
const float n = nearPlane; const float n = nearPlane;
const float f = farPlane; const float f = farPlane;
const float length = n - f;
return Matrix4x4( return Matrix4x4(
2.0f / width, 0, 0, -(r + l) / (r - l) + 1, 2.0f / (r - l), 0, 0, -(r + l) / (r - l),
0, 2.0f / height, 0, -(t + b) / (t - b) + 1, 0, 2.0f / (t - b), 0, -(t + b) / (t - b),
0, 0, 2.0f / length, -(n + f) / (n - f) + 1, 0, 0, 2.0f / (n - f), -(n + f) / (f - n),
0, 0, 0, 1 0, 0, 0, 1
); );
} }
Math::Matrix4x4 Camera::get_perspective_projection_matrix(float aspectRatio) const
{
using namespace Math;
const float n = nearPlane;
const float f = farPlane;
return Matrix4x4(
1.0f / (aspectRatio * std::tan(verticalFovRadians / 2)), 0, 0, 0,
0, 1.0f / std::tan(verticalFovRadians / 2), 0, 0,
0, 0, -(f + n) / (f - n), -(2 * f * n) / (f - n),
0, 0, -1, 0
);
}
} }

View File

@ -38,8 +38,8 @@ namespace Scene
Math::Matrix4x4 get_view_matrix() const; Math::Matrix4x4 get_view_matrix() const;
Math::Matrix4x4 get_orthographic_projection_matrix(float aspectRatio) const; Math::Matrix4x4 get_orthographic_projection_matrix(float width, float height) const;
Math::Matrix4x4 get_perspective_projection_matrix(float width, float height) const; Math::Matrix4x4 get_perspective_projection_matrix(float aspectRatio) const;
}; };
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,13 +1,20 @@
#include <iostream> #include <iostream>
#include <array>
#include <cmath>
#include <SDL.h> #include <SDL.h>
#include "SDL_video.h" #include "SDL_video.h"
#include "SDL_render.h" #include "SDL_render.h"
#include <cstdint> #include <cstdint>
#include "SDL_error.h" #include "SDL_error.h"
#include "Vector2.h" #include "Vector2.h"
#include "Vector3.h"
#include "Vector4.h"
#include "Matrix4x4.h"
#include "MathUtil.h"
#include "Color.h" #include "Color.h"
#include "FrameBuffer.h" #include "FrameBuffer.h"
#include "Rasterizer.h" #include "Rasterizer.h"
#include "Camera.h"
#include "SDL_events.h" #include "SDL_events.h"
#include "SDL_keycode.h" #include "SDL_keycode.h"
@ -106,6 +113,64 @@ static bool EnsureTexture()
return true; return true;
} }
struct ProjectedVertex
{
Math::Vector2Int screen;
bool visible = false;
};
struct CubeFace
{
std::array<int, 4> vertices;
std::array<int, 4> edges;
};
static ProjectedVertex ProjectToScreen(
const Math::Vector3& vertex,
const Math::Matrix4x4& mvp,
const int32_t screenWidth,
const int32_t screenHeight)
{
using namespace Math;
const Vector4 clip = mvp * Vector4::Point(vertex);
if (std::abs(clip.w) < 1e-5f)
{
return {};
}
const float invW = 1.0f / clip.w;
const float ndcX = clip.x * invW;
const float ndcY = clip.y * invW;
const float ndcZ = clip.z * invW;
if (ndcX < -1.0f || ndcX > 1.0f || ndcY < -1.0f || ndcY > 1.0f || ndcZ < -1.0f || ndcZ > 1.0f)
{
return {};
}
const float screenX = (ndcX * 0.5f + 0.5f) * static_cast<float>(screenWidth - 1);
const float screenY = (1.0f - (ndcY * 0.5f + 0.5f)) * static_cast<float>(screenHeight - 1);
return { Vector2(screenX, screenY).to_vector2Int(), true };
}
static bool IsFaceVisible(const CubeFace& face, const std::array<Math::Vector3, 8>& viewSpaceVertices)
{
using namespace Math;
const Vector3& v0 = viewSpaceVertices[face.vertices[0]];
const Vector3& v1 = viewSpaceVertices[face.vertices[1]];
const Vector3& v2 = viewSpaceVertices[face.vertices[2]];
const Vector3 faceNormal = (v1 - v0).cross(v2 - v0);
const Vector3 faceCenter =
(viewSpaceVertices[face.vertices[0]] +
viewSpaceVertices[face.vertices[1]] +
viewSpaceVertices[face.vertices[2]] +
viewSpaceVertices[face.vertices[3]]) / 4.0f;
return faceNormal.dot(faceCenter) < 0.0f;
}
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
@ -114,21 +179,47 @@ int main(int argc, char* argv[])
if (!EnsureSDLWindow()) return -1; if (!EnsureSDLWindow()) return -1;
if (!EnsureRenderer()) return -1; if (!EnsureRenderer()) return -1;
if (!EnsureTexture()) return -1; if (!EnsureTexture()) return -1;
Core::FrameBuffer frameBuffer(width, height); Core::FrameBuffer frameBuffer(width, height);
Rasterizer::Rasterizer rasterizer(frameBuffer); Rasterizer::Rasterizer rasterizer(frameBuffer);
Math::Vector2Int v0(100, 100); Scene::Camera camera;
Math::Vector2Int v1(300, 100); camera.set_position(Math::Vector3(0.0f, 0.0f, 3.0f));
Math::Vector2Int v2(300, 400); camera.set_target(Math::Vector3(0.0f, 0.0f, 0.0f));
RenderData::Color color0(255, 0, 0, 255); camera.set_up(Math::Vector3(0.0f, 1.0f, 0.0f));
RenderData::Color color1(0, 255, 0, 255); camera.set_near_plane(0.1f);
RenderData::Color color2(0, 0, 255, 255); camera.set_far_plane(100.0f);
rasterizer.DrawLine(v0, v1, color0);
rasterizer.DrawLine(v1, v2, color1); const std::array<Math::Vector3, 8> cubeVertices = {
rasterizer.DrawLine(v2, v0, color2); Math::Vector3(-0.5f, -0.5f, -0.5f),
Math::Vector3(0.5f, -0.5f, -0.5f),
Math::Vector3(0.5f, 0.5f, -0.5f),
Math::Vector3(-0.5f, 0.5f, -0.5f),
Math::Vector3(-0.5f, -0.5f, 0.5f),
Math::Vector3(0.5f, -0.5f, 0.5f),
Math::Vector3(0.5f, 0.5f, 0.5f),
Math::Vector3(-0.5f, 0.5f, 0.5f)
};
const std::array<std::pair<int, int>, 12> cubeEdges = {
std::pair<int, int>(0, 1), std::pair<int, int>(1, 2), std::pair<int, int>(2, 3), std::pair<int, int>(3, 0),
std::pair<int, int>(4, 5), std::pair<int, int>(5, 6), std::pair<int, int>(6, 7), std::pair<int, int>(7, 4),
std::pair<int, int>(0, 4), std::pair<int, int>(1, 5), std::pair<int, int>(2, 6), std::pair<int, int>(3, 7)
};
const std::array<CubeFace, 6> cubeFaces = {
CubeFace{ { 0, 3, 2, 1 }, { 0, 1, 2, 3 } },
CubeFace{ { 4, 5, 6, 7 }, { 4, 5, 6, 7 } },
CubeFace{ { 0, 4, 7, 3 }, { 8, 7, 11, 3 } },
CubeFace{ { 1, 2, 6, 5 }, { 1, 10, 5, 9 } },
CubeFace{ { 0, 1, 5, 4 }, { 0, 9, 4, 8 } },
CubeFace{ { 3, 7, 6, 2 }, { 11, 6, 10, 2 } }
};
const RenderData::Color clearColor(18, 18, 24, 255);
const RenderData::Color cubeColor(240, 240, 240, 255);
const float aspectRatio = static_cast<float>(width) / static_cast<float>(height);
bool isRuning = true; bool isRuning = true;
while (isRuning) while (isRuning)
@ -147,6 +238,57 @@ int main(int argc, char* argv[])
} }
} }
frameBuffer.clear(clearColor);
const float timeSeconds = static_cast<float>(SDL_GetTicks()) * 0.001f;
const Math::Matrix4x4 model =
Math::MathUtil::get_rotation_matrix_y(timeSeconds) *
Math::MathUtil::get_rotation_matrix_x(timeSeconds * 0.6f);
const Math::Matrix4x4 view = camera.get_view_matrix();
const Math::Matrix4x4 modelView = view * model;
const Math::Matrix4x4 projection = camera.get_perspective_projection_matrix(aspectRatio);
const Math::Matrix4x4 mvp = projection * modelView;
std::array<Math::Vector3, 8> viewSpaceVertices;
std::array<ProjectedVertex, 8> projectedVertices;
for (size_t i = 0; i < cubeVertices.size(); ++i)
{
viewSpaceVertices[i] = (modelView * Math::Vector4::Point(cubeVertices[i])).to_vector3();
projectedVertices[i] = ProjectToScreen(cubeVertices[i], mvp, width, height);
}
std::array<bool, 12> visibleEdges = {};
for (const CubeFace& face : cubeFaces)
{
if (!IsFaceVisible(face, viewSpaceVertices))
{
continue;
}
for (const int edgeIndex : face.edges)
{
visibleEdges[edgeIndex] = true;
}
}
for (size_t edgeIndex = 0; edgeIndex < cubeEdges.size(); ++edgeIndex)
{
if (!visibleEdges[edgeIndex])
{
continue;
}
const auto& edge = cubeEdges[edgeIndex];
const ProjectedVertex& start = projectedVertices[edge.first];
const ProjectedVertex& end = projectedVertices[edge.second];
if (!start.visible || !end.visible)
{
continue;
}
rasterizer.DrawLine(start.screen, end.screen, cubeColor);
}
SDL_UpdateTexture(texture, nullptr, frameBuffer.get_buffer(), width * sizeof(uint32_t)); SDL_UpdateTexture(texture, nullptr, frameBuffer.get_buffer(), width * sizeof(uint32_t));
SDL_RenderClear(renderer); SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, nullptr, nullptr); SDL_RenderCopy(renderer, texture, nullptr, nullptr);
@ -156,4 +298,3 @@ int main(int argc, char* argv[])
ClearSDLResources(); ClearSDLResources();
return 0; return 0;
} }