|
/*
|
|
* 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 "materials.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;
|
|
}
|
|
|
|
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<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[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<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 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<RenderOperation>* 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<float>(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<float>(i) / static_cast<float>(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<float>::infinity()), Vector3(-std::numeric_limits<float>::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<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 render operations with unsupported materials
|
|
if (operation.material->getMaterialFormatID() != static_cast<unsigned int>(MaterialFormat::PHYSICAL))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Skip non shadow casters
|
|
const PhysicalMaterial* material = static_cast<const PhysicalMaterial*>(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<RenderOperation>* 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<RenderOperation>* operations = renderContext->queue->getOperations();
|
|
|
|
// Render operations
|
|
for (const RenderOperation& operation: *operations)
|
|
{
|
|
// Skip render operations with unsupported materials
|
|
if (operation.material->getMaterialFormatID() != static_cast<unsigned int>(MaterialFormat::PHYSICAL))
|
|
{
|
|
continue;
|
|
}
|
|
const PhysicalMaterial* material = static_cast<const PhysicalMaterial*>(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<RenderOperation>* 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<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::POINT)
|
|
{
|
|
const PointLight* pointLight = static_cast<const PointLight*>(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<const DirectionalLight*>(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<const Spotlight*>(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<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
|
|
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<unsigned int>(MaterialFormat::PHYSICAL))
|
|
{
|
|
continue;
|
|
}
|
|
const PhysicalMaterial* material = static_cast<const PhysicalMaterial*>(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<unsigned int>(MaterialFormat::PHYSICAL))
|
|
{
|
|
return false;
|
|
}
|
|
else if (opB.material->getMaterialFormatID() != static_cast<unsigned int>(MaterialFormat::PHYSICAL))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Cast materials
|
|
const PhysicalMaterial* materialA = static_cast<const PhysicalMaterial*>(opA.material);
|
|
const PhysicalMaterial* materialB = static_cast<const PhysicalMaterial*>(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<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;
|
|
|
|
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<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 != 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<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():
|
|
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);
|
|
}
|