|
|
- /*
- * 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 <http://www.gnu.org/licenses/>.
- */
-
- #include "render-passes.hpp"
- #include "configuration.hpp"
- #include "ui/ui.hpp"
- #include <iostream>
- #include <limits>
-
- 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;
- }
-
- BlurRenderPass::BlurRenderPass():
- gammaCorrect(false)
- {}
-
- bool BlurRenderPass::load(const RenderContext* renderContext)
- {
- permutation = (gammaCorrect) ? 1 : 0;
-
- // Load shader source
- if (!shader.loadSource("data/shaders/blur.glsl"))
- {
- std::cerr << std::string("BlurRenderPass: failed to load shader source.") << std::endl;
- return false;
- }
-
- // Generate permutation
- if (!shader.generatePermutation(permutation))
- {
- std::cerr << std::string("BlurRenderPass: failed to generate shader permutation.") << std::endl;
- return false;
- }
-
- // Connect shader variables
- textureParam.connect(shader.getInput("blurTexture"));
- resolutionParam.connect(shader.getInput("resolution"));
- directionParam.connect(shader.getInput("direction"));
- if (!textureParam.isConnected() ||
- !resolutionParam.isConnected() ||
- !directionParam.isConnected())
- {
- std::cerr << std::string("BlurRenderPass: one or more shader variables were not connected to shader inputs.") << std::endl;
- return false;
- }
-
- // Initialize shader variables
- resolutionParam.setValue(Vector2(renderTarget->width, renderTarget->height));
-
- 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 BlurRenderPass::unload()
- {
- textureParam.disconnect();
- resolutionParam.disconnect();
- directionParam.disconnect();
- shader.deleteAllPermutations();
-
- glDeleteBuffers(1, &quadIBO);
- glDeleteBuffers(1, &quadVBO);
- glDeleteVertexArrays(1, &quadVAO);
- }
-
- void BlurRenderPass::render(RenderContext* renderContext)
- {
- // Bind framebuffer and set up viewport
- glBindFramebuffer(GL_FRAMEBUFFER, renderTarget->framebuffer);
- glViewport(0, 0, renderTarget->width, renderTarget->height);
-
- // Set up OpenGL state
- glDisable(GL_DEPTH_TEST);
- glDepthMask(GL_FALSE);
- glDisable(GL_BLEND);
- glDisable(GL_CULL_FACE);
-
- // Activate shader permutation
- shader.activate(permutation);
-
- // Upload shader variables to shader permutation
- textureParam.upload();
- resolutionParam.upload();
- directionParam.upload();
-
- // Render quad
- glBindVertexArray(quadVAO);
- glDrawElementsBaseVertex(GL_TRIANGLES, quadIndexCount, GL_UNSIGNED_INT, (void*)0, 0);
-
- // Unbind texture
- //glBindTexture(GL_TEXTURE_2D, 0);
- }
-
- ShadowMapRenderPass::ShadowMapRenderPass():
- 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;
-
- // Create split view frustum
- splitViewFrustum = new SplitViewFrustum(4);
- splitViewFrustum->setSplitSchemeWeight(0.85f);
-
- // Determine resolution of shadow maps
- shadowMapResolution = 4096;
- croppedShadowMapResolution = shadowMapResolution >> 1;
-
- // Allocate viewports
- croppedShadowMapViewports = new Vector4[splitViewFrustum->getSubfrustumCount()];
-
- // Setup viewports
- for (int i = 0; i < splitViewFrustum->getSubfrustumCount(); ++i)
- {
- int x = i % 2;
- int y = i / 2;
-
- Vector4* viewport = &croppedShadowMapViewports[i];
- (*viewport)[0] = static_cast<float>(x * croppedShadowMapResolution);
- (*viewport)[1] = static_cast<float>(y * croppedShadowMapResolution);
- (*viewport)[2] = static_cast<float>(croppedShadowMapResolution);
- (*viewport)[3] = static_cast<float>(croppedShadowMapResolution);
- }
-
- // Allocate matrices
- cropMatrices = new Matrix4[splitViewFrustum->getSubfrustumCount()];
- tileMatrices = new Matrix4[splitViewFrustum->getSubfrustumCount()];
-
- // Setup tile matrices
- Matrix4 tileScale = glm::scale(Vector3(0.5f, 0.5f, 1.0f));
- for (int i = 0; i < splitViewFrustum->getSubfrustumCount(); ++i)
- {
- float x = static_cast<float>(i % 2) * 0.5f;
- float y = static_cast<float>(i / 2) * 0.5f;
- tileMatrices[i] = glm::translate(Vector3(x, y, 0.0f)) * tileScale;
- }
-
- // Setup permutation values
- unskinnedPermutation = 0;
- skinnedPermutation = 1;
-
- // Load shader source
- if (!shader.loadSource("data/shaders/depth-pass.glsl"))
- {
- std::cerr << std::string("ShadowMapRenderPass: failed to load shader source.") << std::endl;
- return false;
- }
-
- // Generate unskinned and skinned permutations
- if (!shader.generatePermutation(unskinnedPermutation) || !shader.generatePermutation(skinnedPermutation))
- {
- std::cerr << std::string("ShadowMapRenderPass: failed to generate shader permutation.") << std::endl;
- return false;
- }
-
- // Allocate bone palette parameter
- matrixPaletteParam = new ShaderMatrix4(maxBoneCount);
-
- // Connect shader variables
- modelViewProjectionParam.connect(shader.getInput("modelViewProjectionMatrix"));
- matrixPaletteParam->connect(shader.getInput("matrixPalette"));
- if (!modelViewProjectionParam.isConnected() ||
- !matrixPaletteParam->isConnected())
- {
- std::cerr << std::string("ShadowMapRenderPass: one or more shader variables were not connected to shader inputs.") << std::endl;
- return false;
- }
-
- return true;
- }
-
- void ShadowMapRenderPass::unload()
- {
- modelViewProjectionParam.disconnect();
- matrixPaletteParam->disconnect();
- delete matrixPaletteParam;
- shader.deleteAllPermutations();
-
- delete[] croppedShadowMapViewports;
- croppedShadowMapViewports = nullptr;
-
- delete splitViewFrustum;
- splitViewFrustum = nullptr;
-
- delete[] cropMatrices;
- cropMatrices = nullptr;
-
- delete[] tileMatrices;
- tileMatrices = nullptr;
- }
-
- void ShadowMapRenderPass::render(RenderContext* renderContext)
- {
- // 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_LESS);
-
- // Clear the framebuffer depth
- glClear(GL_DEPTH_BUFFER_BIT);
-
- // Draw front and back faces
- glEnable(GL_CULL_FACE);
- glCullFace(GL_BACK);
-
- // Disable alpha blending
- glDisable(GL_BLEND);
-
- //const Camera& lightCamera = *(renderContext->camera);
- std::list<RenderOperation>* operations = renderContext->queue->getOperations();
-
- GLuint boundVAO = 0;
-
- splitViewFrustum->setMatrices(viewCamera->getView(), viewCamera->getProjection());
-
- // Sort operations
- operations->sort(RenderOpCompare());
-
- std::uint32_t permutation = 0xDEADBEEF;
-
- // For each frustum split
- for (int i = 0; i < splitViewFrustum->getSubfrustumCount(); ++i)
- {
- // Calculate crop matrix
- {
- const ViewFrustum& subfrustum = splitViewFrustum->getSubfrustum(i);
-
- // Create AABB containing the subfrustum corners
- AABB subfrustumBounds(subfrustum.getCorner(0), subfrustum.getCorner(0));
- for (std::size_t j = 1; j < 8; ++j)
- {
- subfrustumBounds.add(subfrustum.getCorner(j));
- }
-
- // Transform subfrustum bounds into light's clip space
- AABB croppingBounds = subfrustumBounds.transformed(lightCamera->getViewProjection());
- Vector3 cropMax = croppingBounds.getMax();
- Vector3 cropMin = croppingBounds.getMin();
-
- // 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<float>(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 operations with no materials and materials with no shadows
- if (operation.material == nullptr || (operation.material->getFlags() & MATERIAL_FLAG_DISABLE_SHADOW_CASTING))
- {
- continue;
- }
-
- // TODO: Perform culling for subfrustums
-
- // Select permutation
- std::uint32_t targetPermutation = (operation.pose != nullptr) ? skinnedPermutation : unskinnedPermutation;
- if (permutation != targetPermutation)
- {
- permutation = targetPermutation;
- shader.activate(permutation);
- }
-
- // Pass matrix palette
- if (operation.pose != nullptr)
- {
- matrixPaletteParam->getConnectedInput()->upload(0, operation.pose->getMatrixPalette(), operation.pose->getSkeleton()->getBoneCount());
- }
-
- const Matrix4& modelMatrix = operation.transform;
- Matrix4 modelViewProjectionMatrix = croppedViewProjection * modelMatrix;
-
- modelViewProjectionParam.setValue(modelViewProjectionMatrix);
- modelViewProjectionParam.upload();
-
- if (boundVAO != operation.vao)
- {
- glBindVertexArray(operation.vao);
- boundVAO = operation.vao;
- }
-
- glDrawElementsBaseVertex(GL_TRIANGLES, operation.triangleCount * 3, GL_UNSIGNED_INT, (void*)0, operation.indexOffset);
- }
- }
-
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
- }
-
- bool ShadowMapRenderPass::RenderOpCompare::operator()(const RenderOperation& opA, const RenderOperation& opB) const
- {
- // If A is rigged
- if (opA.pose != nullptr)
- {
- // And B is rigged
- if (opB.pose != nullptr)
- {
- // Sort by VAO ID
- return (opA.vao <= opB.vao);
- }
- else
- {
- // Render A first
- return true;
- }
- }
-
- // Sort by VAO ID
- return (opA.vao <= opB.vao);
- }
-
- LightingRenderPass::LightingRenderPass():
- shadowMap(0),
- shadowCamera(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;
- maxDirectionalLightCount = 1;
- maxSpotlightCount = 1;
- }
-
- bool LightingRenderPass::load(const RenderContext* renderContext)
- {
- // Load shaders for each material
-
- // Register parameter sets for each unique shader
-
- if (!shader.loadSource("data/shaders/standard.glsl"))
- {
- std::cerr << std::string("LightingRenderPass: Failed to load shader source.") << std::endl;
- return false;
- }
-
- /*
- if (renderContext != nullptr)
- {
- std::list<RenderOperation>* operations = renderContext->queue->getOperations();
-
- for (RenderOperation& op: *operations)
- {
-
- }
- }
- */
-
- // Set permutation values
- std::uint32_t IS_SKINNED = 1;
- std::uint32_t HAS_AMBIENT_CUBE = 1 << 7;
- unskinnedPermutation = HAS_AMBIENT_CUBE;
- skinnedPermutation = IS_SKINNED | HAS_AMBIENT_CUBE;
-
- // Generate shader permutations
- if (!shader.generatePermutation(unskinnedPermutation) || !shader.generatePermutation(skinnedPermutation))
- {
- std::cerr << std::string("LightingRenderPass: failed to generate shader permutation.") << std::endl;
- return false;
- }
-
- // Allocate shader array parameters
- parameters.matrixPalette = new ShaderMatrix4(maxBoneCount);
- parameters.lightViewProjectionMatrices = new ShaderMatrix4(4);
-
- // Connect shader parameters
- parameters.matrixPalette->connect(shader.getInput("matrixPalette"));
- parameters.modelMatrix.connect(shader.getInput("modelMatrix"));
- parameters.modelViewMatrix.connect(shader.getInput("modelViewMatrix"));
- parameters.modelViewProjectionMatrix.connect(shader.getInput("modelViewProjectionMatrix"));
- parameters.normalModelViewMatrix.connect(shader.getInput("normalModelViewMatrix"));
- parameters.normalModelMatrix.connect(shader.getInput("normalModelMatrix"));
- parameters.lightViewProjectionMatrices->connect(shader.getInput("lightViewProjectionMatrices"));
- parameters.splitDistances.connect(shader.getInput("splitDistances"));
- parameters.shadowMap.connect(shader.getInput("shadowMap"));
- parameters.cameraPosition.connect(shader.getInput("cameraPosition"));
- parameters.diffuseCubemap.connect(shader.getInput("diffuseCubemap"));
- parameters.specularCubemap.connect(shader.getInput("specularCubemap"));
-
- parameters.albedoOpacityMap.connect(shader.getInput("albedoOpacityMap"));
- parameters.metalnessRoughnessMap.connect(shader.getInput("metalnessRoughnessMap"));
- parameters.normalOcclusionMap.connect(shader.getInput("normalOcclusionMap"));
-
- if (!parameters.matrixPalette->isConnected() ||
- !parameters.modelMatrix.isConnected() ||
- !parameters.modelViewMatrix.isConnected() ||
- !parameters.modelViewProjectionMatrix.isConnected() ||
- !parameters.normalModelViewMatrix.isConnected() ||
- !parameters.normalModelMatrix.isConnected() ||
- !parameters.lightViewProjectionMatrices->isConnected() ||
- !parameters.splitDistances.isConnected() ||
- !parameters.shadowMap.isConnected() ||
- !parameters.cameraPosition.isConnected() ||
- !parameters.diffuseCubemap.isConnected() ||
- !parameters.specularCubemap.isConnected())
- {
- std::cerr << std::string("LightingRenderPass: one or more shader variables were not connected to shader inputs.") << std::endl;
- }
-
- return true;
- }
-
- void LightingRenderPass::unload()
- {
- // Free shader array parameters
- delete parameters.matrixPalette;
- delete parameters.lightViewProjectionMatrices;
- parameters.matrixPalette = nullptr;
- parameters.lightViewProjectionMatrices = nullptr;
- shader.deleteAllPermutations();
- }
-
- void LightingRenderPass::render(RenderContext* renderContext)
- {
- const Camera& camera = *(renderContext->camera);
- std::list<RenderOperation>* 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
- //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glDisable(GL_BLEND);
-
-
- Vector4 splitDistances;
- for (int i = 0; i < 4; ++i)
- {
- splitDistances[i] = shadowMapPass->getSplitViewFrustum().getSplitDistance(i + 1);
- }
-
- Vector3 directionalLightColors[3];
- Vector3 directionalLightDirections[3];
-
- Vector3 spotlightColors[3];
- Vector3 spotlightPositions[3];
- Vector3 spotlightAttenuations[3];
- Vector3 spotlightDirections[3];
- float spotlightCutoffs[3];
- float spotlightExponents[3];
-
- // Add directional light
- int directionalLightCount = 1;
- directionalLightColors[0] = Vector3(1);
- directionalLightDirections[0] = glm::normalize(Vector3(camera.getView() * -Vector4(0, -2, -1, 0)));
-
- // Add spotlights
- int spotlightCount = 0;
- const std::list<SceneObject*>* lights = renderContext->layer->getObjects(SceneObjectType::LIGHT);
- if (lights != nullptr)
- {
- for (auto object: *lights)
- {
- const Light* light = static_cast<const Light*>(object);
- LightType lightType = light->getLightType();
-
- if (lightType == LightType::SPOTLIGHT && light->isActive())
- {
- const Spotlight* spotlight = static_cast<const Spotlight*>(light);
-
- spotlightColors[spotlightCount] = spotlight->getScaledColor();
- spotlightPositions[spotlightCount] = Vector3(camera.getView() * Vector4(spotlight->getTranslation(), 1.0f));
- spotlightAttenuations[spotlightCount] = spotlight->getAttenuation();
- spotlightDirections[spotlightCount] = glm::normalize(Vector3(camera.getView() * Vector4(-spotlight->getDirection(), 0.0f)));
- spotlightCutoffs[spotlightCount] = spotlight->getCutoff();
- spotlightExponents[spotlightCount] = spotlight->getExponent();
-
- ++spotlightCount;
- }
- }
- }
-
- // Calculate the (light-space) view-projection matrices
- Matrix4 lightViewProjectionMatrices[4];
- for (int i = 0; i < 4; ++i)
- {
- lightViewProjectionMatrices[i] = shadowMapPass->getTileMatrix(i) * biasMatrix * shadowMapPass->getCropMatrix(i) * shadowCamera->getViewProjection();
- }
-
- // Set shader parameter values
- parameters.lightViewProjectionMatrices->setValues(0, &lightViewProjectionMatrices[0], 4);
- parameters.splitDistances.setValue(splitDistances);
- parameters.cameraPosition.setValue(camera.getTranslation());
- parameters.diffuseCubemap.setValue(diffuseCubemap);
- parameters.specularCubemap.setValue(specularCubemap);
- parameters.shadowMap.setValue(shadowMap);
- parameters.directionalLightCount.setValue(0);
- parameters.spotlightCount.setValue(0);
-
- std::uint32_t permutation = 0xDEADBEEF;
- bool blending = false;
- GLuint boundVAO = 0;
-
- // Sort operations
- operations->sort(RenderOpCompare());
-
- // Render operations
- for (const RenderOperation& operation: *operations)
- {
- // Skip operations without materials
- if (!operation.material)
- {
- continue;
- }
-
- bool hasTranslucency = operation.material->getFlags() & MATERIAL_FLAG_TRANSLUCENT;
- if (hasTranslucency && !blending)
- {
- glEnable(GL_BLEND);
- blending = true;
- }
-
- // Select permutation
- std::uint32_t targetPermutation = (operation.pose != nullptr) ? skinnedPermutation : unskinnedPermutation;
- if (permutation != targetPermutation)
- {
- permutation = targetPermutation;
- shader.activate(permutation);
-
- // Pass static params
- parameters.lightViewProjectionMatrices->upload();
- parameters.splitDistances.upload();
- parameters.cameraPosition.upload();
- parameters.diffuseCubemap.upload();
- parameters.specularCubemap.upload();
- parameters.shadowMap.upload();
- parameters.directionalLightCount.upload();
- parameters.spotlightCount.upload();
-
- /*
- shader->setParameter(directionalLightCountParam, directionalLightCount);
- shader->setParameter(directionalLightColorsParam, 0, &directionalLightColors[0], directionalLightCount);
- shader->setParameter(directionalLightDirectionsParam, 0, &directionalLightDirections[0], directionalLightCount);
-
- shader->setParameter(spotlightCountParam, spotlightCount);
- shader->setParameter(spotlightColorsParam, 0, &spotlightColors[0], spotlightCount);
- shader->setParameter(spotlightPositionsParam, 0, &spotlightPositions[0], spotlightCount);
- shader->setParameter(spotlightAttenuationsParam, 0, &spotlightAttenuations[0], spotlightCount);
- shader->setParameter(spotlightDirectionsParam, 0, &spotlightDirections[0], spotlightCount);
- shader->setParameter(spotlightCutoffsParam, 0, &spotlightCutoffs[0], spotlightCount);
- shader->setParameter(spotlightExponentsParam, 0, &spotlightExponents[0], spotlightCount);
- */
- }
-
- 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)));
-
- parameters.modelMatrix.setValue(modelMatrix);
- parameters.modelViewMatrix.setValue(modelViewMatrix);
- parameters.modelViewProjectionMatrix.setValue(modelViewProjectionMatrix);
- parameters.normalModelViewMatrix.setValue(normalModelViewMatrix);
- parameters.normalModelMatrix.setValue(normalModelMatrix);
-
- // Upload matrix parameters
- parameters.modelMatrix.upload();
- parameters.modelViewMatrix.upload();
- parameters.modelViewProjectionMatrix.upload();
- parameters.normalModelViewMatrix.upload();
- parameters.normalModelMatrix.upload();
-
- // Upload pose matrix palette
- if (operation.pose != nullptr && parameters.matrixPalette->isConnected())
- {
- parameters.matrixPalette->getConnectedInput()->upload(0, operation.pose->getMatrixPalette(), operation.pose->getSkeleton()->getBoneCount());
- }
-
- // Upload material parameters
- if (operation.material != nullptr)
- {
- if (operation.material->getShader() != &shader)
- {
- ((Material*)operation.material)->setShader(&shader);
- }
- operation.material->upload();
- }
-
- if (boundVAO != operation.vao)
- {
- glBindVertexArray(operation.vao);
- boundVAO = 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::RenderOpCompare::operator()(const RenderOperation& opA, const RenderOperation& opB) const
- {
- if (!opA.material)
- return false;
- else if (!opB.material);
- return true;
-
- // Determine transparency
- bool transparentA = opA.material->getFlags() & MATERIAL_FLAG_TRANSLUCENT;
- bool transparentB = opB.material->getFlags() & MATERIAL_FLAG_TRANSLUCENT;
-
- if (transparentA)
- {
- if (transparentB)
- {
- // A and B are both transparent, render back to front
- 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
- if (opA.material->getShader() == opB.material->getShader())
- {
- // A and B have the same shader
- if (opA.vao == opB.vao)
- {
- // A and B have the same VAO, sort by depth
- return (opA.depth < opB.depth);
- }
- else
- {
- // Sort by VAO
- return (opA.vao < opB.vao);
- }
- }
- }
- }
-
- // A and B are both opaque and have different shaders, sort by shader
- return (opA.material->getShader() < opB.material->getShader());
- }
-
- DebugRenderPass::DebugRenderPass()
- {}
-
- bool DebugRenderPass::load(const RenderContext* renderContext)
- {
- if (!shader.loadSource("data/shaders/unlit-solid.glsl"))
- {
- std::cerr << std::string("DebugRenderPass: Failed to load shader source.") << std::endl;
- return false;
- }
-
- // Set permutation values
- permutation = 0;
-
- // Generate shader permutations
- if (!shader.generatePermutation(permutation))
- {
- std::cerr << std::string("DebugRenderPass: failed to generate shader permutation.") << std::endl;
- return false;
- }
-
- // Connect shader variables
- modelViewProjectionMatrixParam.connect(shader.getInput("modelViewProjectionMatrix"));
- if (!modelViewProjectionMatrixParam.isConnected())
- {
- std::cerr << std::string("DebugRenderPass: one or more shader variables were not connected to shader inputs.") << std::endl;
- 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()
- {
- modelViewProjectionMatrixParam.disconnect();
- shader.deleteAllPermutations();
-
- 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
- shader.activate(permutation);
-
- // Bind AABB geometry
- glBindVertexArray(aabbVAO);
-
- const std::list<SceneObject*>* 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;
-
- modelViewProjectionMatrixParam.setValue(modelViewProjectionMatrix);
- modelViewProjectionMatrixParam.upload();
-
- glDrawElements(GL_LINES, aabbIndexCount, GL_UNSIGNED_INT, (void*)0);
- }
- }
-
- UIRenderPass::UIRenderPass()
- {}
-
- bool UIRenderPass::load(const RenderContext* renderContext)
- {
- if (!shader.loadSource("data/shaders/ui.glsl"))
- {
- std::cerr << std::string("UIRenderPass: Failed to load shader source.") << std::endl;
- return false;
- }
-
- // Set permutation values
- untexturedPermutation = 0;
- texturedPermutation = 1;
-
- // Generate shader permutations
- if (!shader.generatePermutation(untexturedPermutation) || !shader.generatePermutation(texturedPermutation))
- {
- std::cerr << std::string("UIRenderPass: failed to generate shader permutation.") << std::endl;
- return false;
- }
-
- // Connect shader variables
- modelViewProjectionMatrixParam.connect(shader.getInput("modelViewProjectionMatrix"));
- textureParam.connect(shader.getInput("tex"));
- textureOffsetParam.connect(shader.getInput("texcoordOffset"));
- textureScaleParam.connect(shader.getInput("texcoordScale"));
- if (!modelViewProjectionMatrixParam.isConnected() ||
- !textureParam.isConnected() ||
- !textureOffsetParam.isConnected() ||
- !textureScaleParam.isConnected())
- {
- std::cerr << std::string("UIRenderPass: one or more shader variables were not connected to shader inputs.") << std::endl;
- return false;
- }
-
- return true;
- }
-
- void UIRenderPass::unload()
- {
- modelViewProjectionMatrixParam.disconnect();
- textureParam.disconnect();
- textureOffsetParam.disconnect();
- textureScaleParam.disconnect();
- shader.deleteAllPermutations();
- }
-
- 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);
-
- // Render operations
- const std::list<RenderOperation>* operations = renderContext->queue->getOperations();
- for (const RenderOperation& operation: *operations)
- {
- // Skip render operations with unsupported materials
- /*
- if (operation.material->getMaterialFormatID() != static_cast<unsigned int>(MaterialFormat::UI))
- {
- continue;
- }
- */
-
- const UIMaterial* material = static_cast<const UIMaterial*>(operation.material);
-
- if (material->texture->getValue() != nullptr)
- {
- shader.activate(texturedPermutation);
-
- textureParam.setValue(material->texture->getValue());
- textureOffsetParam.setValue(material->textureOffset->getValue());
- textureScaleParam.setValue(material->textureScale->getValue());
-
- textureParam.upload();
- textureOffsetParam.upload();
- textureScaleParam.upload();
- }
- else
- {
- shader.activate(untexturedPermutation);
- }
-
- const Matrix4& modelMatrix = operation.transform;
- Matrix4 modelViewProjectionMatrix = camera.getViewProjection() * modelMatrix;
-
- // Upload matrix parameters
- modelViewProjectionMatrixParam.setValue(modelViewProjectionMatrix);
- modelViewProjectionMatrixParam.upload();
-
- // Upload material parameters
- //operation.material->upload();
-
- // 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<RenderOperation>* 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():
- cubemap(nullptr)
- {}
-
- bool SkyboxRenderPass::load(const RenderContext* renderContext)
- {
- if (!shader.loadSource("data/shaders/skybox.glsl"))
- {
- std::cerr << std::string("SkyboxRenderPass: Failed to load shader source.") << std::endl;
- return false;
- }
-
- // Set permutation values
- permutation = 0;
-
- // Generate shader permutations
- if (!shader.generatePermutation(permutation))
- {
- std::cerr << std::string("SkyboxRenderPass: failed to generate shader permutation.") << std::endl;
- return false;
- }
-
- // Connect shader variables
- matrixParam.connect(shader.getInput("matrix"));
- cubemapParam.connect(shader.getInput("cubemap"));
- if (!matrixParam.isConnected() || !cubemapParam.isConnected())
- {
- std::cerr << std::string("SkyboxRenderPass: one or more shader variables were not connected to shader inputs.") << std::endl;
- 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()
- {
- matrixParam.disconnect();
- cubemapParam.disconnect();
- shader.deleteAllPermutations();
-
- 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.activate(permutation);
-
- // Bind cubemap texture
- cubemapParam.setValue(cubemap);
- cubemapParam.upload();
-
- // Calculate matrix
- const Camera& camera = *(renderContext->camera);
- Matrix4 modelView = Matrix4(Matrix3(camera.getView()));
- Matrix4 matrix = glm::inverse(modelView) * glm::inverse(camera.getProjection());
-
- // Upload matrix to shader
- matrixParam.setValue(matrix);
- matrixParam.upload();
-
- // Render quad
- glBindVertexArray(quadVAO);
- glDrawElementsBaseVertex(GL_TRIANGLES, quadIndexCount, GL_UNSIGNED_INT, (void*)0, 0);
- }
|