初步实现World和Actor

main
wuyize 2023-04-16 20:56:02 +08:00
parent 6234a31673
commit eb79d7f66c
17 changed files with 349 additions and 190 deletions

View File

@ -2,13 +2,47 @@
layout (location = 0) in vec3 aPos; layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal; layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords; layout (location = 2) in vec2 aTexCoords;
layout (location = 3) in ivec4 boneIds;
layout (location = 4) in vec4 weights;
out vec2 vTexCoords; out vec2 vTexCoords;
uniform mat4 model; uniform mat4 model;
const int MAX_BONES = 100;
const int MAX_BONE_INFLUENCE = 4;
layout (std140, binding = 1) uniform FinalBonesMatrices
{
mat4 finalBonesMatrices[MAX_BONES];
};
void main() void main()
{ {
vec4 totalPosition = vec4(0.0f);
vec3 totalNormal = vec3(0);
int boneCount = 0;
for(int i = 0 ; i < MAX_BONE_INFLUENCE ; i++)
{
if(boneIds[i] == -1)
continue;
if(boneIds[i] >= MAX_BONES)
{
totalPosition = vec4(aPos,1.0f);
break;
}
boneCount++;
vec4 localPosition = finalBonesMatrices[boneIds[i]] * vec4(aPos,1.0f);
totalPosition += localPosition * weights[i];
vec3 localNormal = mat3(finalBonesMatrices[boneIds[i]]) * aNormal;
totalNormal += localNormal * weights[i];
}
if(boneCount == 0)
{
totalPosition = vec4(aPos, 1);
totalNormal = vec3(aNormal);
}
vTexCoords = aTexCoords; vTexCoords = aTexCoords;
gl_Position = model * vec4(aPos, 1.0); gl_Position = model * totalPosition;
} }

View File

@ -31,6 +31,7 @@
<ClInclude Include="src\Model.h" /> <ClInclude Include="src\Model.h" />
<ClInclude Include="src\RenderPass.h" /> <ClInclude Include="src\RenderPass.h" />
<ClInclude Include="src\Shader.h" /> <ClInclude Include="src\Shader.h" />
<ClInclude Include="src\World.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="src\Actor.cpp" /> <ClCompile Include="src\Actor.cpp" />
@ -46,6 +47,7 @@
<ClCompile Include="src\Mesh.cpp" /> <ClCompile Include="src\Mesh.cpp" />
<ClCompile Include="src\Model.cpp" /> <ClCompile Include="src\Model.cpp" />
<ClCompile Include="src\RenderPass.cpp" /> <ClCompile Include="src\RenderPass.cpp" />
<ClCompile Include="src\World.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="Shaders\brdf_lut.comp" /> <None Include="Shaders\brdf_lut.comp" />
@ -160,6 +162,7 @@
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard> <LanguageStandard>stdcpp20</LanguageStandard>
<LanguageStandard_C>stdc17</LanguageStandard_C> <LanguageStandard_C>stdc17</LanguageStandard_C>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
@ -176,6 +179,7 @@
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard> <LanguageStandard>stdcpp20</LanguageStandard>
<LanguageStandard_C>stdc17</LanguageStandard_C> <LanguageStandard_C>stdc17</LanguageStandard_C>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>

View File

@ -54,6 +54,9 @@
<ClInclude Include="src\MainWindow.h"> <ClInclude Include="src\MainWindow.h">
<Filter>头文件</Filter> <Filter>头文件</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\World.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="src\gl.c"> <ClCompile Include="src\gl.c">
@ -95,6 +98,9 @@
<ClCompile Include="src\MainWindow.cpp"> <ClCompile Include="src\MainWindow.cpp">
<Filter>源文件</Filter> <Filter>源文件</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="src\World.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="Shaders\brdf_lut.comp"> <None Include="Shaders\brdf_lut.comp">

View File

@ -1 +1,50 @@
#include "Actor.h" #include "Actor.h"
#include "MainWindow.h"
Actor::Actor(const std::string& path)
: gl(MainWindow::getGLContext())
, model(gl, path)
, danceAnimation(path, &model)
, animator(gl, &danceAnimation)
{
}
void Actor::tick(float deltaTime)
{
animator.UpdateAnimation(deltaTime);
}
void Actor::draw(Shader& shader)
{
gl->BindBufferBase(GL_UNIFORM_BUFFER, 1, animator.getFinalBonesMatricesUBO());
model.draw(shader);
gl->BindBufferBase(GL_UNIFORM_BUFFER, 1, 0);
}
void Actor::setPosition(const glm::vec3& position)
{
this->position = position;
updateTransform();
}
void Actor::setScale(const glm::vec3& scale)
{
this->scale = scale;
updateTransform();
}
void Actor::setRotaion(const glm::quat& rotation)
{
this->rotation = rotation;
updateTransform();
}
std::pair<glm::vec3, glm::vec3> Actor::getAABB()
{
return model.getAABB();
}
void Actor::updateTransform()
{
model.setTransform(glm::translate(glm::mat4(1), position) * glm::scale(glm::mat4(1), scale) * glm::mat4_cast(rotation));
}

View File

@ -1,10 +1,29 @@
#pragma once #pragma once
#include "Model.h" #include "Model.h"
#include <glm/gtc/quaternion.hpp>
#include "Animation.h"
#include "Animator.h"
class Actor class Actor
{ {
public: public:
Actor(const std::string& path);
void tick(float deltaTime);
void draw(Shader& shader);
void setPosition(const glm::vec3& position);
void setScale(const glm::vec3& scale);
void setRotaion(const glm::quat& rotation);
std::pair<glm::vec3, glm::vec3> getAABB();
private: private:
void updateTransform();
GladGLContext* gl;
Model model;
Animation danceAnimation;
Animator animator;
glm::vec3 position = glm::vec3(0);
glm::vec3 scale = glm::vec3(1);
glm::quat rotation = glm::quat(1, 0, 0, 0);
}; };

View File

@ -11,32 +11,34 @@ class Animator
public: public:
static constexpr GLint kMaxBone = 100; static constexpr GLint kMaxBone = 100;
Animator(Animation* animation) Animator(GladGLContext* gl, Animation* animation) : gl(gl)
{ {
m_CurrentTime = 0.0; currentTime = 0.0;
m_CurrentAnimation = animation; currentAnimation = animation;
m_FinalBoneMatrices.reserve(100); finalBoneMatrices.reserve(100);
for (int i = 0; i < 100; i++) for (int i = 0; i < 100; i++)
m_FinalBoneMatrices.push_back(glm::mat4(1.0f)); finalBoneMatrices.push_back(glm::mat4(1.0f));
gl->CreateBuffers(1, &finalBonesMatricesUBO);
gl->NamedBufferData(finalBonesMatricesUBO, sizeof(glm::mat4) * Animator::kMaxBone, nullptr, GL_DYNAMIC_DRAW);
} }
void UpdateAnimation(float dt) void UpdateAnimation(float deltaTime)
{ {
m_DeltaTime = dt; if (currentAnimation)
if (m_CurrentAnimation)
{ {
m_CurrentTime += m_CurrentAnimation->GetTicksPerSecond() * dt; currentTime += currentAnimation->GetTicksPerSecond() * deltaTime;
m_CurrentTime = fmod(m_CurrentTime, m_CurrentAnimation->GetDuration()); currentTime = fmod(currentTime, currentAnimation->GetDuration());
CalculateBoneTransform(&m_CurrentAnimation->GetRootNode(), glm::mat4(1.0f)); CalculateBoneTransform(&currentAnimation->GetRootNode(), glm::mat4(1.0f));
} }
} }
void PlayAnimation(Animation* pAnimation) void PlayAnimation(Animation* pAnimation)
{ {
m_CurrentAnimation = pAnimation; currentAnimation = pAnimation;
m_CurrentTime = 0.0f; currentTime = 0.0f;
} }
void CalculateBoneTransform(const AssimpNodeData* node, glm::mat4 parentTransform) void CalculateBoneTransform(const AssimpNodeData* node, glm::mat4 parentTransform)
@ -44,22 +46,22 @@ public:
std::string nodeName = node->name; std::string nodeName = node->name;
glm::mat4 nodeTransform = node->transformation; glm::mat4 nodeTransform = node->transformation;
Bone* Bone = m_CurrentAnimation->FindBone(nodeName); Bone* Bone = currentAnimation->FindBone(nodeName);
if (Bone) if (Bone)
{ {
Bone->Update(m_CurrentTime); Bone->Update(currentTime);
nodeTransform = Bone->GetLocalTransform(); nodeTransform = Bone->GetLocalTransform();
} }
glm::mat4 globalTransformation = parentTransform * nodeTransform; glm::mat4 globalTransformation = parentTransform * nodeTransform;
auto boneInfoMap = m_CurrentAnimation->GetBoneIDMap(); auto boneInfoMap = currentAnimation->GetBoneIDMap();
if (boneInfoMap.find(nodeName) != boneInfoMap.end()) if (boneInfoMap.find(nodeName) != boneInfoMap.end())
{ {
int index = boneInfoMap[nodeName].id; int index = boneInfoMap[nodeName].id;
glm::mat4 offset = boneInfoMap[nodeName].offset; glm::mat4 offset = boneInfoMap[nodeName].offset;
m_FinalBoneMatrices[index] = globalTransformation * offset; finalBoneMatrices[index] = globalTransformation * offset;
} }
for (int i = 0; i < node->childrenCount; i++) for (int i = 0; i < node->childrenCount; i++)
@ -68,13 +70,19 @@ public:
std::vector<glm::mat4> GetFinalBoneMatrices() std::vector<glm::mat4> GetFinalBoneMatrices()
{ {
return m_FinalBoneMatrices; return finalBoneMatrices;
}
GLuint getFinalBonesMatricesUBO()
{
gl->NamedBufferSubData(finalBonesMatricesUBO, 0, finalBoneMatrices.size() * sizeof(finalBoneMatrices[0]), finalBoneMatrices.data());
return finalBonesMatricesUBO;
} }
private: private:
std::vector<glm::mat4> m_FinalBoneMatrices; GladGLContext* gl;
Animation* m_CurrentAnimation; std::vector<glm::mat4> finalBoneMatrices;
float m_CurrentTime; GLuint finalBonesMatricesUBO;
float m_DeltaTime; Animation* currentAnimation;
float currentTime;
}; };

View File

@ -20,7 +20,7 @@ public:
// Default camera values // Default camera values
static constexpr float YAW = -90.0f; static constexpr float YAW = -90.0f;
static constexpr float PITCH = 0.0f; static constexpr float PITCH = 0.0f;
static constexpr float SPEED = 20.f; static constexpr float SPEED = 5.f;
static constexpr float SENSITIVITY = 0.1f; static constexpr float SENSITIVITY = 0.1f;
static constexpr float ZOOM = 45.0f; static constexpr float ZOOM = 45.0f;
// camera Attributes // camera Attributes
@ -40,7 +40,7 @@ public:
float Zoom; float Zoom;
float Ratio; float Ratio;
float NearPlane = 0.1f; float NearPlane = 0.1f;
float FarPlane = 1000.f; float FarPlane = 100.f;
// constructor with vectors // constructor with vectors
Camera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f), float yaw = YAW, float pitch = PITCH); Camera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f), float yaw = YAW, float pitch = PITCH);

View File

@ -78,39 +78,27 @@ glm::mat4 Light::getLightSpaceMatrix(const float nearPlane, const float farPlane
minZ = std::min(minZ, -trf.z); minZ = std::min(minZ, -trf.z);
maxZ = std::max(maxZ, -trf.z); maxZ = std::max(maxZ, -trf.z);
} }
if (model != nullptr)
for (const glm::vec3& v : model->AABB)
{
const glm::vec4 trf = lightView * glm::vec4(v, 1);
//qDebug() << v;
//qDebug() << trf;
//minX = std::min(minX, trf.x());
//maxX = std::max(maxX, trf.x());
//minY = std::min(minY, trf.y());
//maxY = std::max(maxY, trf.y());
minZ = std::min(minZ, -trf.z);
//maxZ = std::max(maxZ, trf.z());
} std::vector<glm::vec3> aabbVertexs;
//qDebug() << minZ; auto& [minPos, maxPos] = sceneAABB;
// Tune this parameter according to the scene aabbVertexs.emplace_back(minPos.x, minPos.y, minPos.z);
/* constexpr float zMult = 10.0f; aabbVertexs.emplace_back(minPos.x, minPos.y, maxPos.z);
if (minZ < 0) aabbVertexs.emplace_back(minPos.x, maxPos.y, minPos.z);
aabbVertexs.emplace_back(minPos.x, maxPos.y, maxPos.z);
aabbVertexs.emplace_back(maxPos.x, minPos.y, minPos.z);
aabbVertexs.emplace_back(maxPos.x, minPos.y, maxPos.z);
aabbVertexs.emplace_back(maxPos.x, maxPos.y, minPos.z);
aabbVertexs.emplace_back(maxPos.x, maxPos.y, maxPos.z);
for (const glm::vec3& v : aabbVertexs)
{ {
minZ *= zMult; const glm::vec4 trf = lightView * glm::vec4(v, 1);
//minX = std::min(minX, trf.x());
//maxX = std::max(maxX, trf.x());
//minY = std::min(minY, trf.y());
//maxY = std::max(maxY, trf.y());
minZ = std::min(minZ, -trf.z);
//maxZ = std::max(maxZ, trf.z());
} }
else
{
minZ /= zMult;
}
if (maxZ < 0)
{
maxZ /= zMult;
}
else
{
maxZ *= zMult;
}*/
glm::mat4 lightProjection = glm::ortho(minX, maxX, minY, maxY, minZ, maxZ); glm::mat4 lightProjection = glm::ortho(minX, maxX, minY, maxY, minZ, maxZ);
frustumSizes.push_back(std::max(maxX - minX, maxY - minY)); frustumSizes.push_back(std::max(maxX - minX, maxY - minY));

View File

@ -11,11 +11,12 @@
class Light class Light
{ {
public: public:
glm::vec3 lightDirection = glm::normalize(glm::vec3(0.2, 4, 1)); glm::vec3 lightDirection = glm::normalize(glm::vec3(0.2, 4, 0.4));
std::vector<float> shadowCascadeLevels; std::vector<float> shadowCascadeLevels;
float blendRatio = 0.3; float blendRatio = 0.3;
std::vector<float> frustumSizes; std::vector<float> frustumSizes;
Model* model = nullptr; std::pair<glm::vec3, glm::vec3> sceneAABB;
Light(Camera* camera); Light(Camera* camera);
std::vector<glm::vec4> getFrustumCornersWorldSpace(const glm::mat4& projview); std::vector<glm::vec4> getFrustumCornersWorldSpace(const glm::mat4& projview);
std::vector<glm::vec4> getFrustumCornersWorldSpace(const glm::mat4& proj, const glm::mat4& view); std::vector<glm::vec4> getFrustumCornersWorldSpace(const glm::mat4& proj, const glm::mat4& view);

View File

@ -1,6 +1,7 @@
#include "MainWindow.h" #include "MainWindow.h"
#include "IblUtils.h" #include "IblUtils.h"
#include "RenderPass.h" #include "RenderPass.h"
#include "World.h"
MainWindow::MainWindow() MainWindow::MainWindow()
: camera(glm::vec3(0.0f, 0.0f, 3.0f)) : camera(glm::vec3(0.0f, 0.0f, 3.0f))
@ -8,6 +9,105 @@ MainWindow::MainWindow()
{ {
} }
int MainWindow::exec()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
float xscale, yscale;
glfwGetMonitorContentScale(monitor, &xscale, &yscale);
GLFWwindow* window = glfwCreateWindow(kWindowWidth * xscale, kWindowHeight * yscale, "ToyEngine", NULL, NULL);
glfwSetFramebufferSizeCallback(window, [](GLFWwindow* window, int width, int height) {
MainWindow::instance().framebufferSizeCallback(window, width, height);
});
glfwSetCursorPosCallback(window, [](GLFWwindow* window, double xpos, double ypos) {
MainWindow::instance().mouseCallback(window, xpos, ypos);
});
glfwSetScrollCallback(window, [](GLFWwindow* window, double xoffset, double yoffset) {
MainWindow::instance().scrollCallback(window, xoffset, yoffset);
});
int xpos, ypos, width, height;
glfwGetMonitorWorkarea(monitor, &xpos, &ypos, &width, &height);
glfwSetWindowPos(window, xpos + (width - (kWindowWidth * xscale)) / 2, ypos + (height - kWindowHeight * yscale) / 2);
glfwMakeContextCurrent(window);
gl = std::make_unique<GladGLContext>();
if (!gladLoadGLContext(gl.get(), [](const char* name) { return (GLADapiproc)glfwGetProcAddress(name); }))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
gl->Enable(GL_DEBUG_OUTPUT);
//gl->Enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
gl->DebugMessageCallback([](GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) {
if (type == GL_DEBUG_TYPE_ERROR)
std::cerr << std::format("GL_ERROR: type = {:#x}, severity = {:#x}, message = {}", type, severity, message);
}, 0);
gl->ClearColor(0.0f, 0.0f, 0.0f, 1.0f);
gl->Enable(GL_DEPTH_TEST);
gl->DepthFunc(GL_LEQUAL);
gl->Enable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
std::string modelFilePath;
//modelFilePath = "E:\\3D Objects\\plane\\obj\\plane.obj";
//modelFilePath = "E:\\3D Objects\\plane\\plane.gltf";
modelFilePath = "E:\\3D Objects\\vampire/gltf/vampire.gltf";
//modelFilePath = "E:\\3D Objects\\cup\\cup.gltf";
//modelFilePath = "E:\\3D Objects\\Sponza\\Sponza.gltf";
auto actor = std::make_shared<Actor>(modelFilePath);
actor->setRotaion(glm::angleAxis(glm::radians(-90.f), glm::vec3(1, 0, 0)));
auto sponza = std::make_shared<Actor>("E:\\3D Objects\\Sponza\\Sponza.gltf");
sponza->setScale(glm::vec3(2));
World world;
world.addActor(actor);
world.addActor(sponza);
auto [minPos, maxPos] = world.getAABB();
std::cout << std::format("{},{},{} {},{},{}\n", minPos.x, minPos.y, minPos.z, maxPos.x, maxPos.y, maxPos.z);
light.sceneAABB = world.getAABB();
glm::mat4 projection, view;
auto [skyCubemap, irradianceMap, prefilterMap, brdfLUTTexture] = IblUtils::precomputeCubemaps(gl.get());
ShadowMapPass shadowMapPass(gl.get(), shadowFboHandle, shadowMapResolution, world, light);
GeometryPass geometryPass(gl.get(), frameWidth, frameHeight, fbo, world, projection, view);
LightingPass lightingPass(gl.get(), frameWidth, frameHeight, view, camera, light, mainLightRadiance,
gbuffers, shadowGbuffer, irradianceMap, prefilterMap, brdfLUTTexture);
FinalPass finalPass(gl.get(), frameWidth, frameHeight, gbuffers, exposure);
SkyboxPass skyboxPass(gl.get(), projection, view, exposure, skyCubemap);
int w, h;
glfwGetFramebufferSize(window, &w, &h);
framebufferSizeCallback(window, w, h);
while (!glfwWindowShouldClose(window))
{
float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
processInput(window);
world.tick(deltaTime);
projection = camera.getProjectionMatrix();
view = camera.getViewMatrix();
shadowMapPass.dispatch();
geometryPass.dispatch();
lightingPass.dispatch();
finalPass.dispatch();
skyboxPass.dispatch();
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
}
void MainWindow::processInput(GLFWwindow* window) void MainWindow::processInput(GLFWwindow* window)
{ {
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
@ -26,16 +126,17 @@ void MainWindow::processInput(GLFWwindow* window)
if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS)
camera.processKeyboard(DOWN, deltaTime); camera.processKeyboard(DOWN, deltaTime);
glm::mat4 transform(1); static glm::mat4 transform(1);
float speed = 1; float speed = 1;
if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS)
modelPtr->setTransform(glm::translate(transform, glm::vec3(0, 0, speed))); transform = glm::translate(transform, glm::vec3(0, 0, speed));
if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS)
modelPtr->setTransform(glm::translate(transform, glm::vec3(0, 0, -speed))); transform = glm::translate(transform, glm::vec3(0, 0, -speed));
if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS) if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS)
modelPtr->setTransform(glm::translate(transform, glm::vec3(-speed, 0, 0))); transform = glm::translate(transform, glm::vec3(-speed, 0, 0));
if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS) if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS)
modelPtr->setTransform(glm::translate(transform, glm::vec3(speed, 0, 0))); transform = glm::translate(transform, glm::vec3(speed, 0, 0));
//modelPtr->setTransform(transform);
} }
void MainWindow::framebufferSizeCallback(GLFWwindow* window, int width, int height) void MainWindow::framebufferSizeCallback(GLFWwindow* window, int width, int height)
@ -145,9 +246,9 @@ void MainWindow::mouseCallback(GLFWwindow* window, double xpos, double ypos)
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS) if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS)
{ {
float speed = 0.2f; float speed = 0.2f;
glm::mat4 rotate(1); static glm::mat4 rotate(1);
rotate = glm::rotate(rotate, glm::radians(glm::length(glm::vec2(xoffset, yoffset)) * speed), glm::vec3(glm::vec2(-yoffset, xoffset), 0.0)); rotate = glm::rotate(rotate, glm::radians(glm::length(glm::vec2(xoffset, yoffset)) * speed), glm::vec3(glm::vec2(-yoffset, xoffset), 0.0));
modelPtr->setTransform(rotate); //modelPtr->setTransform(rotate);
} }
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS) if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS)
camera.processMouseMovement(xoffset, yoffset); camera.processMouseMovement(xoffset, yoffset);
@ -164,97 +265,7 @@ MainWindow& MainWindow::instance()
return window; return window;
} }
int MainWindow::exec() GladGLContext* MainWindow::getGLContext()
{ {
glfwInit(); return instance().gl.get();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
float xscale, yscale;
glfwGetMonitorContentScale(monitor, &xscale, &yscale);
GLFWwindow* window = glfwCreateWindow(kWindowWidth * xscale, kWindowHeight * yscale, "RenderModel", NULL, NULL);
MainWindow& m = *this;
glfwSetFramebufferSizeCallback(window, [](GLFWwindow* window, int width, int height) {
MainWindow::instance().framebufferSizeCallback(window, width, height);
});
glfwSetCursorPosCallback(window, [](GLFWwindow* window, double xpos, double ypos) {
MainWindow::instance().mouseCallback(window, xpos, ypos);
});
glfwSetScrollCallback(window, [](GLFWwindow* window, double xoffset, double yoffset) {
MainWindow::instance().scrollCallback(window, xoffset, yoffset);
});
int xpos, ypos, width, height;
glfwGetMonitorWorkarea(monitor, &xpos, &ypos, &width, &height);
glfwSetWindowPos(window, xpos + (width - (kWindowWidth * xscale)) / 2, ypos + (height - kWindowHeight * yscale) / 2);
glfwMakeContextCurrent(window);
gl = std::make_unique<GladGLContext>();
if (!gladLoadGLContext(gl.get(), [](const char* name) { return (GLADapiproc)glfwGetProcAddress(name); }))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
gl->Enable(GL_DEBUG_OUTPUT);
//gl->Enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
gl->DebugMessageCallback([](GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) {
if (type == GL_DEBUG_TYPE_ERROR)
std::cerr << std::format("GL_ERROR: type = {:#x}, severity = {:#x}, message = {}", type, severity, message);
}, 0);
gl->ClearColor(0.0f, 0.0f, 0.0f, 1.0f);
gl->Enable(GL_DEPTH_TEST);
gl->DepthFunc(GL_LEQUAL);
gl->Enable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
std::string modelFilePath;
//modelFilePath = "E:\\3D Objects\\plane\\obj\\plane.obj";
//modelFilePath = "E:\\3D Objects\\plane\\plane.gltf";
modelFilePath = "E:\\3D Objects\\vampire/gltf/vampire.gltf";
//modelFilePath = "E:\\3D Objects\\cup\\cup.gltf";
//modelFilePath = "E:\\3D Objects\\Sponza\\Sponza.gltf";
Model model(gl.get(), modelFilePath);
modelPtr = &model;
light.model = &model;
Animation danceAnimation(modelFilePath, &model);
Animator animator(&danceAnimation);
glm::mat4 projection, view;
auto [skyCubemap, irradianceMap, prefilterMap, brdfLUTTexture] = IblUtils::precomputeCubemaps(gl.get());
ShadowMapPass shadowMapPass(gl.get(), shadowFboHandle, shadowMapResolution, model, light);
GeometryPass geometryPass(gl.get(), frameWidth, frameHeight, fbo, model, projection, view, animator);
LightingPass lightingPass(gl.get(), frameWidth, frameHeight, view, camera, light, mainLightRadiance,
gbuffers, shadowGbuffer, irradianceMap, prefilterMap, brdfLUTTexture);
FinalPass finalPass(gl.get(), frameWidth, frameHeight, gbuffers, exposure);
SkyboxPass skyboxPass(gl.get(), projection, view, exposure, skyCubemap);
int w, h;
glfwGetFramebufferSize(window, &w, &h);
framebufferSizeCallback(window, w, h);
while (!glfwWindowShouldClose(window))
{
float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
processInput(window);
animator.UpdateAnimation(deltaTime);
projection = camera.getProjectionMatrix();
view = camera.getViewMatrix();
shadowMapPass.dispatch();
geometryPass.dispatch();
lightingPass.dispatch();
finalPass.dispatch();
skyboxPass.dispatch();
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
} }

View File

@ -10,6 +10,7 @@ class MainWindow
{ {
public: public:
static MainWindow& instance(); static MainWindow& instance();
static GladGLContext* getGLContext();
int exec(); int exec();
private: private:
@ -24,7 +25,6 @@ private:
unsigned int frameWidth; unsigned int frameWidth;
unsigned int frameHeight; unsigned int frameHeight;
Model* modelPtr = nullptr;
Camera camera; Camera camera;
Light light; Light light;
glm::vec3 mainLightRadiance = 40.f * glm::normalize(glm::vec3(0.7529, 0.7450, 0.6784)); glm::vec3 mainLightRadiance = 40.f * glm::normalize(glm::vec3(0.7529, 0.7450, 0.6784));

View File

@ -20,8 +20,17 @@ void Model::draw(Shader& shader)
void Model::setTransform(const glm::mat4& trans) void Model::setTransform(const glm::mat4& trans)
{ {
auto inverse = glm::inverse(transform);
transform = trans;
for (auto& mesh : meshes) for (auto& mesh : meshes)
mesh->model = trans * mesh->model; mesh->model = transform * inverse * mesh->model;
minPos = transform * inverse * glm::vec4(minPos, 1);
maxPos = transform * inverse * glm::vec4(maxPos, 1);
}
std::pair<glm::vec3, glm::vec3> Model::getAABB()
{
return { minPos, maxPos };
} }
void Model::loadModel(std::string const& path) void Model::loadModel(std::string const& path)
@ -38,17 +47,9 @@ void Model::loadModel(std::string const& path)
} }
aiMatrix4x4 transform; aiMatrix4x4 transform;
aiMatrix4x4::Scaling(aiVector3D(10), transform); //aiMatrix4x4::Scaling(aiVector3D(10), transform);
//aiMatrix4x4::Rotation(glm::radians(-90.f), { 1,0,0 }, transform); //aiMatrix4x4::Rotation(glm::radians(-90.f), { 1,0,0 }, transform);
processNode(scene->mRootNode, scene, transform * scene->mRootNode->mTransformation); processNode(scene->mRootNode, scene, transform * scene->mRootNode->mTransformation);
AABB.emplace_back(minPos.x, minPos.y, minPos.z);
AABB.emplace_back(minPos.x, minPos.y, maxPos.z);
AABB.emplace_back(minPos.x, maxPos.y, minPos.z);
AABB.emplace_back(minPos.x, maxPos.y, maxPos.z);
AABB.emplace_back(maxPos.x, minPos.y, minPos.z);
AABB.emplace_back(maxPos.x, minPos.y, maxPos.z);
AABB.emplace_back(maxPos.x, maxPos.y, minPos.z);
AABB.emplace_back(maxPos.x, maxPos.y, maxPos.z);
} }
void Model::processNode(aiNode* node, const aiScene* scene, aiMatrix4x4 mat4) void Model::processNode(aiNode* node, const aiScene* scene, aiMatrix4x4 mat4)

View File

@ -21,7 +21,7 @@ struct BoneInfo
class Model class Model
{ {
public: public:
std::vector<glm::vec3> AABB; glm::mat4 transform = glm::mat4(1);
std::vector<std::unique_ptr<Mesh>> meshes; std::vector<std::unique_ptr<Mesh>> meshes;
std::map<std::string, BoneInfo> boneInfoMap; std::map<std::string, BoneInfo> boneInfoMap;
int boneCount = 0; int boneCount = 0;
@ -29,6 +29,7 @@ public:
Model(GladGLContext* gl, std::string const& path); Model(GladGLContext* gl, std::string const& path);
void draw(Shader& shader); void draw(Shader& shader);
void setTransform(const glm::mat4& trans); void setTransform(const glm::mat4& trans);
std::pair<glm::vec3, glm::vec3> getAABB();
private: private:
GladGLContext* gl; GladGLContext* gl;
std::filesystem::path directory; /// 模型所在路径 std::filesystem::path directory; /// 模型所在路径

View File

@ -2,12 +2,12 @@
#include "IblUtils.h" #include "IblUtils.h"
#include "Mesh.h" #include "Mesh.h"
ShadowMapPass::ShadowMapPass(GladGLContext* gl, GLuint& shadowFboHandle, int& shadowMapResolution, Model& model, Light& light) ShadowMapPass::ShadowMapPass(GladGLContext* gl, GLuint& shadowFboHandle, int& shadowMapResolution, World& world, Light& light)
: RenderPass(gl) : RenderPass(gl)
, modelShadowShader(gl, "Shaders/model_shadow.vert", "Shaders/model_shadow.frag", "Shaders/model_shadow.geom") , modelShadowShader(gl, "Shaders/model_shadow.vert", "Shaders/model_shadow.frag", "Shaders/model_shadow.geom")
, shadowFboHandle(shadowFboHandle) , shadowFboHandle(shadowFboHandle)
, shadowMapResolution(shadowMapResolution) , shadowMapResolution(shadowMapResolution)
, model(model) , world(world)
, light(light) , light(light)
{ {
gl->CreateBuffers(1, &lightSpaceMatricesUBO); gl->CreateBuffers(1, &lightSpaceMatricesUBO);
@ -24,26 +24,22 @@ void ShadowMapPass::dispatch()
gl->Viewport(0, 0, shadowMapResolution, shadowMapResolution); gl->Viewport(0, 0, shadowMapResolution, shadowMapResolution);
gl->Clear(GL_DEPTH_BUFFER_BIT); gl->Clear(GL_DEPTH_BUFFER_BIT);
modelShadowShader.use(); modelShadowShader.use();
model.draw(modelShadowShader); world.draw(modelShadowShader);
modelShadowShader.release(); modelShadowShader.release();
gl->BindFramebuffer(GL_FRAMEBUFFER, 0); gl->BindFramebuffer(GL_FRAMEBUFFER, 0);
} }
GeometryPass::GeometryPass(GladGLContext* gl, unsigned int& frameWidth, unsigned int& frameHeight, GLuint& fbo, Model& model, glm::mat4& projection, glm::mat4& view, Animator& animator) GeometryPass::GeometryPass(GladGLContext* gl, unsigned int& frameWidth, unsigned int& frameHeight, GLuint& fbo, World& world, glm::mat4& projection, glm::mat4& view)
: RenderPass(gl) : RenderPass(gl)
, modelShader(gl, "Shaders/model.vert", "Shaders/model.frag") , modelShader(gl, "Shaders/model.vert", "Shaders/model.frag")
, plainShader(gl, "Shaders/plain.vert", "Shaders/plain.frag") , plainShader(gl, "Shaders/plain.vert", "Shaders/plain.frag")
, frameWidth(frameWidth) , frameWidth(frameWidth)
, frameHeight(frameHeight) , frameHeight(frameHeight)
, fbo(fbo) , fbo(fbo)
, model(model) , world(world)
, projection(projection) , projection(projection)
, view(view) , view(view)
, animator(animator)
{ {
gl->CreateBuffers(1, &finalBonesMatricesUBO);
gl->NamedBufferData(finalBonesMatricesUBO, sizeof(glm::mat4) * Animator::kMaxBone, nullptr, GL_DYNAMIC_DRAW);
gl->BindBufferBase(GL_UNIFORM_BUFFER, 1, finalBonesMatricesUBO);
} }
void GeometryPass::dispatch() void GeometryPass::dispatch()
@ -55,9 +51,7 @@ void GeometryPass::dispatch()
modelShader.use(); modelShader.use();
modelShader.setUniformValue("projection", projection); modelShader.setUniformValue("projection", projection);
modelShader.setUniformValue("view", view); modelShader.setUniformValue("view", view);
auto boneMatrices = animator.GetFinalBoneMatrices(); world.draw(modelShader);
gl->NamedBufferSubData(finalBonesMatricesUBO, 0, boneMatrices.size() * sizeof(boneMatrices[0]), boneMatrices.data());
model.draw(modelShader);
modelShader.release(); modelShader.release();
/// Debug Lighting /// Debug Lighting

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <glad/gl.h> #include <glad/gl.h>
#include "Shader.h" #include "Shader.h"
#include "Model.h" #include "World.h"
#include "Light.h" #include "Light.h"
#include <array> #include <array>
#include "Animator.h" #include "Animator.h"
@ -18,13 +18,13 @@ protected:
class ShadowMapPass : public RenderPass class ShadowMapPass : public RenderPass
{ {
public: public:
ShadowMapPass(GladGLContext* gl, GLuint& shadowFboHandle, int& shadowMapResolution, Model& model, Light& light); ShadowMapPass(GladGLContext* gl, GLuint& shadowFboHandle, int& shadowMapResolution, World& world, Light& light);
void dispatch(); void dispatch();
private: private:
Shader modelShadowShader; Shader modelShadowShader;
GLuint& shadowFboHandle; GLuint& shadowFboHandle;
int& shadowMapResolution; int& shadowMapResolution;
Model& model; World& world;
Light& light; Light& light;
GLuint lightSpaceMatricesUBO; GLuint lightSpaceMatricesUBO;
}; };
@ -33,7 +33,7 @@ class GeometryPass : public RenderPass
{ {
public: public:
GeometryPass(GladGLContext* gl, unsigned int& frameWidth, unsigned int& frameHeight, GeometryPass(GladGLContext* gl, unsigned int& frameWidth, unsigned int& frameHeight,
GLuint& fbo, Model& model, glm::mat4& projection, glm::mat4& view, Animator& animator); GLuint& fbo, World& world, glm::mat4& projection, glm::mat4& view);
void dispatch(); void dispatch();
private: private:
Shader modelShader; Shader modelShader;
@ -42,10 +42,9 @@ private:
unsigned int& frameWidth; unsigned int& frameWidth;
unsigned int& frameHeight; unsigned int& frameHeight;
GLuint& fbo; GLuint& fbo;
Model& model; World& world;
glm::mat4& projection; glm::mat4& projection;
glm::mat4& view; glm::mat4& view;
Animator& animator;
}; };
class LightingPass : public RenderPass class LightingPass : public RenderPass

31
ToyEngine/src/World.cpp Normal file
View File

@ -0,0 +1,31 @@
#include "World.h"
void World::tick(float deltaTime)
{
for (auto& actor : actors)
actor->tick(deltaTime);
}
void World::draw(Shader& shader)
{
for (auto& actor : actors)
actor->draw(shader);
}
void World::addActor(std::shared_ptr<Actor> actor)
{
actors.push_back(actor);
}
std::pair<glm::vec3, glm::vec3> World::getAABB()
{
glm::vec3 minPos = glm::vec3(std::numeric_limits<float>::max());
glm::vec3 maxPos = glm::vec3(std::numeric_limits<float>::min());
for (auto& actor : actors)
{
auto [min, max] = actor->getAABB();
minPos = glm::min(minPos, min);
maxPos = glm::max(maxPos, max);
}
return { minPos, maxPos };
}

13
ToyEngine/src/World.h Normal file
View File

@ -0,0 +1,13 @@
#pragma once
#include "Actor.h"
class World
{
public:
std::vector<std::shared_ptr<Actor>> actors;
void tick(float deltaTime);
void draw(Shader& shader);
void addActor(std::shared_ptr<Actor> actor);
std::pair<glm::vec3, glm::vec3> getAABB();
};