SceneRenderer (WIP).

This commit is contained in:
Patrick 2024-09-20 17:56:33 +02:00
parent 122190e44b
commit c44f87ad00
10 changed files with 580 additions and 136 deletions

View File

@ -3,10 +3,9 @@
#include <glm/mat4x4.hpp> #include <glm/mat4x4.hpp>
#include <glm/vec2.hpp> #include <glm/vec2.hpp>
#include <glm/vec3.hpp>
#include <glm/vec4.hpp> #include <glm/vec4.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "../scene/mesh.hpp"
#include "../sdlpp/keyboard.hpp" #include "../sdlpp/keyboard.hpp"
#include "../util/bitmap.hpp" #include "../util/bitmap.hpp"
#include "../util/mesh.hpp" #include "../util/mesh.hpp"
@ -18,12 +17,6 @@ namespace
inline constexpr float Y_POS_MIN = -10.f; inline constexpr float Y_POS_MIN = -10.f;
inline constexpr float Y_POS_MAX = 10.f; inline constexpr float Y_POS_MAX = 10.f;
inline constexpr Uint16 AXIS_DEADZONE = 5000; inline constexpr Uint16 AXIS_DEADZONE = 5000;
struct VertexShaderParameters
{
glm::mat4 worldToView;
glm::mat4 viewToClip;
};
} }
void ThreeDSceneApp::init(const AppInitArgs& args) void ThreeDSceneApp::init(const AppInitArgs& args)
@ -38,30 +31,11 @@ void ThreeDSceneApp::init(const AppInitArgs& args)
.height = 720 .height = 720
}); });
// create graphics pipeline // init UI renderer
createMeshPipeline();
// create UI pipeline
mUIRenderer.init(*this); mUIRenderer.init(*this);
// load the mesh // init scene renderer
const Mesh mesh = loadMesh(mFileSystem.getPath("meshes/cube.obj")); mSceneRenderer.init(*this);
mNumVertices = static_cast<Uint32>(mesh.vertices.size());
// create vertex buffer
mVertexBuffer.create(mDevice, {
.usage = {.vertex = true},
.size = static_cast<Uint32>(mesh.vertices.size() * sizeof(Vertex))
});
uploadVertexData(mVertexBuffer, std::span(mesh.vertices));
// create texture and sampler
sdlpp::GPUTextureCreateArgs textureArgs = {
.format = sdlpp::GPUTextureFormat::R8G8B8A8_UNORM_SRGB,
.usage = {.sampler = true}
};
mTexture = loadTexture("bitmaps/cube.png", textureArgs);
mSampler.create(mDevice, {});
// open gamepad // open gamepad
const std::vector<SDL_JoystickID> gamepads = sdlpp::getGamepads(); const std::vector<SDL_JoystickID> gamepads = sdlpp::getGamepads();
@ -84,6 +58,11 @@ void ThreeDSceneApp::init(const AppInitArgs& args)
.posX = 100, .posX = 100,
.posY = 500 .posY = 500
}); });
// init the scene
mScene.init({.renderer = &mSceneRenderer});
mScene.getRootNode().emplaceChild<MeshNode>({.mesh = "meshes/cube.obj", .texture = "bitmaps/cube.png"});
mButton->clicked.connect([&]() mButton->clicked.connect([&]()
{ {
mButton->setText("Thanks!"); mButton->setText("Thanks!");
@ -116,39 +95,14 @@ void ThreeDSceneApp::update(const AppUpdateArgs& args)
mLastSwapchainHeight = swapchainHeight; mLastSwapchainHeight = swapchainHeight;
} }
// render the 3D "scene" // render the scene
const VertexShaderParameters vertexShaderParameters = { mSceneRenderer.render({
.worldToView = glm::lookAt(glm::vec3(2.f, mYPos, 2.f), glm::vec3(0.f, 0.f, 0.f), glm::vec3(0.f, 1.f, 0.f)) .cmdBuffer = &cmdBuffer,
* glm::rotate(glm::mat4(1.f), glm::radians(mRotation), glm::vec3(0.f, 1.f, 0.f)), .targetTexture = &swapchainTexture,
.viewToClip = glm::perspectiveFov( .depthTexture = &mDepthBuffer,
/* fov = */ glm::radians(90.f), .targetTextureWidth = swapchainWidth,
/* width = */ static_cast<float>(swapchainWidth), .targetTextureHeight = swapchainHeight
/* height = */ static_cast<float>(swapchainHeight),
/* zNear = */ 0.1f,
/* zFar = */ 100.f
)
};
std::array colorTargets = {sdlpp::GPUColorTargetInfo{
.texture = swapchainTexture,
.clearColor = {.r = 0.f, .g = 0.f, .b = 0.f, .a = 1.f},
.loadOp = sdlpp::GPULoadOp::CLEAR,
}};
sdlpp::GPURenderPass renderPass = cmdBuffer.beginRenderPass({
.colorTargetInfos = colorTargets,
.depthStencilTargetInfo = sdlpp::GPUDepthStencilTargetInfo{
.texture = mDepthBuffer,
.loadOp = sdlpp::GPULoadOp::CLEAR
}
}); });
static const glm::vec4 WHITE(1.f, 1.f, 1.f, 1.f);
cmdBuffer.pushFragmentUniformData(0, std::span(&WHITE, 1));
cmdBuffer.pushVertexUniformData(0, std::span(&vertexShaderParameters, 1));
renderPass.bindFragmentSampler({.texture = mTexture, .sampler = mSampler});
renderPass.bindGraphicsPipeline(mMeshPipeline);
renderPass.bindVertexBuffer({.buffer = mVertexBuffer});
renderPass.drawPrimitives({.numVertices = mNumVertices});
renderPass.end();
// render the "UI" // render the "UI"
mUIRenderer.render({ mUIRenderer.render({
@ -192,72 +146,6 @@ void ThreeDSceneApp::handleMouseButtonEvent(const sdlpp::MouseButtonEvent& event
mWidgetTree.notifyMouseButton(event); mWidgetTree.notifyMouseButton(event);
} }
void ThreeDSceneApp::createMeshPipeline()
{
// create shaders
const sdlpp::GPUShader vertexShader = loadShader("shaders/glsl/textured_3dtriangles_from_buffer.vert.spv", {
.format = sdlpp::GPUShaderFormat::SPIRV,
.stage = sdlpp::GPUShaderStage::VERTEX,
.numUniformBuffers = 1
});
const sdlpp::GPUShader fragmentShader = loadShader("shaders/glsl/color_from_texture.frag.spv", {
.format = sdlpp::GPUShaderFormat::SPIRV,
.stage = sdlpp::GPUShaderStage::FRAGMENT,
.numSamplers = 1,
.numUniformBuffers = 1
});
std::array colorTargetsDescs = {
sdlpp::GPUColorTargetDescription{
.format = mDevice.getSwapchainTextureFormat(mWindow),
.blendState = {
.enableBlend = true,
.srcColorBlendfactor = sdlpp::GPUBlendFactor::SRC_ALPHA,
.dstColorBlendfactor = sdlpp::GPUBlendFactor::ONE_MINUS_SRC_ALPHA,
.colorBlendOp = sdlpp::GPUBlendOp::ADD,
.srcAlphaBlendfactor = sdlpp::GPUBlendFactor::ONE,
.dstAlphaBlendfactor = sdlpp::GPUBlendFactor::ZERO,
.alphaBlendOp = sdlpp::GPUBlendOp::ADD
}
}
};
std::array vertexBindings = {
sdlpp::GPUVertexBinding{
.index = 0,
.pitch = sizeof(Vertex)
}
};
std::array vertexAttributes = {
sdlpp::GPUVertexAttribute{
.location = 0,
.bindingIndex = 0,
.format = sdlpp::GPUVertexElementFormat::FLOAT3,
.offset = offsetof(Vertex, pos)
},
sdlpp::GPUVertexAttribute{
.location = 1,
.bindingIndex = 0,
.format = sdlpp::GPUVertexElementFormat::FLOAT2,
.offset = offsetof(Vertex, texcoord)
}
};
mMeshPipeline.create(mDevice, {
.vertexShader = vertexShader,
.fragmentShader = fragmentShader,
.vertexInputState = {
.vertexBindings = vertexBindings,
.vertexAttributes = vertexAttributes
},
.rasterizerState = {
.cullMode = sdlpp::GPUCullMode::BACK
},
.targetInfo = {
.colorTargetDescriptions = colorTargetsDescs,
.depthStencilFormat = sdlpp::GPUTextureFormat::D16_UNORM
}
});
}
void ThreeDSceneApp::processInput(const AppUpdateArgs& args) void ThreeDSceneApp::processInput(const AppUpdateArgs& args)
{ {
const std::span<const SDL_bool> keystates = sdlpp::getKeyboardState(); const std::span<const SDL_bool> keystates = sdlpp::getKeyboardState();

View File

@ -9,6 +9,8 @@
#include "../gui/label.hpp" #include "../gui/label.hpp"
#include "../gui/widget.hpp" #include "../gui/widget.hpp"
#include "../gui/ui_renderer.hpp" #include "../gui/ui_renderer.hpp"
#include "../scene/scene.hpp"
#include "../scene/scene_renderer.hpp"
#include "../sdlpp/gamepad.hpp" #include "../sdlpp/gamepad.hpp"
namespace sdl_gpu_test namespace sdl_gpu_test
@ -16,20 +18,18 @@ namespace sdl_gpu_test
class ThreeDSceneApp : public Application class ThreeDSceneApp : public Application
{ {
private: private:
sdlpp::GPUBuffer mVertexBuffer;
sdlpp::GPUTexture mDepthBuffer; sdlpp::GPUTexture mDepthBuffer;
sdlpp::GPUGraphicsPipeline mMeshPipeline;
sdlpp::GPUTexture mTexture;
sdlpp::GPUSampler mSampler;
UIRenderer mUIRenderer; UIRenderer mUIRenderer;
WidgetTree mWidgetTree; WidgetTree mWidgetTree;
Label* mLabel; SceneRenderer mSceneRenderer;
Button* mButton; Scene mScene;
Label* mLabel = nullptr;
Button* mButton = nullptr;
sdlpp::Gamepad mGamepad; sdlpp::Gamepad mGamepad;
Uint32 mNumVertices = 0;
Uint32 mLastSwapchainWidth = 1280; Uint32 mLastSwapchainWidth = 1280;
Uint32 mLastSwapchainHeight = 720; Uint32 mLastSwapchainHeight = 720;
float mRotation = 0.f; float mRotation = 0.f;
@ -41,7 +41,6 @@ public:
void handleMouseMotionEvent(const sdlpp::MouseMotionEvent& event) override; void handleMouseMotionEvent(const sdlpp::MouseMotionEvent& event) override;
void handleMouseButtonEvent(const sdlpp::MouseButtonEvent&) override; void handleMouseButtonEvent(const sdlpp::MouseButtonEvent&) override;
private: private:
void createMeshPipeline();
void processInput(const AppUpdateArgs& args); void processInput(const AppUpdateArgs& args);
}; };
} // namespace sdl_gpu_test } // namespace sdl_gpu_test

View File

@ -9,6 +9,9 @@ src_files = Split("""
gui/label.cpp gui/label.cpp
gui/ui_renderer.cpp gui/ui_renderer.cpp
gui/widget.cpp gui/widget.cpp
scene/mesh.cpp
scene/scene.cpp
scene/scene_renderer.cpp
util/bitmap.cpp util/bitmap.cpp
util/font_map.cpp util/font_map.cpp
util/mesh.cpp util/mesh.cpp

View File

@ -0,0 +1,62 @@
#include "./mesh.hpp"
namespace sdl_gpu_test
{
MeshNode::MeshNode(MeshNodeCreateArgs args) : mMeshPath(std::move(args.mesh)), mTexturePath(std::move(args.texture))
{
}
void MeshNode::setMesh(std::string resourcePath)
{
mMeshPath = std::move(resourcePath);
if (mScene != nullptr)
{
updateMesh();
}
}
void MeshNode::setTexture(std::string resourcePath)
{
mTexturePath = std::move(resourcePath);
if (mScene != nullptr)
{
updateTexture();
}
}
void MeshNode::handleEnteredScene()
{
SceneNode::handleEnteredScene();
updateMesh();
updateTexture();
}
void MeshNode::updateMesh()
{
if (mMeshPath.empty())
{
mMesh = nullptr;
}
else
{
mMesh = mScene->getRenderer().getMesh(mMeshPath);
}
}
void MeshNode::updateTexture()
{
if (mTexturePath.empty())
{
mTexture = nullptr;
}
else
{
mTexture = mScene->getRenderer().getTexture(mTexturePath);
}
}
}

View File

@ -0,0 +1,41 @@
#pragma once
#if !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SCENE_MESH_HPP_INCLUDED)
#define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SCENE_MESH_HPP_INCLUDED 1
#include "./scene.hpp"
#include "../util/mesh.hpp"
namespace sdl_gpu_test
{
struct MeshNodeCreateArgs
{
std::string mesh;
std::string texture;
};
class MeshNode : public SceneNode
{
public:
using create_args_t = MeshNodeCreateArgs;
private:
std::shared_ptr<SceneMesh> mMesh;
std::shared_ptr<SceneTexture> mTexture;
std::string mMeshPath;
std::string mTexturePath;
public:
MeshNode(MeshNodeCreateArgs args);
void setMesh(std::string resourcePath);
void setTexture(std::string resourcePath);
void handleEnteredScene() override;
private:
void updateMesh();
void updateTexture();
};
} // namespace sdl_gpu_test
#endif // !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SCENE_MESH_HPP_INCLUDED)

View File

@ -0,0 +1,42 @@
#include "./scene.hpp"
namespace sdl_gpu_test
{
void SceneNode::handleEnteredScene()
{
for (scene_node_ptr_t& child : mChildren)
{
child->enterScene(mScene, this);
}
}
SceneNode* SceneNode::addChild(scene_node_ptr_t&& node)
{
mChildren.push_back(std::move(node));
if (mScene != nullptr)
{
mChildren.back()->enterScene(mScene, this);
}
return mChildren.back().get();
}
void SceneNode::enterScene(Scene* scene, SceneNode* parent)
{
MIJIN_ASSERT(mScene == nullptr && mParent == nullptr, "SceneNode is already in a scene.");
MIJIN_ASSERT_FATAL(scene != nullptr, "Missing parameter: scene.");
mScene = scene;
mParent = parent;
handleEnteredScene();
}
void Scene::init(const SceneInitArgs& args)
{
MIJIN_ASSERT_FATAL(args.renderer != nullptr, "Missing parameter: renderer.");
mRenderer = args.renderer;
}
}

View File

@ -0,0 +1,71 @@
#pragma once
#if !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SCENE_SCENE_HPP_INCLUDED)
#define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SCENE_SCENE_HPP_INCLUDED 1
#include <memory>
#include <vector>
#include "./scene_renderer.hpp"
#include "./transform3d.hpp"
namespace sdl_gpu_test
{
using scene_node_ptr_t = std::unique_ptr<class SceneNode>;
struct SceneNodeCreateArgs
{
};
class SceneNode
{
public:
using create_args_t = SceneNodeCreateArgs;
protected:
std::vector<scene_node_ptr_t> mChildren;
SceneNode* mParent = nullptr;
class Scene* mScene = nullptr;
Transform3D mTransform;
public:
virtual ~SceneNode() noexcept = default;
virtual void handleEnteredScene();
SceneNode* addChild(scene_node_ptr_t&& node);
template<typename TNode>
TNode* emplaceChild(typename TNode::create_args_t args)
{
return static_cast<TNode*>(addChild(std::make_unique<TNode>(args)));
}
private:
void enterScene(Scene* scene, SceneNode* parent);
};
struct SceneInitArgs
{
SceneRenderer* renderer;
};
class Scene
{
private:
SceneNode mRootNode;
SceneRenderer* mRenderer = nullptr;
public:
void init(const SceneInitArgs& args);
[[nodiscard]]
SceneNode& getRootNode() noexcept { return mRootNode; }
[[nodiscard]]
const SceneNode& getRootNode() const noexcept { return mRootNode; }
[[nodiscard]]
SceneRenderer& getRenderer() const noexcept { return *mRenderer; }
};
} // namespace sdl_gpu_test
#endif // !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SCENE_SCENE_HPP_INCLUDED)

View File

@ -0,0 +1,184 @@
#include "./scene_renderer.hpp"
#include <glm/mat4x4.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "./mesh.hpp"
#include "../util/bitmap.hpp"
#include "../util/mesh.hpp"
namespace sdl_gpu_test
{
namespace
{
struct VertexShaderParameters
{
glm::mat4 worldToView;
glm::mat4 viewToClip;
};
}
void SceneRenderer::init(Application& application)
{
mApplication = &application;
mSampler.create(mApplication->getDevice(), {});
}
std::shared_ptr<SceneMesh> SceneRenderer::getMesh(const std::string& resourcePath)
{
auto it = mCachedMeshes.find(resourcePath);
if (it != mCachedMeshes.end())
{
if (std::shared_ptr<SceneMesh> result = it->second.lock(); result != nullptr)
{
return result;
}
mCachedMeshes.erase(it);
}
const Mesh mesh = loadMesh(mApplication->getFileSystem().getPath(resourcePath));
std::shared_ptr<SceneMesh> result = std::make_shared<SceneMesh>();
result->numVertices = mesh.vertices.size();
result->vertexBuffer.create(mApplication->getDevice(), {
.usage = {.vertex = true},
.size = static_cast<Uint32>(result->numVertices * sizeof(Vertex))
});
mApplication->uploadVertexData(result->vertexBuffer, std::span(mesh.vertices));
mCachedMeshes.emplace(resourcePath, result);
return result;
}
std::shared_ptr<SceneTexture> SceneRenderer::getTexture(const std::string& resourcePath)
{
auto it = mCachedTextures.find(resourcePath);
if (it != mCachedTextures.end())
{
if (std::shared_ptr<SceneTexture> result = it->second.lock(); result != nullptr)
{
return result;
}
mCachedTextures.erase(it);
}
const Bitmap bitmap = loadBitmap(mApplication->getFileSystem().getPath(resourcePath));
std::shared_ptr<SceneTexture> result = std::make_shared<SceneTexture>();
result->texture.create(mApplication->getDevice(), {
.format = sdlpp::GPUTextureFormat::R8G8B8A8_UNORM_SRGB,
.usage = {.sampler = true}
});
mApplication->uploadTextureData(result->texture, bitmap);
mCachedTextures.emplace(resourcePath, result);
return result;
}
void SceneRenderer::render(const SceneRendererRenderArgs& args)
{
// just temporary
const float mYPos = 1.5f;
const float mRotation = 0.f;
VertexShaderParameters vertexShaderParameters = {
.worldToView = glm::lookAt(glm::vec3(2.f, mYPos, 2.f), glm::vec3(0.f, 0.f, 0.f), glm::vec3(0.f, 1.f, 0.f))
* glm::rotate(glm::mat4(1.f), glm::radians(mRotation), glm::vec3(0.f, 1.f, 0.f)),
.viewToClip = glm::perspectiveFov(
/* fov = */ glm::radians(90.f),
/* width = */ static_cast<float>(args.targetTextureWidth),
/* height = */ static_cast<float>(args.targetTextureHeight),
/* zNear = */ 0.1f,
/* zFar = */ 100.f
)
};
std::array colorTargets = {sdlpp::GPUColorTargetInfo{
.texture = *args.targetTexture,
.clearColor = {.r = 0.f, .g = 0.f, .b = 0.f, .a = 1.f},
.loadOp = sdlpp::GPULoadOp::CLEAR,
}};
sdlpp::GPURenderPass renderPass = args.cmdBuffer->beginRenderPass({
.colorTargetInfos = colorTargets,
.depthStencilTargetInfo = sdlpp::GPUDepthStencilTargetInfo{
.texture = *args.depthTexture,
.loadOp = sdlpp::GPULoadOp::CLEAR
}
});
renderPass.bindGraphicsPipeline(mPipeline);
static const glm::vec4 WHITE(1.f, 1.f, 1.f, 1.f);
for (const RenderListEntry& entry : mRenderList)
{
args.cmdBuffer->pushFragmentUniformData(0, std::span(&WHITE, 1));
args.cmdBuffer->pushVertexUniformData(0, std::span<const VertexShaderParameters>(&vertexShaderParameters, 1));
renderPass.bindFragmentSampler({.texture = entry.texture->texture, .sampler = mSampler});
renderPass.bindVertexBuffer({.buffer = entry.mesh->vertexBuffer});
renderPass.drawPrimitives({.numVertices = static_cast<Uint32>(entry.mesh->numVertices)});
}
renderPass.end();
}
void SceneRenderer::createPipeline()
{
// create shaders
const sdlpp::GPUShader vertexShader = mApplication->loadShader("shaders/glsl/textured_3dtriangles_from_buffer.vert.spv", {
.format = sdlpp::GPUShaderFormat::SPIRV,
.stage = sdlpp::GPUShaderStage::VERTEX,
.numUniformBuffers = 1
});
const sdlpp::GPUShader fragmentShader = mApplication->loadShader("shaders/glsl/color_from_texture.frag.spv", {
.format = sdlpp::GPUShaderFormat::SPIRV,
.stage = sdlpp::GPUShaderStage::FRAGMENT,
.numSamplers = 1,
.numUniformBuffers = 1
});
std::array colorTargetsDescs = {
sdlpp::GPUColorTargetDescription{
.format = mApplication->getDevice().getSwapchainTextureFormat(mApplication->getWindow()),
.blendState = {
.enableBlend = true,
.srcColorBlendfactor = sdlpp::GPUBlendFactor::SRC_ALPHA,
.dstColorBlendfactor = sdlpp::GPUBlendFactor::ONE_MINUS_SRC_ALPHA,
.colorBlendOp = sdlpp::GPUBlendOp::ADD,
.srcAlphaBlendfactor = sdlpp::GPUBlendFactor::ONE,
.dstAlphaBlendfactor = sdlpp::GPUBlendFactor::ZERO,
.alphaBlendOp = sdlpp::GPUBlendOp::ADD
}
}
};
std::array vertexBindings = {
sdlpp::GPUVertexBinding{
.index = 0,
.pitch = sizeof(Vertex)
}
};
std::array vertexAttributes = {
sdlpp::GPUVertexAttribute{
.location = 0,
.bindingIndex = 0,
.format = sdlpp::GPUVertexElementFormat::FLOAT3,
.offset = offsetof(Vertex, pos)
},
sdlpp::GPUVertexAttribute{
.location = 1,
.bindingIndex = 0,
.format = sdlpp::GPUVertexElementFormat::FLOAT2,
.offset = offsetof(Vertex, texcoord)
}
};
mPipeline.create(mApplication->getDevice(), {
.vertexShader = vertexShader,
.fragmentShader = fragmentShader,
.vertexInputState = {
.vertexBindings = vertexBindings,
.vertexAttributes = vertexAttributes
},
.rasterizerState = {
.cullMode = sdlpp::GPUCullMode::BACK
},
.targetInfo = {
.colorTargetDescriptions = colorTargetsDescs,
.depthStencilFormat = sdlpp::GPUTextureFormat::D16_UNORM
}
});
}
}

View File

@ -0,0 +1,72 @@
#pragma once
#if !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SCENE_SCENE_RENDERER_HPP_INCLUDED)
#define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SCENE_SCENE_RENDERER_HPP_INCLUDED 1
#include <memory>
#include <unordered_map>
#include <vector>
#include "./transform3d.hpp"
#include "../application.hpp"
#include "../sdlpp/gpu.hpp"
namespace sdl_gpu_test
{
struct SceneMesh
{
sdlpp::GPUBuffer vertexBuffer;
std::size_t numVertices;
};
struct SceneTexture
{
sdlpp::GPUTexture texture;
};
struct SceneRendererRenderArgs
{
const sdlpp::GPUCommandBuffer* cmdBuffer;
const sdlpp::GPUTexture* targetTexture;
const sdlpp::GPUTexture* depthTexture;
unsigned targetTextureWidth;
unsigned targetTextureHeight;
};
class SceneRenderer
{
public:
using mesh_idx_t = std::uint64_t;
private:
struct RenderListEntry
{
std::shared_ptr<SceneMesh> mesh;
std::shared_ptr<SceneTexture> texture;
Transform3D transform;
mesh_idx_t meshIdx;
};
Application* mApplication = nullptr;
std::unordered_map<std::string, std::weak_ptr<SceneMesh>> mCachedMeshes;
std::unordered_map<std::string, std::weak_ptr<SceneTexture>> mCachedTextures;
std::vector<RenderListEntry> mRenderList;
sdlpp::GPUGraphicsPipeline mPipeline;
sdlpp::GPUSampler mSampler;
public:
void init(Application& application);
[[nodiscard]]
std::shared_ptr<SceneMesh> getMesh(const std::string& resourcePath);
[[nodiscard]]
std::shared_ptr<SceneTexture> getTexture(const std::string& resourcePath);
void render(const SceneRendererRenderArgs& args);
private:
void createPipeline();
};
} // namespace sdl_gpu_test
#endif // !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SCENE_SCENE_RENDERER_HPP_INCLUDED)

View File

@ -0,0 +1,82 @@
#pragma once
#if !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SCENE_TRANSFORM3D_HPP_INCLUDED)
#define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SCENE_TRANSFORM3D_HPP_INCLUDED 1
#define GLM_ENABLE_EXPERIMENTAL 1
#include <glm/mat4x4.hpp>
#include <glm/vec3.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/euler_angles.hpp>
#include <glm/gtx/matrix_decompose.hpp>
#undef GLM_ENABLE_EXPERIMENTAL
namespace sdl_gpu_test
{
struct Transform3D
{
glm::mat4 matrix = glm::mat4(1);
[[nodiscard]] Transform3D inverse() const
{
return Transform3D {
.matrix = glm::inverse(matrix)
};
}
[[nodiscard]] Transform3D apply(const Transform3D& other) const
{
return Transform3D{
.matrix = matrix * other.matrix
};
}
template<typename T>
[[nodiscard]] T apply(const T& value) const
{
return matrix * value;
}
[[nodiscard]] glm::vec3 apply(const glm::vec3 value) const
{
return glm::vec3(matrix * glm::vec4(value, 1.f));
}
[[nodiscard]] glm::vec3 applyRotation(const glm::vec3 vec) const
{
// TODO: maybe find a better way to extract the rotation? this is really expensive
glm::vec3 scale;
glm::quat orientation;
glm::vec3 translation;
glm::vec3 skew;
glm::vec4 perspective;
glm::decompose(matrix, scale, orientation, translation, skew, perspective);
return orientation * vec;
}
[[nodiscard]] glm::vec3 getTranslation() const { return glm::vec3(matrix[3]); }
inline void setTranslation(const glm::vec3& translation);
void setLookAt(const glm::vec3& eye, const glm::vec3& target, const glm::vec3& up = glm::vec3(0.f, 1.f, 0.f)) {
matrix = glm::inverse(glm::lookAt(eye, target, up)); // glm lookAt() is for camera matrices, therefore basically inverted
}
[[nodiscard]] static inline Transform3D make(const glm::vec3& translation, const glm::quat& rotation = {}, const glm::vec3& scale = glm::vec3(1.f));
[[nodiscard]] static Transform3D makeLookAt(const glm::vec3& eye, const glm::vec3& target, const glm::vec3& up = glm::vec3(0.f, 1.f, 0.f)) {
return Transform3D{glm::inverse(glm::lookAt(eye, target, up))}; // glm lookAt() is for camera matrices, therefore basically inverted
}
};
inline Transform3D Transform3D::make(const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale)
{
return Transform3D{glm::translate(glm::mat4_cast(rotation) * glm::scale(glm::mat4(1), scale), translation)};
}
void Transform3D::setTranslation(const glm::vec3& translation)
{
matrix[3] = glm::vec4(translation, 1.f);
}
} // namespace sdl_gpu_test
#endif // !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_SCENE_TRANSFORM3D_HPP_INCLUDED)