feat(渲染): 重构渲染系统并添加相机支持

- 在Batch中添加纹理采样器uniform设置
- 重构Sprite渲染逻辑,使用Renderer的drawSprite方法
- 添加Camera类并集成到Application和Renderer中
- 支持Y轴翻转的投影矩阵以适应2D游戏坐标系
- 改进颜色处理,移除不必要的归一化计算
- 添加渲染错误处理和日志输出
This commit is contained in:
2026-03-17 18:40:19 +08:00
parent f0298504ac
commit 57a96a0cc5
7 changed files with 56 additions and 28 deletions

View File

@@ -1,6 +1,7 @@
#pragma once
#include <frostbite2D/core/window.h>
#include <frostbite2D/graphics/camera.h>
#include <frostbite2D/types/type_alias.h>
#include <string>
@@ -176,6 +177,7 @@ private:
Window* window_ = nullptr;
class Renderer* renderer_ = nullptr;
Camera* camera_ = nullptr;
AppConfig config_;
bool initialized_ = false;

View File

@@ -55,19 +55,17 @@ void Sprite::Render() {
}
Renderer& renderer = Renderer::get();
Batch& batch = renderer.getBatch();
Shader* shader = getActiveShader();
if (!shader || !shader->isValid()) {
RenderChildren();
return;
Vec2 pos = GetPosition();
Vec2 size = GetSize();
if (size.x == 0 || size.y == 0) {
size = Vec2((float)texture_->getWidth(), (float)texture_->getHeight());
}
updateTransform();
Quad quad = createQuad();
batch.submitQuad(quad, transform_, texture_, shader, blendMode_);
// 直接使用 Renderer 的 drawSprite 函数,确保和直接渲染一致
renderer.drawSprite(pos, Rect(0, 0, (float)texture_->getWidth(), (float)texture_->getHeight()),
Vec2((float)texture_->getWidth(), (float)texture_->getHeight()),
texture_, color_);
RenderChildren();
}

View File

@@ -3,6 +3,7 @@
#include <cstdio>
#include <frostbite2D/core/application.h>
#include <frostbite2D/graphics/renderer.h>
#include <frostbite2D/graphics/camera.h>
#include <frostbite2D/platform/switch.h>
#include <frostbite2D/types/type_math.h>
#include <frostbite2D/utils/asset.h>
@@ -69,6 +70,12 @@ void Application::shutdown() {
window_ = nullptr;
}
// 清理相机
if (camera_) {
delete camera_;
camera_ = nullptr;
}
// 平台相关清理
#ifdef __SWITCH__
switchShutdown();
@@ -110,6 +117,12 @@ bool Application::initCoreModules() {
renderer_->setViewport(0, 0, config_.windowConfig.width,
config_.windowConfig.height);
// 创建并设置相机
camera_ = new Camera();
camera_->setViewport(config_.windowConfig.width, config_.windowConfig.height);
camera_->setFlipY(true); // 启用 Y 轴翻转,(0,0) 在左上角
renderer_->setCamera(camera_);
return true;
}
@@ -198,11 +211,10 @@ void Application::update() {
void Application::render() {
Renderer& renderer = Renderer::get();
Batch& batch = renderer.getBatch();
batch.begin();
renderer.beginFrame();
SceneManager::get().Render();
batch.end();
renderer.endFrame();
if (window_) {
window_->swap();

View File

@@ -152,9 +152,11 @@ void Batch::flushCurrentBatch() {
// 绑定着色器和纹理
if (currentBatch_.shader) {
currentBatch_.shader->use();
// 设置纹理采样器 uniform 变量
currentBatch_.shader->setTexture("u_texture", 0);
}
if (currentBatch_.texture) {
currentBatch_.texture->bind();
currentBatch_.texture->bind(0);
}
glBindBuffer(GL_ARRAY_BUFFER, vbo_);

View File

@@ -37,8 +37,19 @@ glm::mat4 Camera::getViewMatrix() const {
glm::mat4 Camera::getProjectionMatrix() const {
float left = 0.0f;
float right = static_cast<float>(viewportWidth_);
float bottom = static_cast<float>(viewportHeight_);
float top = 0.0f;
float bottom, top;
if (flipY_) {
// Y 轴向下:(0,0) 在左上角2D 游戏常用)
// glm::ortho(left, right, bottom, top, ...)
// 这里 bottom 是屏幕底部值大top 是屏幕顶部(值小)
bottom = static_cast<float>(viewportHeight_);
top = 0.0f;
} else {
// Y 轴向上:(0,0) 在左下角OpenGL 默认)
bottom = 0.0f;
top = static_cast<float>(viewportHeight_);
}
return glm::ortho(left, right, bottom, top, -1.0f, 1.0f);
}

View File

@@ -175,10 +175,7 @@ void Renderer::drawQuad(const Vec2& pos, const Size& size, Ptr<Texture> texture)
void Renderer::drawQuad(const Rect& rect, const Color& color) {
drawQuad(Vec2(rect.left(), rect.top()),
Size(rect.width(), rect.height()),
static_cast<float>(color.r) / 255.0f,
static_cast<float>(color.g) / 255.0f,
static_cast<float>(color.b) / 255.0f,
static_cast<float>(color.a) / 255.0f);
color.r, color.g, color.b, color.a);
}
void Renderer::drawSprite(const Vec2& pos, const Size& size, Ptr<Texture> texture) {
@@ -189,10 +186,7 @@ void Renderer::drawSprite(const Vec2& pos, const Rect& srcRect, const Vec2& texS
Ptr<Texture> texture, const Color& color) {
Rect destRect(pos.x, pos.y, srcRect.width(), srcRect.height());
Quad quad = Quad::createTextured(destRect, srcRect, texSize,
static_cast<float>(color.r) / 255.0f,
static_cast<float>(color.g) / 255.0f,
static_cast<float>(color.b) / 255.0f,
static_cast<float>(color.a) / 255.0f);
color.r, color.g, color.b, color.a);
Transform2D transform = Transform2D::identity();
auto* shader = shaderManager_.getShader("sprite");

View File

@@ -32,9 +32,18 @@ int main(int argc, char **argv) {
auto menuScene = MakePtr<Scene>();
SceneManager::get().PushScene(menuScene);
// 先测试彩色四边形,排除纹理问题
SDL_Log("Testing colored quad...");
// 尝试加载精灵
auto sprite = Sprite::createFromFile("assets\\player.png");
if (sprite) {
sprite->SetPosition(100, 100);
menuScene->AddActor(sprite);
SDL_Log("Sprite created and added to scene");
} else {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create sprite from file!");
}
app.run();