/* * Copyright (C) 2017 Christopher J. Howard * * This file is part of Antkeeper Source Code. * * Antkeeper Source Code is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Antkeeper Source Code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Antkeeper Source Code. If not, see . */ #include "render-passes.hpp" #include "materials.hpp" #include #include ClearRenderPass::ClearRenderPass(): clearColor(true), clearDepth(true), clearStencil(true), color(0.0f), depth(1.0f), index(0) {} bool ClearRenderPass::load(const RenderContext* renderContext) { return true; } void ClearRenderPass::unload() {} void ClearRenderPass::render(RenderContext* renderContext) { glBindFramebuffer(GL_FRAMEBUFFER, renderTarget->framebuffer); GLbitfield mask = 0; if (clearColor) { mask |= GL_COLOR_BUFFER_BIT; glClearColor(color[0], color[1], color[2], color[3]); } if (clearDepth) { mask |= GL_DEPTH_BUFFER_BIT; glClearDepth(depth); } if (clearStencil) { mask |= GL_STENCIL_BUFFER_BIT; glClearStencil(index); } glClear(mask); } void ClearRenderPass::setClear(bool color, bool depth, bool stencil) { clearColor = color; clearDepth = depth; clearStencil = stencil; } void ClearRenderPass::setClearColor(const Vector4& color) { this->color = color; } void ClearRenderPass::setClearDepth(float depth) { this->depth = depth; } void ClearRenderPass::setClearStencil(int index) { this->index = index; } ShadowMapRenderPass::ShadowMapRenderPass(): unskinnedShader(nullptr), skinnedShader(nullptr), croppedShadowMapViewports(nullptr), viewCamera(nullptr), splitViewFrustum(nullptr), cropMatrices(nullptr), tileMatrices(nullptr) {} bool ShadowMapRenderPass::load(const RenderContext* renderContext) { // Set maximum number of bones for skinned meshes maxBoneCount = 64; // Set number of frustum splits frustumSplitCount = 4; // Create split view frustum splitViewFrustum = new SplitViewFrustum(frustumSplitCount); // Determine resolution of shadow maps shadowMapResolution = 4096; croppedShadowMapResolution = shadowMapResolution >> 1; // Allocate viewports croppedShadowMapViewports = new Vector4[frustumSplitCount]; // Setup viewports for (int i = 0; i < frustumSplitCount; ++i) { int x = i % 2; int y = i / 2; Vector4* viewport = &croppedShadowMapViewports[i]; (*viewport)[0] = static_cast(x * croppedShadowMapResolution); (*viewport)[1] = static_cast(y * croppedShadowMapResolution); (*viewport)[2] = static_cast(croppedShadowMapResolution); (*viewport)[3] = static_cast(croppedShadowMapResolution); } // Allocate matrices cropMatrices = new Matrix4[frustumSplitCount]; tileMatrices = new Matrix4[frustumSplitCount]; // Setup tile matrices Matrix4 tileScale = glm::scale(Vector3(0.5f, 0.5f, 1.0f)); for (int i = 0; i < frustumSplitCount; ++i) { float x = static_cast(i % 2) * 0.5f; float y = static_cast(i / 2) * 0.5f; tileMatrices[i] = glm::translate(Vector3(x, y, 0.0f)) * tileScale; } // Setup shader parameters modelViewProjectionParam = parameterSet.addParameter("modelViewProjectionMatrix", ShaderParameter::Type::MATRIX_4, 1); matrixPaletteParam = parameterSet.addParameter("matrixPalette", ShaderParameter::Type::MATRIX_4, maxBoneCount); // Load unskinned shader shaderLoader.undefine(); shaderLoader.define("VERTEX_POSITION", EMERGENT_VERTEX_POSITION); unskinnedShader = shaderLoader.load("data/shaders/depth-pass.glsl", ¶meterSet); if (!unskinnedShader) { return false; } // Load skinned shader shaderLoader.define("SKINNED"); shaderLoader.define("VERTEX_BONE_INDICES", EMERGENT_VERTEX_BONE_INDICES); shaderLoader.define("VERTEX_BONE_WEIGHTS", EMERGENT_VERTEX_BONE_WEIGHTS); shaderLoader.define("MAX_BONE_COUNT", maxBoneCount); skinnedShader = shaderLoader.load("data/shaders/depth-pass.glsl", ¶meterSet); if (!skinnedShader) { return false; } return true; } void ShadowMapRenderPass::unload() { delete unskinnedShader; unskinnedShader = nullptr; delete skinnedShader; skinnedShader = nullptr; delete[] croppedShadowMapViewports; croppedShadowMapViewports = nullptr; delete splitViewFrustum; splitViewFrustum = nullptr; delete[] cropMatrices; cropMatrices = nullptr; delete[] tileMatrices; tileMatrices = nullptr; parameterSet.removeParameters(); } void ShadowMapRenderPass::render(RenderContext* renderContext) { // Bind framebuffer and setup viewport glBindFramebuffer(GL_FRAMEBUFFER, renderTarget->framebuffer); glViewport(0, 0, renderTarget->width, renderTarget->height); // Clear the framebuffer depth glClear(GL_DEPTH_BUFFER_BIT); // Enable depth testing glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glDepthFunc(GL_LESS); // Draw front and back faces glDisable(GL_CULL_FACE); // Disable alpha blending glDisable(GL_BLEND); //const Camera& lightCamera = *(renderContext->camera); const std::list* operations = renderContext->queue->getOperations(); Shader* shader = nullptr; // Update split view frustum //splitViewFrustum->setMatrices(viewCamera->getView(), viewCamera->getProjection()); const ViewFrustum& viewFrustum = viewCamera->getViewFrustum(); // Find center of view frustum Vector3 center = Vector3(0.0f); for (std::size_t i = 0; i < viewFrustum.getCornerCount(); ++i) { center += viewFrustum.getCorner(i); } center = center * 1.0f / static_cast(viewFrustum.getCornerCount()); // Position light camera in center of view frustum //lightCamera->lookAt(center, center + lightCamera->getForward(), lightCamera->getUp()); // Calculate split distances float clipNear = viewCamera->getClipNear(); float clipFar = viewCamera->getClipFar(); float* splitDistances = new float[frustumSplitCount + 1]; float splitSchemeWeight = 0.5f; for (std::size_t i = 1; i < frustumSplitCount; ++i) { float part = static_cast(i) / static_cast(frustumSplitCount); // Calculate uniform split distance float uniformSplitDistance = clipNear + (clipFar - clipNear) * part; // Calculate logarithmic split distance float logSplitDistance = clipNear * std::pow(clipFar / clipNear, part); // Interpolate between uniform and logarithmic split distances splitDistances[i] = logSplitDistance * splitSchemeWeight + uniformSplitDistance * (1.0f - splitSchemeWeight); } splitDistances[0] = clipNear; splitDistances[frustumSplitCount] = clipFar; // For each frustum split for (int i = 0; i < frustumSplitCount; ++i) { // Calculate crop matrix { ViewFrustum frustumSplit; // Determine near and far distances for this subfrustum float splitNear = splitDistances[0]; float splitFar = splitDistances[4]; // Calculate subfrustum projection matrix Matrix4 splitProjection = glm::ortho(viewCamera->getClipLeft(), viewCamera->getClipRight(), viewCamera->getClipBottom(), viewCamera->getClipTop(), splitNear, splitFar); // Set subfrustum matrices frustumSplit.setMatrices(viewCamera->getView(), splitProjection); // Create AABB containing the frustum split corners AABB frustumSplitBounds(Vector3(std::numeric_limits::infinity()), Vector3(-std::numeric_limits::infinity())); for (std::size_t j = 0; j < frustumSplit.getCornerCount(); ++j) { frustumSplitBounds.add(frustumSplit.getCorner(j)); } // Transform frustum split bounds into light's clip space AABB croppingBounds = frustumSplitBounds.transformed(lightCamera->getViewProjection()); Vector3 cropMax = croppingBounds.getMax(); Vector3 cropMin = croppingBounds.getMin(); //cropMin.z = 0.0f; // Calculate scale Vector3 scale; scale.x = 2.0f / (cropMax.x - cropMin.x); scale.y = 2.0f / (cropMax.y - cropMin.y); scale.z = 1.0f / (cropMax.z - cropMin.z); // Quantize scale //float scaleQuantizer = 64.0f; //scale.x = 1.0f / std::ceil(1.0f / scale.x * scaleQuantizer) * scaleQuantizer; //scale.y = 1.0f / std::ceil(1.0f / scale.y * scaleQuantizer) * scaleQuantizer; // Calculate offset Vector3 offset; offset.x = (cropMax.x + cropMin.x) * scale.x * -0.5f; offset.y = (cropMax.y + cropMin.y) * scale.y * -0.5f; offset.z = -cropMin.z * scale.z; // Quantize offset //float halfTextureSize = static_cast(croppedShadowMapResolution) * 0.5f; //offset.x = std::ceil(offset.x * halfTextureSize) / halfTextureSize; //offset.y = std::ceil(offset.y * halfTextureSize) / halfTextureSize; cropMatrices[i] = glm::translate(offset) * glm::scale(scale); } Matrix4 croppedViewProjection = cropMatrices[i] * lightCamera->getViewProjection(); // Activate viewport for corresponding cropped shadow map const Vector4& viewport = croppedShadowMapViewports[i]; glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); // Render operations for (const RenderOperation& operation: *operations) { // Skip render operations with unsupported materials if (operation.material->getMaterialFormatID() != static_cast(MaterialFormat::PHYSICAL)) { continue; } // Skip non shadow casters const PhysicalMaterial* material = static_cast(operation.material); if (!material->shadowCaster) { continue; } // Select shader Shader* targetShader = nullptr; if (operation.pose != nullptr) { targetShader = skinnedShader; } else { targetShader = unskinnedShader; } // Switch shader if necessary if (shader != targetShader) { shader = targetShader; // Bind shader shader->bind(); } // Pass matrix palette if (operation.pose != nullptr) { shader->setParameter(matrixPaletteParam, 0, operation.pose->getMatrixPalette(), operation.pose->getSkeleton()->getBoneCount()); } const Matrix4& modelMatrix = operation.transform; Matrix4 modelViewProjectionMatrix = croppedViewProjection * modelMatrix; shader->setParameter(modelViewProjectionParam, modelViewProjectionMatrix); glBindVertexArray(operation.vao); glDrawElementsBaseVertex(GL_TRIANGLES, operation.triangleCount * 3, GL_UNSIGNED_INT, (void*)0, operation.indexOffset); } } delete[] splitDistances; glBindFramebuffer(GL_FRAMEBUFFER, 0); } ClippingRenderPass::ClippingRenderPass(): shader(nullptr) { clippingPlanesParam = parameterSet.addParameter("clippingPlanes", ShaderParameter::Type::VECTOR_4, 1); modelParam = parameterSet.addParameter("modelMatrix", ShaderParameter::Type::MATRIX_4, 1); modelViewProjectionParam = parameterSet.addParameter("modelViewProjectionMatrix", ShaderParameter::Type::MATRIX_4, 1); } bool ClippingRenderPass::load(const RenderContext* renderContext) { shaderLoader.undefine(); shaderLoader.define("CLIPPING_PLANE_COUNT", 1); shader = shaderLoader.load("data/shaders/clip.glsl", ¶meterSet); if (!shader) { return false; } return true; } void ClippingRenderPass::unload() { delete shader; shader = nullptr; } void ClippingRenderPass::render(RenderContext* renderContext) { glEnable(GL_CLIP_DISTANCE0); glEnable(GL_STENCIL_TEST); glDisable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Bind shader shader->bind(); // Pass clipping planes to shader shader->setParameter(clippingPlanesParam, clippingPlane); // Grab render context parameters const Camera& camera = *(renderContext->camera); const std::list* operations = renderContext->queue->getOperations(); // Two passes for (int i = 0; i < 2; ++i) { if (!i) { // Increment stencil for back faces glStencilFunc(GL_ALWAYS, 0, 0); glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); glCullFace(GL_FRONT); } else { // Decrement stencil for front faces glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); glCullFace(GL_BACK); } for (const RenderOperation& operation: *operations) { const Matrix4& modelMatrix = operation.transform; Matrix4 modelViewProjectionMatrix = camera.getViewProjection() * modelMatrix; shader->setParameter(modelParam, modelMatrix); shader->setParameter(modelViewProjectionParam, modelViewProjectionMatrix); glBindVertexArray(operation.vao); glDrawElementsBaseVertex(GL_TRIANGLES, operation.triangleCount * 3, GL_UNSIGNED_INT, (void*)0, operation.indexOffset); } } glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glDepthFunc(GL_LESS); glDisable(GL_CLIP_DISTANCE0); } void ClippingRenderPass::setClippingPlane(const Plane& plane) { this->clippingPlane = Vector4(plane.getNormal(), plane.getDistance()); } SoilRenderPass::SoilRenderPass(): shader(nullptr) { horizonTexturesParam = parameterSet.addParameter("horizonTextures", ShaderParameter::Type::INT, 4); modelParam = parameterSet.addParameter("modelMatrix", ShaderParameter::Type::MATRIX_4, 1); modelViewProjectionParam = parameterSet.addParameter("modelViewProjectionMatrix", ShaderParameter::Type::MATRIX_4, 1); horizonOTexture = nullptr; horizonATexture = nullptr; horizonBTexture = nullptr; horizonCTexture = nullptr; } bool SoilRenderPass::load(const RenderContext* renderContext) { shaderLoader.define("VERTEX_POSITION", EMERGENT_VERTEX_POSITION); shaderLoader.define("VERTEX_TEXCOORD", EMERGENT_VERTEX_TEXCOORD); shaderLoader.define("VERTEX_NORMAL", EMERGENT_VERTEX_NORMAL); shader = shaderLoader.load("data/shaders/soil-profile.glsl", ¶meterSet); if (!shader) { return false; } return true; } void SoilRenderPass::unload() { shaderLoader.undefine(); delete shader; shader = nullptr; delete horizonOTexture; delete horizonATexture; delete horizonBTexture; delete horizonCTexture; horizonOTexture = nullptr; horizonATexture = nullptr; horizonBTexture = nullptr; horizonCTexture = nullptr; } void SoilRenderPass::render(RenderContext* renderContext) { // Bind framebuffer and setup viewport glBindFramebuffer(GL_FRAMEBUFFER, renderTarget->framebuffer); glViewport(0, 0, renderTarget->width, renderTarget->height); // Bind shader shader->bind(); if (!horizonOTexture || !horizonATexture || !horizonBTexture || !horizonCTexture) { return; } // Bind textures glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, horizonOTexture->getTextureID()); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, horizonATexture->getTextureID()); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, horizonBTexture->getTextureID()); glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, horizonCTexture->getTextureID()); // Pass texture units to shader int textureUnits[] = {0, 1, 2, 3}; shader->setParameter(horizonTexturesParam, 0, &textureUnits[0], 4); // Enable depth testing glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glDepthFunc(GL_LEQUAL); // Enable backface culling glEnable(GL_CULL_FACE); glCullFace(GL_BACK); const Camera& camera = *(renderContext->camera); const std::list* operations = renderContext->queue->getOperations(); // Render operations for (const RenderOperation& operation: *operations) { // Skip render operations with unsupported materials if (operation.material->getMaterialFormatID() != static_cast(MaterialFormat::PHYSICAL)) { continue; } const PhysicalMaterial* material = static_cast(operation.material); if (!(material->flags & (unsigned int)PhysicalMaterial::Flags::SOIL)) { continue; } const Matrix4& modelMatrix = operation.transform; Matrix4 modelViewProjectionMatrix = camera.getViewProjection() * modelMatrix; shader->setParameter(modelParam, modelMatrix); shader->setParameter(modelViewProjectionParam, modelViewProjectionMatrix); glBindVertexArray(operation.vao); glDrawElementsBaseVertex(GL_TRIANGLES, operation.triangleCount * 3, GL_UNSIGNED_INT, (void*)0, operation.indexOffset); } } LightingRenderPass::LightingRenderPass(): shadowMap(0), shadowCamera(nullptr), treeShadow(nullptr), diffuseCubemap(nullptr), specularCubemap(nullptr), shadowMapPass(nullptr) { // Initialize bias matrix for calculating the model-view-projection-bias matrix (used for shadow map texture coordinate calculation) biasMatrix = glm::translate(Vector3(0.5f)) * glm::scale(Vector3(0.5f)); maxBoneCount = 64; matrixPaletteParam = parameterSet.addParameter("matrixPalette", ShaderParameter::Type::MATRIX_4, maxBoneCount); modelParam = parameterSet.addParameter("modelMatrix", ShaderParameter::Type::MATRIX_4, 1); modelViewParam = parameterSet.addParameter("modelViewMatrix", ShaderParameter::Type::MATRIX_4, 1); modelViewProjectionParam = parameterSet.addParameter("modelViewProjectionMatrix", ShaderParameter::Type::MATRIX_4, 1); normalModelViewParam = parameterSet.addParameter("normalModelViewMatrix", ShaderParameter::Type::MATRIX_3, 1); normalModelParam = parameterSet.addParameter("normalModelMatrix", ShaderParameter::Type::MATRIX_3, 1); lightViewProjectionParam = parameterSet.addParameter("lightViewProjectionMatrix", ShaderParameter::Type::MATRIX_4, 1); shadowMapParam = parameterSet.addParameter("shadowMap", ShaderParameter::Type::INT, 1); cameraPositionParam = parameterSet.addParameter("cameraPosition", ShaderParameter::Type::VECTOR_3, 1); directionalLightCountParam = parameterSet.addParameter("directionalLightCount", ShaderParameter::Type::INT, 1); directionalLightColorsParam = parameterSet.addParameter("directionalLightColors", ShaderParameter::Type::VECTOR_3, 1); directionalLightDirectionsParam = parameterSet.addParameter("directionalLightDirections", ShaderParameter::Type::VECTOR_3, 1); albedoOpacityMapParam = parameterSet.addParameter("albedoOpacityMap", ShaderParameter::Type::INT, 1); metalnessRoughnessMapParam = parameterSet.addParameter("metalnessRoughnessMap", ShaderParameter::Type::INT, 1); normalOcclusionMapParam = parameterSet.addParameter("normalOcclusionMap", ShaderParameter::Type::INT, 1); diffuseCubemapParam = parameterSet.addParameter("diffuseCubemap", ShaderParameter::Type::INT, 1); specularCubemapParam = parameterSet.addParameter("specularCubemap", ShaderParameter::Type::INT, 1); } bool LightingRenderPass::load(const RenderContext* renderContext) { // Load tree shadow TextureLoader textureLoader; treeShadow = textureLoader.load("data/textures/tree-shadow-0.png"); if (!treeShadow) { std::cerr << "Failed to load tree shadow" << std::endl; } // Load unskinned shader shaderLoader.undefine(); shaderLoader.define("TEXTURE_COUNT", 0); shaderLoader.define("VERTEX_POSITION", EMERGENT_VERTEX_POSITION); shaderLoader.define("VERTEX_NORMAL", EMERGENT_VERTEX_NORMAL); shaderLoader.define("VERTEX_TEXCOORD", EMERGENT_VERTEX_TEXCOORD); unskinnedShader = shaderLoader.load("data/shaders/lit-object.glsl", ¶meterSet); // Load skinned shader shaderLoader.define("SKINNED"); shaderLoader.define("MAX_BONE_COUNT", maxBoneCount); shaderLoader.define("VERTEX_BONE_INDICES", EMERGENT_VERTEX_BONE_INDICES); shaderLoader.define("VERTEX_BONE_WEIGHTS", EMERGENT_VERTEX_BONE_WEIGHTS); skinnedShader = shaderLoader.load("data/shaders/lit-object.glsl", ¶meterSet); if (!unskinnedShader || !skinnedShader) { return false; } time = 0.0f; return true; } void LightingRenderPass::unload() { delete unskinnedShader; delete skinnedShader; unskinnedShader = nullptr; skinnedShader = nullptr; for (auto it = shaderCache.begin(); it != shaderCache.end(); ++it) { delete it->second; } shaderCache.clear(); delete treeShadow; treeShadow = nullptr; delete diffuseCubemap; diffuseCubemap = nullptr; delete specularCubemap; specularCubemap = nullptr; } void LightingRenderPass::render(RenderContext* renderContext) { /* time += 1.0f / 60.f; // Bind framebuffer and setup viewport glBindFramebuffer(GL_FRAMEBUFFER, renderTarget->framebuffer); glViewport(0, 0, renderTarget->width, renderTarget->height); // Clear the framebuffer depth //glClearColor(0.0f, 0.0f, 0.0f, 1.0f); //glClearDepth(1.0); //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Enable clipping if (renderContext->layer->getIndex() == 0) { // Clipping pass cappingRenderContext.camera = renderContext->camera; cappingRenderContext.layer = renderContext->layer; for (int i = 0; i < 5; ++i) { clippingRenderPass.setClippingPlane(clippingPlanes[i]); clippingRenderPass.render(renderContext); Transform transform = Transform::getIdentity(); transform.translation = clippingPlanes[i].getNormal() * -clippingPlanes[i].getDistance(); transform.scale = Vector3(150.0f); transform.rotation = glm::normalize(glm::rotation(Vector3(0, 0, -1), clippingPlanes[i].getNormal())); ModelInstance* cappingPlaneInstance = &cappingPlaneInstances[i]; cappingPlaneInstance->setTransform(transform); cappingRenderQueue.clear(); cappingRenderQueue.queue(cappingPlaneInstance); cappingRenderPass.render(&cappingRenderContext); } glEnable(GL_CLIP_DISTANCE0); } else { glDisable(GL_CLIP_DISTANCE0); } // Enable depth testing glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glDepthFunc(GL_LEQUAL); // Enable backface culling glEnable(GL_CULL_FACE); glCullFace(GL_BACK); // Enable alpha blending glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); const Camera& camera = *(renderContext->camera); const std::list* operations = renderContext->queue->getOperations(); // Calculate camera direction const Vector3& cameraDirection = camera.getForward(); // Textures const std::size_t maxTextures = 8; int materialTexture[maxTextures]; Vector2 texcoordOffset[maxTextures]; Vector2 texcoordScale[maxTextures]; float textureDiffuseInfluence[maxTextures]; float textureSpecularInfluence[maxTextures]; float textureEmissiveInfluence[maxTextures]; float textureRoughnessInfluence[maxTextures]; float textureOpacityInfluence[maxTextures]; float textureNormalInfluence[maxTextures]; for (std::size_t i = 0; i < maxTextures; ++i) { materialTexture[i] = i + 2; } // Lights // Point lights const std::size_t maxPointLightCount = 4; std::size_t pointLightCount = 0; Vector3 pointLightColor[maxPointLightCount]; Vector3 pointLightPosition[maxPointLightCount]; Vector3 pointLightAttenuation[maxPointLightCount]; for (std::size_t i = 0; i < maxPointLightCount; ++i) pointLightColor[i] = Vector3(0.0f); // Directional lights const std::size_t maxDirectionalLightCount = 4; std::size_t directionalLightCount = 0; Vector3 directionalLightColor[maxDirectionalLightCount]; Vector3 directionalLightDirection[maxDirectionalLightCount]; for (std::size_t i = 0; i < maxDirectionalLightCount; ++i) directionalLightColor[i] = Vector3(0.0f); // Spotlights const std::size_t maxSpotlightCount = 4; std::size_t spotlightCount = 0; Vector3 spotlightColor[maxSpotlightCount]; Vector3 spotlightPosition[maxSpotlightCount]; Vector3 spotlightAttenuation[maxSpotlightCount]; Vector3 spotlightDirection[maxSpotlightCount]; float spotlightCutoff[maxSpotlightCount]; float spotlightExponent[maxSpotlightCount]; for (std::size_t i = 0; i < maxSpotlightCount; ++i) spotlightColor[i] = Vector3(0.0f); const std::list* lights = renderContext->layer->getObjects(SceneObjectType::LIGHT); if (lights != nullptr) { for (auto object: *lights) { const Light* light = static_cast(object); LightType lightType = light->getLightType(); if (lightType == LightType::POINT) { const PointLight* pointLight = static_cast(light); pointLightColor[pointLightCount] = pointLight->getScaledColor(); pointLightPosition[pointLightCount] = Vector3(camera.getView() * Vector4(pointLight->getTranslation(), 1.0f)); pointLightAttenuation[pointLightCount] = pointLight->getAttenuation(); ++pointLightCount; } else if (lightType == LightType::DIRECTIONAL) { const DirectionalLight* directionalLight = static_cast(light); directionalLightColor[directionalLightCount] = directionalLight->getScaledColor(); directionalLightDirection[directionalLightCount] = glm::normalize(Vector3(camera.getView() * Vector4(-directionalLight->getDirection(), 0.0f))); ++directionalLightCount; } else if (lightType == LightType::SPOTLIGHT) { const Spotlight* spotlight = static_cast(light); spotlightColor[spotlightCount] = spotlight->getScaledColor(); spotlightPosition[spotlightCount] = Vector3(camera.getView() * Vector4(spotlight->getTranslation(), 1.0f)); spotlightAttenuation[spotlightCount] = spotlight->getAttenuation(); spotlightDirection[spotlightCount] = glm::normalize(Vector3(camera.getView() * Vector4(-spotlight->getDirection(), 0.0f))); spotlightCutoff[spotlightCount] = spotlight->getCutoff(); spotlightExponent[spotlightCount] = spotlight->getExponent(); ++spotlightCount; } } } // Calculate the (light-space) view-projection-bias matrix Matrix4 viewProjectionBiasMatrix = biasMatrix * shadowCamera->getViewProjection(); // Bind shader Shader* boundShader = nullptr; // Bind shadow map glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, shadowMap); // Bind tree shadow glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, treeShadow.getTextureID()); // For each clipping plane for (int clippingPlaneIndex = 0; clippingPlaneIndex < 5; ++clippingPlaneIndex) { // Render operations for (const RenderOperation& operation: *operations) { const Material* material = operation.material; // Find shader std::size_t hashValue = material->getHashValue(); auto it = shaderCache.find(hashValue); if (it == shaderCache.end()) { std::cerr << "Warning: material requires unloaded shader" << std::endl; continue; } // Bind shader Shader* shader = it->second; if (shader != boundShader) { shader->bind(); boundShader = shader; } // Get shader parameters ShaderParameterSet* parameters = shader->getParameters(); const Matrix4& modelMatrix = operation.transform; Matrix4 modelViewMatrix = camera.getView() * modelMatrix; Matrix4 modelViewProjectionMatrix = camera.getViewProjection() * modelMatrix; // Pass matrix parameters if (parameters->hasParameter(ShaderParameter::MODEL_MATRIX)) { parameters->setValue(ShaderParameter::MODEL_MATRIX, modelMatrix); } if (parameters->hasParameter(ShaderParameter::MODEL_VIEW_MATRIX)) { parameters->setValue(ShaderParameter::MODEL_VIEW_MATRIX, modelViewMatrix); } if (parameters->hasParameter(ShaderParameter::MODEL_VIEW_PROJECTION_MATRIX)) { parameters->setValue(ShaderParameter::MODEL_VIEW_PROJECTION_MATRIX, modelViewProjectionMatrix); } if (parameters->hasParameter(ShaderParameter::NORMAL_MODEL_MATRIX)) { Matrix3 normalModelMatrix = glm::transpose(glm::inverse(Matrix3(modelMatrix))); parameters->setValue(ShaderParameter::NORMAL_MODEL_MATRIX, normalModelMatrix); } if (parameters->hasParameter(ShaderParameter::NORMAL_MODEL_VIEW_MATRIX)) { Matrix3 normalModelViewMatrix = glm::transpose(glm::inverse(Matrix3(modelViewMatrix))); parameters->setValue(ShaderParameter::NORMAL_MODEL_VIEW_MATRIX, normalModelViewMatrix); } if (parameters->hasParameter(ShaderParameter::CAMERA_DIRECTION)) { parameters->setValue(ShaderParameter::CAMERA_DIRECTION, cameraDirection); } // Pass material parameters if (parameters->hasParameter(ShaderParameter::MATERIAL_DIFFUSE_COLOR)) { parameters->setValue(ShaderParameter::MATERIAL_DIFFUSE_COLOR, material->getDiffuseColor()); } if (parameters->hasParameter(ShaderParameter::MATERIAL_SPECULAR_COLOR)) { parameters->setValue(ShaderParameter::MATERIAL_SPECULAR_COLOR, material->getSpecularColor()); } if (parameters->hasParameter(ShaderParameter::MATERIAL_EMISSIVE_COLOR)) { parameters->setValue(ShaderParameter::MATERIAL_EMISSIVE_COLOR, material->getEmissiveColor()); } if (parameters->hasParameter(ShaderParameter::MATERIAL_ROUGHNESS)) { parameters->setValue(ShaderParameter::MATERIAL_ROUGHNESS, material->getRoughness()); } if (parameters->hasParameter(ShaderParameter::MATERIAL_OPACITY)) { parameters->setValue(ShaderParameter::MATERIAL_OPACITY, material->getOpacity()); } // Pass texture parameters if (parameters->hasParameter(ShaderParameter::MATERIAL_TEXTURE)) { std::size_t textureCount = material->getTextureCount(); for (std::size_t i = 0; i < textureCount; ++i) { const Texture* texture = material->getTexture(i); texcoordOffset[i] = Vector2(texture->getCoordinateOffset()); texcoordScale[i] = Vector2(texture->getCoordinateScale()); textureDiffuseInfluence[i] = texture->getDiffuseInfluence(); textureSpecularInfluence[i] = texture->getSpecularInfluence(); textureEmissiveInfluence[i] = texture->getEmissiveInfluence(); textureRoughnessInfluence[i] = texture->getRoughnessInfluence(); textureOpacityInfluence[i] = texture->getOpacityInfluence(); textureNormalInfluence[i] = texture->getNormalInfluence(); // Bind texture glActiveTexture(GL_TEXTURE2 + i); glBindTexture(GL_TEXTURE_2D, texture->getTextureID()); } parameters->setValue(ShaderParameter::MATERIAL_TEXTURE, 0, &materialTexture[0], textureCount); if (parameters->hasParameter(ShaderParameter::TEXCOORD_OFFSET)) parameters->setValue(ShaderParameter::TEXCOORD_OFFSET, 0, &texcoordOffset[0], textureCount); if (parameters->hasParameter(ShaderParameter::TEXCOORD_SCALE)) parameters->setValue(ShaderParameter::TEXCOORD_SCALE, 0, &texcoordScale[0], textureCount); if (parameters->hasParameter(ShaderParameter::TEXTURE_DIFFUSE_INFLUENCE)) parameters->setValue(ShaderParameter::TEXTURE_DIFFUSE_INFLUENCE, 0, &textureDiffuseInfluence[0], textureCount); if (parameters->hasParameter(ShaderParameter::TEXTURE_SPECULAR_INFLUENCE)) parameters->setValue(ShaderParameter::TEXTURE_SPECULAR_INFLUENCE, 0, &textureSpecularInfluence[0], textureCount); if (parameters->hasParameter(ShaderParameter::TEXTURE_EMISSIVE_INFLUENCE)) parameters->setValue(ShaderParameter::TEXTURE_EMISSIVE_INFLUENCE, 0, &textureEmissiveInfluence[0], textureCount); if (parameters->hasParameter(ShaderParameter::TEXTURE_ROUGHNESS_INFLUENCE)) parameters->setValue(ShaderParameter::TEXTURE_ROUGHNESS_INFLUENCE, 0, &textureRoughnessInfluence[0], textureCount); if (parameters->hasParameter(ShaderParameter::TEXTURE_OPACITY_INFLUENCE)) parameters->setValue(ShaderParameter::TEXTURE_OPACITY_INFLUENCE, 0, &textureOpacityInfluence[0], textureCount); if (parameters->hasParameter(ShaderParameter::TEXTURE_NORMAL_INFLUENCE)) parameters->setValue(ShaderParameter::TEXTURE_NORMAL_INFLUENCE, 0, &textureNormalInfluence[0], textureCount); } // Pass lighting parameters if (parameters->hasParameter(ShaderParameter::POINT_LIGHT_COLOR)) { parameters->setValue(ShaderParameter::POINT_LIGHT_COLOR, 0, &pointLightColor[0], spotlightCount); parameters->setValue(ShaderParameter::POINT_LIGHT_POSITION, 0, &pointLightPosition[0], spotlightCount); parameters->setValue(ShaderParameter::POINT_LIGHT_ATTENUATION, 0, &pointLightAttenuation[0], spotlightCount); } if (parameters->hasParameter(ShaderParameter::DIRECTIONAL_LIGHT_COLOR)) { parameters->setValue(ShaderParameter::DIRECTIONAL_LIGHT_COLOR, 0, &directionalLightColor[0], directionalLightCount); parameters->setValue(ShaderParameter::DIRECTIONAL_LIGHT_DIRECTION, 0, &directionalLightDirection[0], directionalLightCount); } if (parameters->hasParameter(ShaderParameter::SPOTLIGHT_COLOR)) { parameters->setValue(ShaderParameter::SPOTLIGHT_COLOR, 0, &spotlightColor[0], spotlightCount); parameters->setValue(ShaderParameter::SPOTLIGHT_POSITION, 0, &spotlightPosition[0], spotlightCount); parameters->setValue(ShaderParameter::SPOTLIGHT_ATTENUATION, 0, &spotlightAttenuation[0], spotlightCount); parameters->setValue(ShaderParameter::SPOTLIGHT_DIRECTION, 0, &spotlightDirection[0], spotlightCount); parameters->setValue(ShaderParameter::SPOTLIGHT_CUTOFF, 0, &spotlightCutoff[0], spotlightCount); parameters->setValue(ShaderParameter::SPOTLIGHT_EXPONENT, 0, &spotlightExponent[0], spotlightCount); } if (parameters->hasParameter(ShaderParameter::DIFFUSE_ENVIRONMENT_MAP)) { parameters->setValue(ShaderParameter::DIFFUSE_ENVIRONMENT_MAP, 1); } if (parameters->hasParameter(ShaderParameter::SPECULAR_ENVIRONMENT_MAP)) { parameters->setValue(ShaderParameter::SPECULAR_ENVIRONMENT_MAP, 2); } // Pass shadow parameters if (parameters->hasParameter(ShaderParameter::MODEL_VIEW_PROJECTION_BIAS_MATRIX)) { Matrix4 modelViewProjectionBiasMatrix = viewProjectionBiasMatrix * modelMatrix; parameters->setValue(ShaderParameter::MODEL_VIEW_PROJECTION_BIAS_MATRIX, modelViewProjectionBiasMatrix); } if (parameters->hasParameter(ShaderParameter::SHADOW_MAP)) { parameters->setValue(ShaderParameter::SHADOW_MAP, 0); } if (parameters->hasParameter(ShaderParameter::TREE_SHADOW)) { parameters->setValue(ShaderParameter::TREE_SHADOW, 1); } if (parameters->hasParameter(ShaderParameter::TIME)) { parameters->setValue(ShaderParameter::TIME, time); } // Pass clipping parameters if (parameters->hasParameter(ShaderParameter::CLIPPING_PLANES)) { const Plane& clippingPlane = clippingPlanes[clippingPlaneIndex]; parameters->setValue(ShaderParameter::CLIPPING_PLANES, Vector4(clippingPlane.getNormal(), clippingPlane.getDistance())); } // Draw geometry glBindVertexArray(operation.vao); if (!material->isOpaque()) { //glBlendFunc(GL_ZERO, GL_SRC_COLOR); //glBlendFunc(GL_ONE, GL_ONE); //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //glBlendFunc(GL_ZERO, GL_SRC_COLOR); //glDepthMask(GL_FALSE); glFrontFace(GL_CW); glDrawElementsBaseVertex(GL_TRIANGLES, operation.triangleCount * 3, GL_UNSIGNED_INT, (void*)0, operation.indexOffset); parameters->setValue(ShaderParameter::MATERIAL_DIFFUSE_COLOR, material->getDiffuseColor() * 0.05f); glFrontFace(GL_CCW); //glDepthMask(GL_TRUE); glDrawElementsBaseVertex(GL_TRIANGLES, operation.triangleCount * 3, GL_UNSIGNED_INT, (void*)0, operation.indexOffset); //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } else { glDrawElementsBaseVertex(GL_TRIANGLES, operation.triangleCount * 3, GL_UNSIGNED_INT, (void*)0, operation.indexOffset); } } } // Disable clipping glDisable(GL_CLIP_DISTANCE0); */ const Camera& camera = *(renderContext->camera); std::list* operations = renderContext->queue->getOperations(); // Bind framebuffer and setup viewport glBindFramebuffer(GL_FRAMEBUFFER, renderTarget->framebuffer); glViewport(0, 0, renderTarget->width, renderTarget->height); // Enable depth testing glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glDepthFunc(GL_LEQUAL); // Enable backface culling glEnable(GL_CULL_FACE); glCullFace(GL_BACK); // Enable alpha blending glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); int directionalLightCount = 1; Vector3 directionalLightColors[3]; Vector3 directionalLightDirections[3]; directionalLightColors[0] = Vector3(1); directionalLightDirections[0] = glm::normalize(Vector3(camera.getView() * -Vector4(0, -2, -1, 0))); // Calculate the (light-space) view-projection matrix Matrix4 lightViewProjectionMatrix = shadowMapPass->getTileMatrix(0) * biasMatrix * shadowMapPass->getCropMatrix(0) * shadowCamera->getViewProjection(); //Matrix4 lightViewProjectionMatrix = biasMatrix * shadowCamera->getViewProjection(); glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_CUBE_MAP, diffuseCubemap->getTextureID()); glActiveTexture(GL_TEXTURE4); glBindTexture(GL_TEXTURE_CUBE_MAP, specularCubemap->getTextureID()); glActiveTexture(GL_TEXTURE5); glBindTexture(GL_TEXTURE_2D, shadowMap); Shader* shader = nullptr; Texture* albedoOpacityMap = nullptr; Texture* metalnessRoughnessMap = nullptr; Texture* normalOcclusionMap = nullptr; // Sort operations operations->sort(RenderOpCompare()); // Render operations for (const RenderOperation& operation: *operations) { // Skip render operations with unsupported materials if (operation.material->getMaterialFormatID() != static_cast(MaterialFormat::PHYSICAL)) { continue; } const PhysicalMaterial* material = static_cast(operation.material); if (!(material->flags & (unsigned int)PhysicalMaterial::Flags::OBJECT)) { continue; } // Skip render operations with unsupported vertex formats // Select shader Shader* targetShader = nullptr; if (operation.pose != nullptr) { targetShader = skinnedShader; } else { targetShader = unskinnedShader; } // Switch shader if necessary if (shader != targetShader) { shader = targetShader; // Bind shader shader->bind(); // Pass static params shader->setParameter(lightViewProjectionParam, lightViewProjectionMatrix); shader->setParameter(albedoOpacityMapParam, 0); shader->setParameter(metalnessRoughnessMapParam, 1); shader->setParameter(normalOcclusionMapParam, 2); shader->setParameter(diffuseCubemapParam, 3); shader->setParameter(specularCubemapParam, 4); shader->setParameter(shadowMapParam, 5); shader->setParameter(directionalLightCountParam, directionalLightCount); shader->setParameter(directionalLightColorsParam, 0, &directionalLightColors[0], directionalLightCount); shader->setParameter(directionalLightDirectionsParam, 0, &directionalLightDirections[0], directionalLightCount); shader->setParameter(cameraPositionParam, camera.getTranslation()); } // Pass matrix palette if (operation.pose != nullptr) { shader->setParameter(matrixPaletteParam, 0, operation.pose->getMatrixPalette(), operation.pose->getSkeleton()->getBoneCount()); } // Bind albedo-opacity map if (material->albedoOpacityMap != albedoOpacityMap) { albedoOpacityMap = material->albedoOpacityMap; if (albedoOpacityMap != nullptr) { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, albedoOpacityMap->getTextureID()); } } // Bind metalness-roughness map if (material->metalnessRoughnessMap != metalnessRoughnessMap) { metalnessRoughnessMap = material->metalnessRoughnessMap; if (metalnessRoughnessMap != nullptr) { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, metalnessRoughnessMap->getTextureID()); } } // Bind normal-occlusion map if (material->normalOcclusionMap != normalOcclusionMap) { normalOcclusionMap = material->normalOcclusionMap; if (normalOcclusionMap != nullptr) { glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, normalOcclusionMap->getTextureID()); } } const Matrix4& modelMatrix = operation.transform; Matrix4 modelViewMatrix = camera.getView() * modelMatrix; Matrix4 modelViewProjectionMatrix = camera.getViewProjection() * modelMatrix; Matrix3 normalModelViewMatrix = glm::transpose(glm::inverse(Matrix3(modelViewMatrix))); Matrix3 normalModelMatrix = glm::transpose(glm::inverse(Matrix3(modelMatrix))); shader->setParameter(modelParam, modelMatrix); shader->setParameter(modelViewParam, modelViewMatrix); shader->setParameter(modelViewProjectionParam, modelViewProjectionMatrix); shader->setParameter(normalModelViewParam, normalModelViewMatrix); shader->setParameter(normalModelParam, normalModelMatrix); glBindVertexArray(operation.vao); glDrawElementsBaseVertex(GL_TRIANGLES, operation.triangleCount * 3, GL_UNSIGNED_INT, (void*)0, operation.indexOffset); } glActiveTexture(GL_TEXTURE5); glBindTexture(GL_TEXTURE_2D, 0); } bool LightingRenderPass::loadShader(const RenderOperation& operation) { /* const std::string shaderFilename = "data/shaders/main.glsl"; // Get material and its hash value const Material* material = operation.material; std::size_t hashValue = material->getHashValue(); // Check if shader has already been loaded auto it = shaderCache.find(hashValue); if (it != shaderCache.end()) return true; // Define shader preprocessor macros // Undefine previous definitions shaderLoader.undefine(); // Clipping shaderLoader.define("CLIPPING_PLANE_COUNT", 1); // Vertex format shaderLoader.define("VERTEX_POSITION", EMERGENT_VERTEX_POSITION); shaderLoader.define("VERTEX_NORMAL", EMERGENT_VERTEX_NORMAL); //shaderLoader.define("VERTEX_COLOR", EMERGENT_VERTEX_COLOR); // Lighting // Material if (material->isShadeless()) { shaderLoader.define("SHADELESS"); } else { // Lighting //shaderLoader.define("POINT_LIGHT_COUNT", 1); shaderLoader.define("DIRECTIONAL_LIGHT_COUNT", 2); //shaderLoader.define("SPOTLIGHT_COUNT", 2); //shaderLoader.define("ENVIRONMENT_MAP"); } if (material->isShadowReceiver()) shaderLoader.define("SHADOWED"); // Final shaderLoader.define("GAMMA_CORRECT"); // Load shader Shader* shader = shaderLoader.load(shaderFilename); if (!shader) { std::cerr << "Failed to load shader \"" << shaderFilename << "\"" << std::endl; return false; } // Store shader in cache shaderCache[hashValue] = shader; return true; */ return false; } bool LightingRenderPass::RenderOpCompare::operator()(const RenderOperation& opA, const RenderOperation& opB) const { // Skip render operations with unsupported materials if (opA.material->getMaterialFormatID() != static_cast(MaterialFormat::PHYSICAL)) { return false; } else if (opB.material->getMaterialFormatID() != static_cast(MaterialFormat::PHYSICAL)) { return true; } // Cast materials const PhysicalMaterial* materialA = static_cast(opA.material); const PhysicalMaterial* materialB = static_cast(opB.material); // Determine transparency bool transparentA = materialA->flags & (unsigned int)PhysicalMaterial::Flags::TRANSLUCENT; bool transparentB = materialB->flags & (unsigned int)PhysicalMaterial::Flags::TRANSLUCENT; if (transparentA) { if (transparentB) { // A and B are both transparent, sort by depth return (opA.depth <= opB.depth); } else { // A is transparent, B is opaque. Render B first return false; } } else { if (transparentB) { // A is opaque, B is transparent. Render A first return true; } else { // A and B are both opaque, sort by material return (opA.material < opB.material); } } } DebugRenderPass::DebugRenderPass() { modelViewProjectionParam = parameterSet.addParameter("modelViewProjectionMatrix", ShaderParameter::Type::MATRIX_4, 1); } bool DebugRenderPass::load(const RenderContext* renderContext) { unlitSolidShader = shaderLoader.load("data/shaders/unlit-solid.glsl", ¶meterSet); if (!unlitSolidShader) { return false; } const float aabbVertexData[] = { -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, }; const std::uint32_t aabbIndexData[] = { 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 }; aabbVertexCount = 8; aabbIndexCount = 24; // Create AABB geometry glGenVertexArrays(1, &aabbVAO); glBindVertexArray(aabbVAO); glGenBuffers(1, &aabbVBO); glBindBuffer(GL_ARRAY_BUFFER, aabbVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * aabbVertexCount, aabbVertexData, GL_STATIC_DRAW); glEnableVertexAttribArray(EMERGENT_VERTEX_POSITION); glVertexAttribPointer(EMERGENT_VERTEX_POSITION, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (char*)0 + 0*sizeof(float)); glGenBuffers(1, &aabbIBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, aabbIBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(std::uint32_t) * aabbIndexCount, aabbIndexData, GL_STATIC_DRAW); return true; } void DebugRenderPass::unload() { delete unlitSolidShader; unlitSolidShader = nullptr; glDeleteBuffers(1, &aabbIBO); glDeleteBuffers(1, &aabbVBO); glDeleteVertexArrays(1, &aabbVAO); } void DebugRenderPass::render(RenderContext* renderContext) { // Bind framebuffer and setup viewport glBindFramebuffer(GL_FRAMEBUFFER, renderTarget->framebuffer); glViewport(0, 0, renderTarget->width, renderTarget->height); const Camera& camera = *(renderContext->camera); /* // Bind framebuffer and setup viewport glBindFramebuffer(GL_FRAMEBUFFER, renderTarget->framebuffer); glViewport(0, 0, renderTarget->width, renderTarget->height); // Clear the framebuffer depth glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClearDepth(1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Disable depth testing glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glDepthFunc(GL_LESS); */ // Disable backface culling glDisable(GL_CULL_FACE); // Disable alpha blending glDisable(GL_BLEND); // Bind unlit solid shader unlitSolidShader->bind(); // Bind AABB geometry glBindVertexArray(aabbVAO); const std::list* objects = renderContext->layer->getObjects(); for (auto object: *objects) { if (!camera.getCullingMask()->intersects(object->getBounds())) continue; const AABB& bounds = object->getBounds(); const Vector3& min = bounds.getMin(); const Vector3& max = bounds.getMax(); Vector3 scale = max - min; Vector3 center = (min + max) * 0.5f; const Vector3& translation = center; Matrix4 modelMatrix = glm::translate(translation) * glm::scale(scale); Matrix4 modelViewProjectionMatrix = camera.getViewProjection() * modelMatrix; unlitSolidShader->setParameter(modelViewProjectionParam, modelViewProjectionMatrix); glDrawElements(GL_LINES, aabbIndexCount, GL_UNSIGNED_INT, (void*)0); } } UIRenderPass::UIRenderPass() { modelViewProjectionParam = parameterSet.addParameter("modelViewProjectionMatrix", ShaderParameter::Type::MATRIX_4, 1); textureParam = parameterSet.addParameter("tex", ShaderParameter::Type::INT, 1); texcoordOffsetParam = parameterSet.addParameter("texcoordOffset", ShaderParameter::Type::VECTOR_2, 1); texcoordScaleParam = parameterSet.addParameter("texcoordScale", ShaderParameter::Type::VECTOR_2, 1); } bool UIRenderPass::load(const RenderContext* renderContext) { shaderLoader.define("VERTEX_POSITION", EMERGENT_VERTEX_POSITION); shaderLoader.define("VERTEX_TEXCOORD", EMERGENT_VERTEX_TEXCOORD); shaderLoader.define("VERTEX_COLOR", EMERGENT_VERTEX_COLOR); shaderLoader.define("GAMMA_CORRECT"); shaderLoader.define("TEXTURE_COUNT", 1); texturedUIShader = shaderLoader.load("data/shaders/ui.glsl", ¶meterSet); shaderLoader.undefine(); shaderLoader.define("VERTEX_POSITION", EMERGENT_VERTEX_POSITION); shaderLoader.define("VERTEX_COLOR", EMERGENT_VERTEX_COLOR); shaderLoader.define("GAMMA_CORRECT"); untexturedUIShader = shaderLoader.load("data/shaders/ui.glsl", ¶meterSet); if (!texturedUIShader || !untexturedUIShader) { return false; } return true; } void UIRenderPass::unload() { delete texturedUIShader; delete untexturedUIShader; texturedUIShader = nullptr; untexturedUIShader = nullptr; } void UIRenderPass::render(RenderContext* renderContext) { const Camera& camera = *(renderContext->camera); // Bind framebuffer and setup viewport glBindFramebuffer(GL_FRAMEBUFFER, renderTarget->framebuffer); glViewport(0, 0, renderTarget->width, renderTarget->height); // Disable depth testing glDisable(GL_DEPTH_TEST); //glDepthMask(GL_FALSE); //glDepthFunc(GL_LESS); // Disable backface culling glEnable(GL_CULL_FACE); glCullFace(GL_BACK); // Enable alpha blending glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glActiveTexture(GL_TEXTURE0); Shader* shader = nullptr; // Render operations const std::list* operations = renderContext->queue->getOperations(); for (const RenderOperation& operation: *operations) { // Skip render operations with unsupported materials if (operation.material->getMaterialFormatID() != static_cast(MaterialFormat::UI)) { continue; } const UIMaterial* material = static_cast(operation.material); if (material->texture != nullptr) { shader = texturedUIShader; shader->bind(); shader->setParameter(textureParam, 0); shader->setParameter(texcoordOffsetParam, Vector2(0.0f)); shader->setParameter(texcoordScaleParam, Vector2(1.0f)); glBindTexture(GL_TEXTURE_2D, material->texture->getTextureID()); } else { shader = untexturedUIShader; shader->bind(); } const Matrix4& modelMatrix = operation.transform; Matrix4 modelViewProjectionMatrix = camera.getViewProjection() * modelMatrix; // Pass matrix parameters shader->setParameter(modelViewProjectionParam, modelViewProjectionMatrix); // Draw geometry glBindVertexArray(operation.vao); glDrawElementsBaseVertex(GL_TRIANGLES, operation.triangleCount * 3, GL_UNSIGNED_INT, (void*)0, operation.indexOffset); } } VignetteRenderPass::VignetteRenderPass(): shader(nullptr) { bayerTextureParam = parameterSet.addParameter("bayerTexture", ShaderParameter::Type::INT, 1); modelViewProjectionParam = parameterSet.addParameter("modelViewProjectionMatrix", ShaderParameter::Type::MATRIX_4, 1); } bool VignetteRenderPass::load(const RenderContext* renderContext) { shaderLoader.undefine(); shaderLoader.define("VERTEX_POSITION", EMERGENT_VERTEX_POSITION); shaderLoader.define("VERTEX_COLOR", EMERGENT_VERTEX_COLOR); shaderLoader.define("TEXTURE_COUNT", 1); shader = shaderLoader.load("data/shaders/vignette.glsl", ¶meterSet); if (!shader) { return false; } /// @see http://www.anisopteragames.com/how-to-fix-color-banding-with-dithering/ static const char pattern[] = { 0, 32, 8, 40, 2, 34, 10, 42, 48, 16, 56, 24, 50, 18, 58, 26, 12, 44, 4, 36, 14, 46, 6, 38, 60, 28, 52, 20, 62, 30, 54, 22, 3, 35, 11, 43, 1, 33, 9, 41, 51, 19, 59, 27, 49, 17, 57, 25, 15, 47, 7, 39, 13, 45, 5, 37, 63, 31, 55, 23, 61, 29, 53, 21 }; glGenTextures(1, &bayerTextureID); glBindTexture(GL_TEXTURE_2D, bayerTextureID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, 8, 8, 0, GL_RED, GL_UNSIGNED_BYTE, pattern); return true; } void VignetteRenderPass::unload() { delete shader; shader = nullptr; glDeleteTextures(1, &bayerTextureID); } void VignetteRenderPass::render(RenderContext* renderContext) { glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); // Bind shader shader->bind(); // Bind texture glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, bayerTextureID); // Pass texture unit to shader shader->setParameter(bayerTextureParam, 0); const Camera& camera = *(renderContext->camera); const std::list* operations = renderContext->queue->getOperations(); // Render operations for (const RenderOperation& operation: *operations) { const Material* material = operation.material; const Matrix4& modelMatrix = operation.transform; Matrix4 modelViewProjectionMatrix = camera.getViewProjection() * modelMatrix; shader->setParameter(modelViewProjectionParam, modelViewProjectionMatrix); glBindVertexArray(operation.vao); glDrawElementsBaseVertex(GL_TRIANGLES, operation.triangleCount * 3, GL_UNSIGNED_INT, (void*)0, operation.indexOffset); } } SkyboxRenderPass::SkyboxRenderPass(): shader(nullptr), cubemap(nullptr) { matrixParam = parameterSet.addParameter("matrix", ShaderParameter::Type::MATRIX_4, 1); cubemapParam = parameterSet.addParameter("cubemap", ShaderParameter::Type::INT, 1); } bool SkyboxRenderPass::load(const RenderContext* renderContext) { shaderLoader.undefine(); shaderLoader.define("VERTEX_POSITION", EMERGENT_VERTEX_POSITION); shader = shaderLoader.load("data/shaders/skybox.glsl", ¶meterSet); if (!shader) { return false; } const float quadVertexData[] = { -1.0f, 1.0f, 0.0f, -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f }; const std::uint32_t quadIndexData[] = { 0, 1, 3, 3, 1, 2 }; quadVertexCount = 4; quadIndexCount = 6; // Create AABB geometry glGenVertexArrays(1, &quadVAO); glBindVertexArray(quadVAO); glGenBuffers(1, &quadVBO); glBindBuffer(GL_ARRAY_BUFFER, quadVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * quadVertexCount, quadVertexData, GL_STATIC_DRAW); glEnableVertexAttribArray(EMERGENT_VERTEX_POSITION); glVertexAttribPointer(EMERGENT_VERTEX_POSITION, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (char*)0 + 0*sizeof(float)); glGenBuffers(1, &quadIBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadIBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(std::uint32_t) * quadIndexCount, quadIndexData, GL_STATIC_DRAW); return true; } void SkyboxRenderPass::unload() { delete shader; shader = nullptr; glDeleteBuffers(1, &quadIBO); glDeleteBuffers(1, &quadVBO); glDeleteVertexArrays(1, &quadVAO); } void SkyboxRenderPass::render(RenderContext* renderContext) { if (!cubemap) { return; } glBindFramebuffer(GL_FRAMEBUFFER, renderTarget->framebuffer); glViewport(0, 0, renderTarget->width, renderTarget->height); glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); //glDisable(GL_CULL_FACE); //glCullFace(GL_BACK); // Bind shader shader->bind(); // Bind cubemap texture glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap->getTextureID()); // Pass texture unit to shader shader->setParameter(cubemapParam, 0); // Calculate matrix const Camera& camera = *(renderContext->camera); Matrix4 modelView = Matrix4(Matrix3(camera.getView())); Matrix4 matrix = glm::inverse(modelView) * glm::inverse(camera.getProjection()); // Pass matrix to shader shader->setParameter(matrixParam, matrix); // Render quad glBindVertexArray(quadVAO); glDrawElementsBaseVertex(GL_TRIANGLES, quadIndexCount, GL_UNSIGNED_INT, (void*)0, 0); }