SceneRenderer (WIP).
This commit is contained in:
parent
122190e44b
commit
c44f87ad00
@ -3,10 +3,9 @@
|
||||
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <glm/vec2.hpp>
|
||||
#include <glm/vec3.hpp>
|
||||
#include <glm/vec4.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
#include "../scene/mesh.hpp"
|
||||
#include "../sdlpp/keyboard.hpp"
|
||||
#include "../util/bitmap.hpp"
|
||||
#include "../util/mesh.hpp"
|
||||
@ -18,12 +17,6 @@ namespace
|
||||
inline constexpr float Y_POS_MIN = -10.f;
|
||||
inline constexpr float Y_POS_MAX = 10.f;
|
||||
inline constexpr Uint16 AXIS_DEADZONE = 5000;
|
||||
|
||||
struct VertexShaderParameters
|
||||
{
|
||||
glm::mat4 worldToView;
|
||||
glm::mat4 viewToClip;
|
||||
};
|
||||
}
|
||||
|
||||
void ThreeDSceneApp::init(const AppInitArgs& args)
|
||||
@ -38,30 +31,11 @@ void ThreeDSceneApp::init(const AppInitArgs& args)
|
||||
.height = 720
|
||||
});
|
||||
|
||||
// create graphics pipeline
|
||||
createMeshPipeline();
|
||||
|
||||
// create UI pipeline
|
||||
// init UI renderer
|
||||
mUIRenderer.init(*this);
|
||||
|
||||
// load the mesh
|
||||
const Mesh mesh = loadMesh(mFileSystem.getPath("meshes/cube.obj"));
|
||||
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, {});
|
||||
// init scene renderer
|
||||
mSceneRenderer.init(*this);
|
||||
|
||||
// open gamepad
|
||||
const std::vector<SDL_JoystickID> gamepads = sdlpp::getGamepads();
|
||||
@ -84,6 +58,11 @@ void ThreeDSceneApp::init(const AppInitArgs& args)
|
||||
.posX = 100,
|
||||
.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->setText("Thanks!");
|
||||
@ -116,39 +95,14 @@ void ThreeDSceneApp::update(const AppUpdateArgs& args)
|
||||
mLastSwapchainHeight = swapchainHeight;
|
||||
}
|
||||
|
||||
// render the 3D "scene"
|
||||
const 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>(swapchainWidth),
|
||||
/* 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
|
||||
}
|
||||
// render the scene
|
||||
mSceneRenderer.render({
|
||||
.cmdBuffer = &cmdBuffer,
|
||||
.targetTexture = &swapchainTexture,
|
||||
.depthTexture = &mDepthBuffer,
|
||||
.targetTextureWidth = swapchainWidth,
|
||||
.targetTextureHeight = swapchainHeight
|
||||
});
|
||||
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"
|
||||
mUIRenderer.render({
|
||||
@ -192,72 +146,6 @@ void ThreeDSceneApp::handleMouseButtonEvent(const sdlpp::MouseButtonEvent& 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)
|
||||
{
|
||||
const std::span<const SDL_bool> keystates = sdlpp::getKeyboardState();
|
||||
|
@ -9,6 +9,8 @@
|
||||
#include "../gui/label.hpp"
|
||||
#include "../gui/widget.hpp"
|
||||
#include "../gui/ui_renderer.hpp"
|
||||
#include "../scene/scene.hpp"
|
||||
#include "../scene/scene_renderer.hpp"
|
||||
#include "../sdlpp/gamepad.hpp"
|
||||
|
||||
namespace sdl_gpu_test
|
||||
@ -16,20 +18,18 @@ namespace sdl_gpu_test
|
||||
class ThreeDSceneApp : public Application
|
||||
{
|
||||
private:
|
||||
sdlpp::GPUBuffer mVertexBuffer;
|
||||
sdlpp::GPUTexture mDepthBuffer;
|
||||
sdlpp::GPUGraphicsPipeline mMeshPipeline;
|
||||
sdlpp::GPUTexture mTexture;
|
||||
sdlpp::GPUSampler mSampler;
|
||||
|
||||
UIRenderer mUIRenderer;
|
||||
WidgetTree mWidgetTree;
|
||||
|
||||
Label* mLabel;
|
||||
Button* mButton;
|
||||
SceneRenderer mSceneRenderer;
|
||||
Scene mScene;
|
||||
|
||||
Label* mLabel = nullptr;
|
||||
Button* mButton = nullptr;
|
||||
|
||||
sdlpp::Gamepad mGamepad;
|
||||
Uint32 mNumVertices = 0;
|
||||
Uint32 mLastSwapchainWidth = 1280;
|
||||
Uint32 mLastSwapchainHeight = 720;
|
||||
float mRotation = 0.f;
|
||||
@ -41,7 +41,6 @@ public:
|
||||
void handleMouseMotionEvent(const sdlpp::MouseMotionEvent& event) override;
|
||||
void handleMouseButtonEvent(const sdlpp::MouseButtonEvent&) override;
|
||||
private:
|
||||
void createMeshPipeline();
|
||||
void processInput(const AppUpdateArgs& args);
|
||||
};
|
||||
} // namespace sdl_gpu_test
|
||||
|
@ -9,6 +9,9 @@ src_files = Split("""
|
||||
gui/label.cpp
|
||||
gui/ui_renderer.cpp
|
||||
gui/widget.cpp
|
||||
scene/mesh.cpp
|
||||
scene/scene.cpp
|
||||
scene/scene_renderer.cpp
|
||||
util/bitmap.cpp
|
||||
util/font_map.cpp
|
||||
util/mesh.cpp
|
||||
|
62
private/sdl_gpu_test/scene/mesh.cpp
Normal file
62
private/sdl_gpu_test/scene/mesh.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
41
private/sdl_gpu_test/scene/mesh.hpp
Normal file
41
private/sdl_gpu_test/scene/mesh.hpp
Normal 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)
|
42
private/sdl_gpu_test/scene/scene.cpp
Normal file
42
private/sdl_gpu_test/scene/scene.cpp
Normal 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;
|
||||
}
|
||||
}
|
71
private/sdl_gpu_test/scene/scene.hpp
Normal file
71
private/sdl_gpu_test/scene/scene.hpp
Normal 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)
|
184
private/sdl_gpu_test/scene/scene_renderer.cpp
Normal file
184
private/sdl_gpu_test/scene/scene_renderer.cpp
Normal 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
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
72
private/sdl_gpu_test/scene/scene_renderer.hpp
Normal file
72
private/sdl_gpu_test/scene/scene_renderer.hpp
Normal 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)
|
82
private/sdl_gpu_test/scene/transform3d.hpp
Normal file
82
private/sdl_gpu_test/scene/transform3d.hpp
Normal 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)
|
Loading…
x
Reference in New Issue
Block a user