初步实现World和Actor
parent
6234a31673
commit
eb79d7f66c
|
@ -2,13 +2,47 @@
|
|||
layout (location = 0) in vec3 aPos;
|
||||
layout (location = 1) in vec3 aNormal;
|
||||
layout (location = 2) in vec2 aTexCoords;
|
||||
layout (location = 3) in ivec4 boneIds;
|
||||
layout (location = 4) in vec4 weights;
|
||||
|
||||
out vec2 vTexCoords;
|
||||
|
||||
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()
|
||||
{
|
||||
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;
|
||||
gl_Position = model * vec4(aPos, 1.0);
|
||||
gl_Position = model * totalPosition;
|
||||
}
|
|
@ -31,6 +31,7 @@
|
|||
<ClInclude Include="src\Model.h" />
|
||||
<ClInclude Include="src\RenderPass.h" />
|
||||
<ClInclude Include="src\Shader.h" />
|
||||
<ClInclude Include="src\World.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\Actor.cpp" />
|
||||
|
@ -46,6 +47,7 @@
|
|||
<ClCompile Include="src\Mesh.cpp" />
|
||||
<ClCompile Include="src\Model.cpp" />
|
||||
<ClCompile Include="src\RenderPass.cpp" />
|
||||
<ClCompile Include="src\World.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Shaders\brdf_lut.comp" />
|
||||
|
@ -160,6 +162,7 @@
|
|||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
<LanguageStandard_C>stdc17</LanguageStandard_C>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
|
@ -176,6 +179,7 @@
|
|||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
<LanguageStandard_C>stdc17</LanguageStandard_C>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
|
|
|
@ -54,6 +54,9 @@
|
|||
<ClInclude Include="src\MainWindow.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\World.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\gl.c">
|
||||
|
@ -95,6 +98,9 @@
|
|||
<ClCompile Include="src\MainWindow.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\World.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Shaders\brdf_lut.comp">
|
||||
|
|
|
@ -1 +1,50 @@
|
|||
#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));
|
||||
}
|
||||
|
|
|
@ -1,10 +1,29 @@
|
|||
#pragma once
|
||||
#include "Model.h"
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include "Animation.h"
|
||||
#include "Animator.h"
|
||||
|
||||
class Actor
|
||||
{
|
||||
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:
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
|
|
|
@ -11,32 +11,34 @@ class Animator
|
|||
public:
|
||||
static constexpr GLint kMaxBone = 100;
|
||||
|
||||
Animator(Animation* animation)
|
||||
Animator(GladGLContext* gl, Animation* animation) : gl(gl)
|
||||
{
|
||||
m_CurrentTime = 0.0;
|
||||
m_CurrentAnimation = animation;
|
||||
currentTime = 0.0;
|
||||
currentAnimation = animation;
|
||||
|
||||
m_FinalBoneMatrices.reserve(100);
|
||||
finalBoneMatrices.reserve(100);
|
||||
|
||||
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 (m_CurrentAnimation)
|
||||
if (currentAnimation)
|
||||
{
|
||||
m_CurrentTime += m_CurrentAnimation->GetTicksPerSecond() * dt;
|
||||
m_CurrentTime = fmod(m_CurrentTime, m_CurrentAnimation->GetDuration());
|
||||
CalculateBoneTransform(&m_CurrentAnimation->GetRootNode(), glm::mat4(1.0f));
|
||||
currentTime += currentAnimation->GetTicksPerSecond() * deltaTime;
|
||||
currentTime = fmod(currentTime, currentAnimation->GetDuration());
|
||||
CalculateBoneTransform(¤tAnimation->GetRootNode(), glm::mat4(1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
void PlayAnimation(Animation* pAnimation)
|
||||
{
|
||||
m_CurrentAnimation = pAnimation;
|
||||
m_CurrentTime = 0.0f;
|
||||
currentAnimation = pAnimation;
|
||||
currentTime = 0.0f;
|
||||
}
|
||||
|
||||
void CalculateBoneTransform(const AssimpNodeData* node, glm::mat4 parentTransform)
|
||||
|
@ -44,22 +46,22 @@ public:
|
|||
std::string nodeName = node->name;
|
||||
glm::mat4 nodeTransform = node->transformation;
|
||||
|
||||
Bone* Bone = m_CurrentAnimation->FindBone(nodeName);
|
||||
Bone* Bone = currentAnimation->FindBone(nodeName);
|
||||
|
||||
if (Bone)
|
||||
{
|
||||
Bone->Update(m_CurrentTime);
|
||||
Bone->Update(currentTime);
|
||||
nodeTransform = Bone->GetLocalTransform();
|
||||
}
|
||||
|
||||
glm::mat4 globalTransformation = parentTransform * nodeTransform;
|
||||
|
||||
auto boneInfoMap = m_CurrentAnimation->GetBoneIDMap();
|
||||
auto boneInfoMap = currentAnimation->GetBoneIDMap();
|
||||
if (boneInfoMap.find(nodeName) != boneInfoMap.end())
|
||||
{
|
||||
int index = boneInfoMap[nodeName].id;
|
||||
glm::mat4 offset = boneInfoMap[nodeName].offset;
|
||||
m_FinalBoneMatrices[index] = globalTransformation * offset;
|
||||
finalBoneMatrices[index] = globalTransformation * offset;
|
||||
}
|
||||
|
||||
for (int i = 0; i < node->childrenCount; i++)
|
||||
|
@ -68,13 +70,19 @@ public:
|
|||
|
||||
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:
|
||||
std::vector<glm::mat4> m_FinalBoneMatrices;
|
||||
Animation* m_CurrentAnimation;
|
||||
float m_CurrentTime;
|
||||
float m_DeltaTime;
|
||||
|
||||
GladGLContext* gl;
|
||||
std::vector<glm::mat4> finalBoneMatrices;
|
||||
GLuint finalBonesMatricesUBO;
|
||||
Animation* currentAnimation;
|
||||
float currentTime;
|
||||
};
|
||||
|
|
|
@ -20,7 +20,7 @@ public:
|
|||
// Default camera values
|
||||
static constexpr float YAW = -90.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 ZOOM = 45.0f;
|
||||
// camera Attributes
|
||||
|
@ -40,7 +40,7 @@ public:
|
|||
float Zoom;
|
||||
float Ratio;
|
||||
float NearPlane = 0.1f;
|
||||
float FarPlane = 1000.f;
|
||||
float FarPlane = 100.f;
|
||||
|
||||
// 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);
|
||||
|
|
|
@ -78,39 +78,27 @@ glm::mat4 Light::getLightSpaceMatrix(const float nearPlane, const float farPlane
|
|||
minZ = std::min(minZ, -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());
|
||||
|
||||
}
|
||||
//qDebug() << minZ;
|
||||
// Tune this parameter according to the scene
|
||||
/* constexpr float zMult = 10.0f;
|
||||
if (minZ < 0)
|
||||
std::vector<glm::vec3> aabbVertexs;
|
||||
auto& [minPos, maxPos] = sceneAABB;
|
||||
aabbVertexs.emplace_back(minPos.x, minPos.y, minPos.z);
|
||||
aabbVertexs.emplace_back(minPos.x, minPos.y, maxPos.z);
|
||||
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);
|
||||
frustumSizes.push_back(std::max(maxX - minX, maxY - minY));
|
||||
|
|
|
@ -11,11 +11,12 @@
|
|||
class Light
|
||||
{
|
||||
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;
|
||||
float blendRatio = 0.3;
|
||||
std::vector<float> frustumSizes;
|
||||
Model* model = nullptr;
|
||||
std::pair<glm::vec3, glm::vec3> sceneAABB;
|
||||
|
||||
Light(Camera* camera);
|
||||
std::vector<glm::vec4> getFrustumCornersWorldSpace(const glm::mat4& projview);
|
||||
std::vector<glm::vec4> getFrustumCornersWorldSpace(const glm::mat4& proj, const glm::mat4& view);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "MainWindow.h"
|
||||
#include "IblUtils.h"
|
||||
#include "RenderPass.h"
|
||||
#include "World.h"
|
||||
|
||||
MainWindow::MainWindow()
|
||||
: 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)
|
||||
{
|
||||
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)
|
||||
camera.processKeyboard(DOWN, deltaTime);
|
||||
|
||||
glm::mat4 transform(1);
|
||||
static glm::mat4 transform(1);
|
||||
float speed = 1;
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
|
@ -145,9 +246,9 @@ void MainWindow::mouseCallback(GLFWwindow* window, double xpos, double ypos)
|
|||
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS)
|
||||
{
|
||||
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));
|
||||
modelPtr->setTransform(rotate);
|
||||
//modelPtr->setTransform(rotate);
|
||||
}
|
||||
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS)
|
||||
camera.processMouseMovement(xoffset, yoffset);
|
||||
|
@ -164,97 +265,7 @@ MainWindow& MainWindow::instance()
|
|||
return window;
|
||||
}
|
||||
|
||||
int MainWindow::exec()
|
||||
GladGLContext* MainWindow::getGLContext()
|
||||
{
|
||||
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, "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();
|
||||
}
|
||||
return instance().gl.get();
|
||||
}
|
|
@ -10,6 +10,7 @@ class MainWindow
|
|||
{
|
||||
public:
|
||||
static MainWindow& instance();
|
||||
static GladGLContext* getGLContext();
|
||||
int exec();
|
||||
|
||||
private:
|
||||
|
@ -24,7 +25,6 @@ private:
|
|||
unsigned int frameWidth;
|
||||
unsigned int frameHeight;
|
||||
|
||||
Model* modelPtr = nullptr;
|
||||
Camera camera;
|
||||
Light light;
|
||||
glm::vec3 mainLightRadiance = 40.f * glm::normalize(glm::vec3(0.7529, 0.7450, 0.6784));
|
||||
|
|
|
@ -20,8 +20,17 @@ void Model::draw(Shader& shader)
|
|||
|
||||
void Model::setTransform(const glm::mat4& trans)
|
||||
{
|
||||
auto inverse = glm::inverse(transform);
|
||||
transform = trans;
|
||||
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)
|
||||
|
@ -38,17 +47,9 @@ void Model::loadModel(std::string const& path)
|
|||
}
|
||||
|
||||
aiMatrix4x4 transform;
|
||||
aiMatrix4x4::Scaling(aiVector3D(10), transform);
|
||||
//aiMatrix4x4::Scaling(aiVector3D(10), transform);
|
||||
//aiMatrix4x4::Rotation(glm::radians(-90.f), { 1,0,0 }, transform);
|
||||
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)
|
||||
|
@ -56,7 +57,7 @@ void Model::processNode(aiNode* node, const aiScene* scene, aiMatrix4x4 mat4)
|
|||
for (unsigned int i = 0; i < node->mNumMeshes; i++)
|
||||
if (auto mesh = processMesh(scene->mMeshes[node->mMeshes[i]], scene, mat4))
|
||||
meshes.emplace_back(std::move(mesh));
|
||||
|
||||
|
||||
for (unsigned int i = 0; i < node->mNumChildren; i++)
|
||||
processNode(node->mChildren[i], scene, mat4 * node->mChildren[i]->mTransformation);
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ struct BoneInfo
|
|||
class Model
|
||||
{
|
||||
public:
|
||||
std::vector<glm::vec3> AABB;
|
||||
glm::mat4 transform = glm::mat4(1);
|
||||
std::vector<std::unique_ptr<Mesh>> meshes;
|
||||
std::map<std::string, BoneInfo> boneInfoMap;
|
||||
int boneCount = 0;
|
||||
|
@ -29,6 +29,7 @@ public:
|
|||
Model(GladGLContext* gl, std::string const& path);
|
||||
void draw(Shader& shader);
|
||||
void setTransform(const glm::mat4& trans);
|
||||
std::pair<glm::vec3, glm::vec3> getAABB();
|
||||
private:
|
||||
GladGLContext* gl;
|
||||
std::filesystem::path directory; /// 模型所在路径
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
#include "IblUtils.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)
|
||||
, modelShadowShader(gl, "Shaders/model_shadow.vert", "Shaders/model_shadow.frag", "Shaders/model_shadow.geom")
|
||||
, shadowFboHandle(shadowFboHandle)
|
||||
, shadowMapResolution(shadowMapResolution)
|
||||
, model(model)
|
||||
, world(world)
|
||||
, light(light)
|
||||
{
|
||||
gl->CreateBuffers(1, &lightSpaceMatricesUBO);
|
||||
|
@ -24,26 +24,22 @@ void ShadowMapPass::dispatch()
|
|||
gl->Viewport(0, 0, shadowMapResolution, shadowMapResolution);
|
||||
gl->Clear(GL_DEPTH_BUFFER_BIT);
|
||||
modelShadowShader.use();
|
||||
model.draw(modelShadowShader);
|
||||
world.draw(modelShadowShader);
|
||||
modelShadowShader.release();
|
||||
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)
|
||||
, modelShader(gl, "Shaders/model.vert", "Shaders/model.frag")
|
||||
, plainShader(gl, "Shaders/plain.vert", "Shaders/plain.frag")
|
||||
, frameWidth(frameWidth)
|
||||
, frameHeight(frameHeight)
|
||||
, fbo(fbo)
|
||||
, model(model)
|
||||
, world(world)
|
||||
, projection(projection)
|
||||
, 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()
|
||||
|
@ -55,9 +51,7 @@ void GeometryPass::dispatch()
|
|||
modelShader.use();
|
||||
modelShader.setUniformValue("projection", projection);
|
||||
modelShader.setUniformValue("view", view);
|
||||
auto boneMatrices = animator.GetFinalBoneMatrices();
|
||||
gl->NamedBufferSubData(finalBonesMatricesUBO, 0, boneMatrices.size() * sizeof(boneMatrices[0]), boneMatrices.data());
|
||||
model.draw(modelShader);
|
||||
world.draw(modelShader);
|
||||
modelShader.release();
|
||||
|
||||
/// Debug Lighting
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include <glad/gl.h>
|
||||
#include "Shader.h"
|
||||
#include "Model.h"
|
||||
#include "World.h"
|
||||
#include "Light.h"
|
||||
#include <array>
|
||||
#include "Animator.h"
|
||||
|
@ -18,13 +18,13 @@ protected:
|
|||
class ShadowMapPass : public RenderPass
|
||||
{
|
||||
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();
|
||||
private:
|
||||
Shader modelShadowShader;
|
||||
GLuint& shadowFboHandle;
|
||||
int& shadowMapResolution;
|
||||
Model& model;
|
||||
World& world;
|
||||
Light& light;
|
||||
GLuint lightSpaceMatricesUBO;
|
||||
};
|
||||
|
@ -33,7 +33,7 @@ class GeometryPass : public RenderPass
|
|||
{
|
||||
public:
|
||||
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();
|
||||
private:
|
||||
Shader modelShader;
|
||||
|
@ -42,10 +42,9 @@ private:
|
|||
unsigned int& frameWidth;
|
||||
unsigned int& frameHeight;
|
||||
GLuint& fbo;
|
||||
Model& model;
|
||||
World& world;
|
||||
glm::mat4& projection;
|
||||
glm::mat4& view;
|
||||
Animator& animator;
|
||||
};
|
||||
|
||||
class LightingPass : public RenderPass
|
||||
|
|
|
@ -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 };
|
||||
}
|
|
@ -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();
|
||||
};
|
||||
|
Loading…
Reference in New Issue