diff --git a/Game/src/MainState.cpp b/Game/src/MainState.cpp index bbf5ab6..08ea381 100644 --- a/Game/src/MainState.cpp +++ b/Game/src/MainState.cpp @@ -13,7 +13,7 @@ void MainState::onEnter() { text.centered(true); uiTex.create(nf::BaseAssets::logo, nf::Vec2(0.025, 0.025), 0.5); button.create(nf::Vec2(0.8, 0.025), "Reset"); - light.create(nf::Vec3(0.0, 5.0, 0.0), nf::Vec3(1.0, 1.0, 1.0)); + light.create(nf::Vec3(5.0, 300.0, 100.0), nf::Vec3(1.0, 1.0, 1.0), 1.5, nf::Light::Type::DIRECTIONAL); cm.create(nf::BaseAssets::cubemap); } @@ -48,7 +48,7 @@ void MainState::update(double deltaTime) { xrot += offset; if (app->isKeyHeld(NFI_RIGHT)) xrot -= offset; - test.setRotation(-yrot, -xrot, 0.0); + test.setPosition(-xrot / 10.0, 0.0, -yrot / 10.0 - 5.0); text.setText("FPS: " + std::to_string(app->getFPS())); @@ -61,10 +61,10 @@ void MainState::update(double deltaTime) { void MainState::render(nf::Renderer& renderer) { renderer.render(test); renderer.render(plane); + renderer.render(light); renderer.render(text); renderer.render(uiTex); renderer.render(button); - renderer.render(light); renderer.render(cm); } diff --git a/NFPackCreator/AssetBuild/base/shaders/entityFragment.shader b/NFPackCreator/AssetBuild/base/shaders/entityFragment.shader index 023f976..9745a89 100644 --- a/NFPackCreator/AssetBuild/base/shaders/entityFragment.shader +++ b/NFPackCreator/AssetBuild/base/shaders/entityFragment.shader @@ -3,6 +3,7 @@ in vec2 texCoord; in vec3 normals; in vec3 fragPos; +in vec4 fragPosLightSpace[16]; struct Camera { vec3 pos; @@ -23,6 +24,7 @@ struct Light { vec3 pos; vec3 color; float strength; + sampler2D depthTex; }; uniform Camera camera; @@ -33,6 +35,26 @@ uniform bool isContinued; out vec4 outColor; +float calcShadow(int lightNum, vec4 fragPosLight, vec3 no, vec3 lDir) { + vec3 fp = fragPosLight.xyz / fragPosLight.w; + fp = fp * 0.5 + 0.5; + float current = fp.z; + float bias = max(0.05 * (1.0 - dot(no, lDir)), 0.005); + float shad = 0.0f; + vec2 texSize = 1.0 / textureSize(light[lightNum].depthTex, 0); + + for (int x = -1; x <= 1; x++) { + for (int y = -1; y <= 1; y++) { + float pcfDepth = texture(light[lightNum].depthTex, fp.xy + vec2(x, y) * texSize).r; + shad += current - bias > pcfDepth ? 1.0 : 0.0; + } + } + shad /= 9.0; + if (current > 1.0) + shad = 0.0; + return shad; +} + void main() { vec3 color = vec3(0.0); @@ -46,7 +68,7 @@ void main() { if (material.hasSpecTex) matSpec = texture(material.specularTexture, texCoord).rgb; - float ambientStrength = 0.5f; + float ambientStrength = 0.2f; vec3 ambient = ambientStrength * matDiff; if (!isContinued) color += ambient; @@ -56,7 +78,7 @@ void main() { } if (light[i].type == 1) { - vec3 lightDir = normalize(-light[i].pos); + vec3 lightDir = normalize(light[i].pos - fragPos); vec3 norm = normalize(normals); float diff = max(dot(norm, lightDir), 0.0); vec3 diffuse = light[i].color * (diff * matDiff) * (light[i].strength / 2.0f); @@ -66,7 +88,8 @@ void main() { float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.specPower); vec3 specular = light[i].color * spec * matSpec * (light[i].strength / 2.0f); - color += (ambient + diffuse + specular); + float shadow = calcShadow(i, fragPosLightSpace[i], norm, lightDir); + color += (diffuse + specular) * (1.0 - shadow); continue; } if (light[i].type == 2) { diff --git a/NFPackCreator/AssetBuild/base/shaders/entityVertex.shader b/NFPackCreator/AssetBuild/base/shaders/entityVertex.shader index 75409f3..f08f9b2 100644 --- a/NFPackCreator/AssetBuild/base/shaders/entityVertex.shader +++ b/NFPackCreator/AssetBuild/base/shaders/entityVertex.shader @@ -7,15 +7,20 @@ layout(location = 2) in vec3 normal; uniform mat4 model; uniform mat4 view; uniform mat4 proj; +uniform mat4 lightSpaceMat[16]; +uniform int numMats; out vec2 texCoord; out vec3 normals; out vec3 fragPos; +out vec4 fragPosLightSpace[16]; void main() { texCoord = texCoords; normals = mat3(transpose(inverse(model))) * normal; fragPos = vec3(model * vec4(pos, 1.0)); - - gl_Position = proj * view * model * vec4(pos, 1.0); + for (int i = 0; i < numMats; i++) { + fragPosLightSpace[i] = lightSpaceMat[i] * vec4(fragPos, 1.0); + } + gl_Position = proj * view * vec4(fragPos, 1.0); } \ No newline at end of file diff --git a/NFPackCreator/AssetBuild/base/shaders/shadow/directionalShadowFragment.shader b/NFPackCreator/AssetBuild/base/shaders/shadow/directionalShadowFragment.shader new file mode 100644 index 0000000..78c61e5 --- /dev/null +++ b/NFPackCreator/AssetBuild/base/shaders/shadow/directionalShadowFragment.shader @@ -0,0 +1,5 @@ +#version 330 core + +void main() { + +} \ No newline at end of file diff --git a/NFPackCreator/AssetBuild/base/shaders/shadow/directionalShadowVertex.shader b/NFPackCreator/AssetBuild/base/shaders/shadow/directionalShadowVertex.shader new file mode 100644 index 0000000..d22deb7 --- /dev/null +++ b/NFPackCreator/AssetBuild/base/shaders/shadow/directionalShadowVertex.shader @@ -0,0 +1,12 @@ +#version 330 core + +layout(location = 0) in vec3 pos; + +uniform mat4 lightSpace; +uniform mat4 model; + +out vec3 texCoord; + +void main() { + gl_Position = lightSpace * model * vec4(pos, 1.0); +} \ No newline at end of file diff --git a/NothinFancy/src/Renderer/Drawable/Entity.cpp b/NothinFancy/src/Renderer/Drawable/Entity.cpp index 0a222a6..9516395 100644 --- a/NothinFancy/src/Renderer/Drawable/Entity.cpp +++ b/NothinFancy/src/Renderer/Drawable/Entity.cpp @@ -66,10 +66,10 @@ namespace nf { m_scale = scale; } - void Entity::render(Shader* shader) { + void Entity::render(Shader* shader, bool onlyDepth) { shader->bind(); setModelMatrix(shader); - m_model->render(shader); + m_model->render(shader, onlyDepth); } Model* Entity::getModel() const { diff --git a/NothinFancy/src/Renderer/Drawable/Model.cpp b/NothinFancy/src/Renderer/Drawable/Model.cpp index 7249189..60505f4 100644 --- a/NothinFancy/src/Renderer/Drawable/Model.cpp +++ b/NothinFancy/src/Renderer/Drawable/Model.cpp @@ -40,26 +40,28 @@ namespace nf { m_shininess = shininess; } - void Material::render(Shader* shader) { + void Material::render(Shader* shader, bool onlyDepth) { m_vao->bind(); m_ib->bind(); - if (m_hasDiffuse) { - shader->setUniform("material.hasDiffuseTex", true); - m_diffuseTexture->bind(); + if (!onlyDepth) { + if (m_hasDiffuse) { + shader->setUniform("material.hasDiffuseTex", true); + m_diffuseTexture->bind(); + } + else { + shader->setUniform("material.hasDiffuseTex", false); + glm::vec3 color(m_diffColor.x, m_diffColor.y, m_diffColor.z); + shader->setUniform("material.diffuseColor", color); + } + if (m_hasSpecular) { + shader->setUniform("material.hasSpecTex", true); + m_specularTexture->bind(1); + shader->setUniform("material.specularTexture", 1); + } + else + shader->setUniform("material.hasSpecTex", false); + shader->setUniform("material.specPower", m_shininess); } - else { - shader->setUniform("material.hasDiffuseTex", false); - glm::vec3 color(m_diffColor.x, m_diffColor.y, m_diffColor.z); - shader->setUniform("material.diffuseColor", color); - } - if (m_hasSpecular) { - shader->setUniform("material.hasSpecTex", true); - m_specularTexture->bind(1); - shader->setUniform("material.specularTexture", 1); - } - else - shader->setUniform("material.hasSpecTex", false); - shader->setUniform("material.specPower", m_shininess); glDrawElements(GL_TRIANGLES, m_ib->getCount(), GL_UNSIGNED_INT, nullptr); } @@ -281,9 +283,9 @@ namespace nf { } } - void Model::render(Shader* shader) { + void Model::render(Shader* shader, bool onlyDepth) { for (Material* curr : m_materials) { - curr->render(shader); + curr->render(shader, onlyDepth); } } diff --git a/NothinFancy/src/Renderer/Renderer.cpp b/NothinFancy/src/Renderer/Renderer.cpp index ec617ad..af371b0 100644 --- a/NothinFancy/src/Renderer/Renderer.cpp +++ b/NothinFancy/src/Renderer/Renderer.cpp @@ -17,6 +17,7 @@ namespace nf { Renderer::Renderer(Application* app) : + m_shadowMapFBO(0), m_cubemap(nullptr), m_fadeIn(false), m_fadeOut(false), @@ -70,6 +71,8 @@ namespace nf { loadBaseAssets(); + createShadowMap(); + if (!m_app->isCustomWindowIcon()) { ATexture& windowTex = *(ATexture*)m_baseAP["defaultwindowicon.png"]; int width, height, nChannels; @@ -138,23 +141,23 @@ namespace nf { void Renderer::doFrame(Camera* camera, double dT) { //Begin frame - glViewport(0, 0, m_app->getConfig().width, m_app->getConfig().height); + glBindFramebuffer(GL_FRAMEBUFFER, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); camera->bind(m_entityShader, m_cubemapShader); //Draw Entities (3D models) - glm::mat4 proj = glm::perspective(glm::radians(45.0f), (float)m_app->getConfig().width / (float)m_app->getConfig().height, 0.1f, 100000.0f); + glm::mat4 proj = glm::perspective(glm::radians(45.0f), (float)m_app->getConfig().width / (float)m_app->getConfig().height, 0.1f, 10000.0f); m_entityShader->bind(); m_entityShader->setUniform("proj", proj); for (Entity* draw : m_lGame) { Entity& curr = *draw; - unsigned int drawCount = (unsigned int)std::ceil(m_lights.size() / 100.0); + unsigned int drawCount = (unsigned int)std::ceil(m_lights.size() / (double)m_texSlots); if (drawCount == 0) drawCount++; unsigned int lightsRemaining = m_lights.size(); int currLight; - if (lightsRemaining > 100) - currLight = -100; + if (lightsRemaining > m_texSlots) + currLight = -(int)m_texSlots; else currLight = -(int)lightsRemaining; for (unsigned int i = 0; i < drawCount; i++) { @@ -166,8 +169,8 @@ namespace nf { m_entityShader->setUniform("isContinued", true); } unsigned int currLightsDrawn; - if (lightsRemaining >= 100) - currLightsDrawn = 100; + if (lightsRemaining >= m_texSlots) + currLightsDrawn = m_texSlots; else currLightsDrawn = lightsRemaining; lightsRemaining -= currLightsDrawn; @@ -176,6 +179,9 @@ namespace nf { for (unsigned int j = 0; j < currLightsDrawn; j++) { m_lights[j + (unsigned int)currLight]->bind(m_entityShader, j); } + renderShadowMaps(currLight, currLightsDrawn); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glViewport(0, 0, m_app->getConfig().width, m_app->getConfig().height); curr.render(m_entityShader); } glDepthFunc(GL_LESS); @@ -261,6 +267,40 @@ namespace nf { Error("OpenGL error " + std::to_string(err)); } + void Renderer::renderShadowMaps(unsigned int startingLight, unsigned int count) { + glViewport(0, 0, 4096, 4096); + float nearP = 0.1f, farP = 500.0f; + glm::mat4 lightProj = glm::ortho(-50.0f, 50.0f, -50.0f, 50.0f, nearP, farP); + glm::mat4 lightView; + glm::mat4 lightSpaceMat; + glBindFramebuffer(GL_FRAMEBUFFER, m_shadowMapFBO); + for (unsigned int i = 0; i < count; i++) { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_shadowMaps[i], 0); + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + glClear(GL_DEPTH_BUFFER_BIT); + Vec3 posTemp = m_lights[startingLight + i]->getPosition(); + glm::vec3 posTemp2(posTemp.x, posTemp.y, posTemp.z); + lightView = glm::lookAt(posTemp2, glm::vec3(0.0), glm::vec3(0.0, 1.0, 0.0)); + lightSpaceMat = lightProj * lightView; + m_directionalShadowShader->setUniform("lightSpace", lightSpaceMat); + std::string stringPos = "lightSpaceMat["; + stringPos += std::to_string(i); + stringPos += "]"; + m_entityShader->setUniform(stringPos, lightSpaceMat); + for (Entity* curr : m_lGame) { + curr->render(m_directionalShadowShader, true); + } + stringPos = "light["; + stringPos += std::to_string(i); + stringPos += "].depthTex"; + glActiveTexture(GL_TEXTURE3 + i); + glBindTexture(GL_TEXTURE_2D, m_shadowMaps[i]); + m_entityShader->setUniform(stringPos, 3 + (int)i); + } + m_entityShader->setUniform("numMats", (int)count); + } + void Renderer::loadBaseAssets() { m_baseAP.load("base.nfpack"); const char* entityVertex = m_baseAP["entityVertex.shader"]->data; @@ -278,6 +318,9 @@ namespace nf { const char* fadeVertex = m_baseAP["fadeVertex.shader"]->data; const char* fadeFragment = m_baseAP["fadeFragment.shader"]->data; m_fadeShader = new Shader(fadeVertex, fadeFragment); + const char* directionalShadowVertex = m_baseAP["directionalShadowVertex.shader"]->data; + const char* directionalShadowFragment = m_baseAP["directionalShadowFragment.shader"]->data; + m_directionalShadowShader = new Shader(directionalShadowVertex, directionalShadowFragment); BaseAssets::cube = (AModel*)m_baseAP["cube.obj"]; BaseAssets::plane = (AModel*)m_baseAP["plane.obj"]; @@ -291,12 +334,33 @@ namespace nf { BaseAssets::button = (AButton*)m_baseAP["default.button"]; } + void Renderer::createShadowMap() { + m_texSlots = 16; + glGenFramebuffers(1, &m_shadowMapFBO); + glBindFramebuffer(GL_FRAMEBUFFER, m_shadowMapFBO); + for (unsigned int i = 0; i < m_texSlots; i++) { + unsigned int depthMap; + glGenTextures(1, &depthMap); + glBindTexture(GL_TEXTURE_2D, depthMap); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 4096, 4096, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + float borderColor[] = { 1.0f, 1.0f, 1.0f, 1.0f }; + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); + m_shadowMaps.push_back(depthMap); + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + Renderer::~Renderer() { delete m_entityShader; delete m_textShader; delete m_uiTextureShader; delete m_cubemapShader; delete m_fadeShader; + delete m_directionalShadowShader; delete m_fadeVAO; delete m_fadeIB; ReleaseDC(m_app->getWindow(), m_hdc); diff --git a/NothinFancy/src/include/Entity.h b/NothinFancy/src/include/Entity.h index 52178dd..901b22f 100644 --- a/NothinFancy/src/include/Entity.h +++ b/NothinFancy/src/include/Entity.h @@ -22,7 +22,7 @@ namespace nf { void setScale(double x, double y, double z); void setScale(const Vec3& scale); - void render(Shader* shader); + void render(Shader* shader, bool onlyDepth = false); Model* getModel() const; void destroy() override; diff --git a/NothinFancy/src/include/Model.h b/NothinFancy/src/include/Model.h index a12ef23..6790c42 100644 --- a/NothinFancy/src/include/Model.h +++ b/NothinFancy/src/include/Model.h @@ -12,7 +12,7 @@ namespace nf { public: Material(const void* vb, const size_t vbSize, const void* tc, const size_t tcSize, const void* vn, const size_t vnSize, const void* ib, const unsigned int ibCount, ATexture* diffTex, Vec3& diffColor, ATexture* specTex, float shininess); - void render(Shader* shader); + void render(Shader* shader, bool onlyDepth); ~Material(); private: @@ -28,7 +28,7 @@ namespace nf { public: Model(AModel* model); - void render(Shader* shader); + void render(Shader* shader, bool onlyDepth); bool isBaseAsset(); diff --git a/NothinFancy/src/include/NothinFancy.h b/NothinFancy/src/include/NothinFancy.h index f4896fe..992ee14 100644 --- a/NothinFancy/src/include/NothinFancy.h +++ b/NothinFancy/src/include/NothinFancy.h @@ -39,6 +39,11 @@ namespace nf { ~Renderer(); private: + void renderShadowMaps(unsigned int startingLight, unsigned int count); + + void loadBaseAssets(); + void createShadowMap(); + Application* m_app; HDC m_hdc; @@ -46,6 +51,10 @@ namespace nf { AssetPack m_baseAP; + unsigned int m_shadowMapFBO; + std::vector m_shadowMaps; + unsigned int m_texSlots; + std::vector m_lights; std::vector m_lGame; Cubemap* m_cubemap; @@ -55,6 +64,7 @@ namespace nf { Shader* m_uiTextureShader; Shader* m_cubemapShader; Shader* m_fadeShader; + Shader* m_directionalShadowShader; bool m_fadeIn, m_fadeOut; bool m_fadeNoText; diff --git a/NothinFancy/src/include/Renderer.h b/NothinFancy/src/include/Renderer.h index db96c61..440a848 100644 --- a/NothinFancy/src/include/Renderer.h +++ b/NothinFancy/src/include/Renderer.h @@ -32,7 +32,10 @@ namespace nf { ~Renderer(); private: + void renderShadowMaps(unsigned int startingLight, unsigned int count); + void loadBaseAssets(); + void createShadowMap(); Application* m_app; @@ -41,6 +44,10 @@ namespace nf { AssetPack m_baseAP; + unsigned int m_shadowMapFBO; + std::vector m_shadowMaps; + unsigned int m_texSlots; + std::vector m_lights; std::vector m_lGame; Cubemap* m_cubemap; @@ -50,6 +57,7 @@ namespace nf { Shader* m_uiTextureShader; Shader* m_cubemapShader; Shader* m_fadeShader; + Shader* m_directionalShadowShader; bool m_fadeIn, m_fadeOut; bool m_fadeNoText;