Browse Source

Add support for translucency and selective shadow casting via material flags

master
C. J. Howard 7 years ago
parent
commit
cc39de6646
6 changed files with 266 additions and 157 deletions
  1. +1
    -1
      data
  2. +1
    -1
      lib/emergent
  3. +2
    -0
      src/application.cpp
  4. +4
    -1
      src/configuration.hpp.in
  5. +224
    -107
      src/material-loader.cpp
  6. +34
    -47
      src/render-passes.cpp

+ 1
- 1
data

@ -1 +1 @@
Subproject commit 41b7c54fb2819da830a47d0e5a5756eed5a0310d
Subproject commit 0ed0baf703fdc72c524d8c779c3ae2d92402d041

+ 1
- 1
lib/emergent

@ -1 +1 @@
Subproject commit ce417f4eafa15035b3a7613363e23157b8e59900
Subproject commit c79c7f5a714472ae123a12400d462e59c05bd443

+ 2
- 0
src/application.cpp View File

@ -2075,6 +2075,8 @@ void Application::loadLevel(std::size_t index)
{ {
albedoOpacityMap->setValue(&pheromoneTexture); albedoOpacityMap->setValue(&pheromoneTexture);
} }
material->setFlags(MATERIAL_FLAG_TRANSLUCENT | MATERIAL_FLAG_DISABLE_SHADOW_CASTING);
//material->shadowCaster = false; //material->shadowCaster = false;
//material->flags |= (unsigned int)PhysicalMaterial::Flags::TRANSLUCENT; //material->flags |= (unsigned int)PhysicalMaterial::Flags::TRANSLUCENT;

+ 4
- 1
src/configuration.hpp.in View File

@ -46,7 +46,7 @@ const float WORLD_WIDTH = 100.0f; // cm
const float WORLD_HEIGHT = 100.0f; // cm const float WORLD_HEIGHT = 100.0f; // cm
const float FRAMES_PER_SECOND = 60.0f; const float FRAMES_PER_SECOND = 60.0f;
const float TIMESTEP = 1.0f / FRAMES_PER_SECOND; const float TIMESTEP = 1.0f / FRAMES_PER_SECOND;
const float PHEROMONE_MATRIX_RESOLUTION = 5.12f;
const float PHEROMONE_MATRIX_RESOLUTION = 5.12f; // pheromone cells per cm
const int PHEROMONE_MATRIX_COLUMNS = (int)(WORLD_WIDTH * PHEROMONE_MATRIX_RESOLUTION); const int PHEROMONE_MATRIX_COLUMNS = (int)(WORLD_WIDTH * PHEROMONE_MATRIX_RESOLUTION);
const int PHEROMONE_MATRIX_ROWS = (int)(WORLD_HEIGHT * PHEROMONE_MATRIX_RESOLUTION); const int PHEROMONE_MATRIX_ROWS = (int)(WORLD_HEIGHT * PHEROMONE_MATRIX_RESOLUTION);
const Vector2 WORLD_BOUNDS_MIN = Vector2(-WORLD_WIDTH * 0.5f, -WORLD_HEIGHT * 0.5f); const Vector2 WORLD_BOUNDS_MIN = Vector2(-WORLD_WIDTH * 0.5f, -WORLD_HEIGHT * 0.5f);
@ -59,4 +59,7 @@ const float HOMING_PHEROMONE_COLOR[] = {0.55f, 0.55f, 0.00f, 0.0f}; // CMYK
const float RECRUITMENT_PHEROMONE_COLOR[] = {0.00f, 0.55f, 0.55f, 0.0f}; // CMYK const float RECRUITMENT_PHEROMONE_COLOR[] = {0.00f, 0.55f, 0.55f, 0.0f}; // CMYK
const float ALARM_PHEROMONE_COLOR[] = {0.00f, 0.00f, 1.00f, 0.0f}; // CMYK const float ALARM_PHEROMONE_COLOR[] = {0.00f, 0.00f, 1.00f, 0.0f}; // CMYK
const std::uint64_t MATERIAL_FLAG_TRANSLUCENT = 0x0000000001;
const std::uint64_t MATERIAL_FLAG_DISABLE_SHADOW_CASTING = 0x0000000002;
#endif // CONFIGURATION_HPP #endif // CONFIGURATION_HPP

+ 224
- 107
src/material-loader.cpp View File

@ -78,151 +78,244 @@ Material* MaterialLoader::load(const std::string& filename)
return nullptr; return nullptr;
} }
// Parse lines
std::string line; std::string line;
std::size_t lineNumber = 0;
const std::string whitespace = " \t";
// Parse lines
while (file.good() && std::getline(file, line)) while (file.good() && std::getline(file, line))
{ {
const std::string whitespace = " \t";
// Increment current line number
++lineNumber;
// Skip empty lines // Skip empty lines
if (line.empty()) if (line.empty())
{ {
continue; continue;
} }
// Find position of first character in variable name
std::size_t variableNamePosition = line.find_first_not_of(whitespace, 0);
if (variableNamePosition == std::string::npos)
{
// Skip whitespace-only lines
continue;
}
// Find position of equals sign
std::size_t equalsSignPosition = line.find_first_of("=", variableNamePosition);
if (equalsSignPosition == std::string::npos)
// Find position of first character in the command
std::size_t commandPosition = line.find_first_not_of(whitespace, 0);
if (commandPosition == std::string::npos)
{ {
// Skip lines with no equals sign
// Skip whitespace-only lines
continue; continue;
} }
// Find position of first character in variable type
std::size_t variableTypePosition = line.find_first_not_of(whitespace, equalsSignPosition + 1);
if (variableTypePosition == std::string::npos)
{
// Skip lines with no variable type definition
continue;
}
// Determine command type
std::string command = line.substr(commandPosition, line.find_first_of(" \t=", commandPosition) - commandPosition);
// Count parentheses
std::size_t leftParenthesisCount = std::count(line.begin() + variableNamePosition, line.end(), '(');
std::size_t rightParenthesisCount = std::count(line.begin() + variableNamePosition, line.end(), ')');
if (leftParenthesisCount != rightParenthesisCount || leftParenthesisCount == 0)
// Parse command
if (command == "shader" || command == "flags")
{ {
// Skip lines with invalid number of parentheses
continue;
// Find position of equals sign
std::size_t equalsSignPosition = line.find_first_of("=", commandPosition);
if (equalsSignPosition == std::string::npos)
{
// Skip lines with no equals sign
std::cerr << "MaterialLoader::load(): Invalid line " << lineNumber << " in \"" << filename << "\"" << std::endl;
continue;
}
// Find position of first character in the value string
std::size_t valueStartPosition = line.find_first_not_of(whitespace, equalsSignPosition + 1);
if (valueStartPosition == std::string::npos)
{
// Skip lines with no value
std::cerr << "MaterialLoader::load(): Invalid line " << lineNumber << " in \"" << filename << "\"" << std::endl;
continue;
}
// Find position the end of the value string
std::size_t valueEndPosition = line.find_first_of(" \t;", valueStartPosition);
// Determine value string
std::string valueString;
if (valueEndPosition == std::string::npos)
{
valueString = line.substr(valueStartPosition);
}
else
{
valueString = line.substr(valueStartPosition, valueEndPosition - valueStartPosition);
}
// Execute command
if (command == "shader")
{
// Load shader
Shader* shader = loadShader(valueString);
if (!shader)
{
std::cerr << "MaterialLoader::load(): Failed to load shader \"" << valueString << "\" on line " << lineNumber << " in \"" << filename << "\"" << std::endl;
}
else
{
material->setShader(shader);
}
}
else
{
// Parse flags
std::uint64_t flags;
std::stringstream stream;
stream << valueString;
stream >> flags;
material->setFlags(flags);
}
} }
std::string variableName = line.substr(variableNamePosition, line.find_first_of(" \t=", variableNamePosition) - variableNamePosition);
std::string variableType = line.substr(variableTypePosition, line.find_first_of(" \t[(", variableTypePosition) - variableTypePosition);
std::size_t elementCount = leftParenthesisCount;
std::size_t currentPosition = variableTypePosition;
std::vector<std::vector<std::string>> elements;
bool invalid = false;
for (std::size_t i = 0; i < elementCount; ++i)
else if (command == "var")
{ {
std::size_t leftParenthesisPosition = line.find_first_of("(", currentPosition);
std::size_t rightParenthesisPosition = line.find_first_of(")", leftParenthesisPosition + 1);
// Find position of first character in variable name
std::size_t variableNamePosition = line.find_first_not_of(whitespace, commandPosition + command.length());
if (variableNamePosition == std::string::npos)
{
// Skip lines with no variable name
std::cerr << "MaterialLoader::load(): Invalid variable on line " << lineNumber << " in \"" << filename << "\"" << std::endl;
continue;
}
// Find position of equals sign
std::size_t equalsSignPosition = line.find_first_of("=", variableNamePosition);
if (equalsSignPosition == std::string::npos)
{
// Skip lines with no equals sign
std::cerr << "MaterialLoader::load(): Invalid variable on line " << lineNumber << " in \"" << filename << "\"" << std::endl;
continue;
}
if (leftParenthesisPosition == std::string::npos || rightParenthesisPosition == std::string::npos)
// Find position of first character in variable type
std::size_t variableTypePosition = line.find_first_not_of(whitespace, equalsSignPosition + 1);
if (variableTypePosition == std::string::npos)
{ {
invalid = true;
break;
// Skip lines with no variable type definition
std::cerr << "MaterialLoader::load(): Invalid variable on line " << lineNumber << " in \"" << filename << "\"" << std::endl;
continue;
} }
currentPosition = leftParenthesisPosition + 1;
std::size_t argumentCount = std::count(line.begin() + leftParenthesisPosition + 1, line.begin() + rightParenthesisPosition, ',') + 1;
std::vector<std::string> arguments;
for (std::size_t j = 0; j < argumentCount; ++j)
// Count parentheses
std::size_t leftParenthesisCount = std::count(line.begin() + variableNamePosition, line.end(), '(');
std::size_t rightParenthesisCount = std::count(line.begin() + variableNamePosition, line.end(), ')');
if (leftParenthesisCount != rightParenthesisCount || leftParenthesisCount == 0)
{ {
std::size_t argumentStart = line.find_first_not_of(whitespace, currentPosition);
std::size_t argumentEnd = line.find_first_of(" \t,)", argumentStart + 1);
// Skip lines with invalid number of parentheses
std::cerr << "MaterialLoader::load(): Invalid variable on line " << lineNumber << " in \"" << filename << "\"" << std::endl;
continue;
}
std::string variableName = line.substr(variableNamePosition, line.find_first_of(" \t=", variableNamePosition) - variableNamePosition);
std::string variableType = line.substr(variableTypePosition, line.find_first_of(" \t[(", variableTypePosition) - variableTypePosition);
std::size_t elementCount = leftParenthesisCount;
std::size_t currentPosition = variableTypePosition;
std::vector<std::vector<std::string>> elements;
bool invalid = false;
for (std::size_t i = 0; i < elementCount; ++i)
{
std::size_t leftParenthesisPosition = line.find_first_of("(", currentPosition);
std::size_t rightParenthesisPosition = line.find_first_of(")", leftParenthesisPosition + 1);
if (argumentStart == std::string::npos || argumentEnd == std::string::npos)
if (leftParenthesisPosition == std::string::npos || rightParenthesisPosition == std::string::npos)
{ {
// Unable to parse argument
invalid = true; invalid = true;
break; break;
} }
std::string argument = line.substr(argumentStart, argumentEnd - argumentStart);
arguments.push_back(argument);
currentPosition = leftParenthesisPosition + 1;
std::size_t argumentCount = std::count(line.begin() + leftParenthesisPosition + 1, line.begin() + rightParenthesisPosition, ',') + 1;
std::vector<std::string> arguments;
for (std::size_t j = 0; j < argumentCount; ++j)
{
std::size_t argumentStart = line.find_first_not_of(whitespace, currentPosition);
std::size_t argumentEnd = line.find_first_of(" \t,)", argumentStart + 1);
if (argumentStart == std::string::npos || argumentEnd == std::string::npos)
{
// Unable to parse argument
invalid = true;
break;
}
std::string argument = line.substr(argumentStart, argumentEnd - argumentStart);
arguments.push_back(argument);
currentPosition = argumentEnd + 1;
}
currentPosition = argumentEnd + 1;
if (invalid)
{
// Unable to parse element
break;
}
elements.push_back(arguments);
currentPosition = rightParenthesisPosition + 1;
} }
if (invalid) if (invalid)
{ {
// Unable to parse element
break;
// Unable to parse line
continue;
} }
elements.push_back(arguments);
currentPosition = rightParenthesisPosition + 1;
}
if (invalid)
{
// Unable to parse line
continue;
}
if (variableType == "int")
{
ShaderInt* variable = material->addVariable<int>(variableName, elements.size());
loadShaderInt(variable, elements);
}
else if (variableType == "float")
{
ShaderFloat* variable = material->addVariable<float>(variableName, elements.size());
loadShaderFloat(variable, elements);
}
else if (variableType == "vec2")
{
ShaderVector2* variable = material->addVariable<Vector2>(variableName, elements.size());
loadShaderVector2(variable, elements);
}
else if (variableType == "vec3")
{
ShaderVector3* variable = material->addVariable<Vector3>(variableName, elements.size());
loadShaderVector3(variable, elements);
}
else if (variableType == "vec4")
{
ShaderVector4* variable = material->addVariable<Vector4>(variableName, elements.size());
loadShaderVector4(variable, elements);
}
else if (variableType == "mat3")
{
ShaderMatrix3* variable = material->addVariable<Matrix3>(variableName, elements.size());
loadShaderMatrix3(variable, elements);
}
else if (variableType == "mat4")
{
ShaderMatrix4* variable = material->addVariable<Matrix4>(variableName, elements.size());
loadShaderMatrix4(variable, elements);
}
else if (variableType == "texture")
{
ShaderTexture2D* variable = material->addVariable<const Texture2D*>(variableName, elements.size());
loadShaderTexture2D(variable, elements);
if (variableType == "int")
{
ShaderInt* variable = material->addVariable<int>(variableName, elements.size());
loadShaderInt(variable, elements);
}
else if (variableType == "float")
{
ShaderFloat* variable = material->addVariable<float>(variableName, elements.size());
loadShaderFloat(variable, elements);
}
else if (variableType == "vec2")
{
ShaderVector2* variable = material->addVariable<Vector2>(variableName, elements.size());
loadShaderVector2(variable, elements);
}
else if (variableType == "vec3")
{
ShaderVector3* variable = material->addVariable<Vector3>(variableName, elements.size());
loadShaderVector3(variable, elements);
}
else if (variableType == "vec4")
{
ShaderVector4* variable = material->addVariable<Vector4>(variableName, elements.size());
loadShaderVector4(variable, elements);
}
else if (variableType == "mat3")
{
ShaderMatrix3* variable = material->addVariable<Matrix3>(variableName, elements.size());
loadShaderMatrix3(variable, elements);
}
else if (variableType == "mat4")
{
ShaderMatrix4* variable = material->addVariable<Matrix4>(variableName, elements.size());
loadShaderMatrix4(variable, elements);
}
else if (variableType == "texture")
{
ShaderTexture2D* variable = material->addVariable<const Texture2D*>(variableName, elements.size());
loadShaderTexture2D(variable, elements);
}
else if (variableType == "textureCube")
{
ShaderTextureCube* variable = material->addVariable<const TextureCube*>(variableName, elements.size());
loadShaderTextureCube(variable, elements);
}
} }
else if (variableType == "textureCube")
else
{ {
ShaderTextureCube* variable = material->addVariable<const TextureCube*>(variableName, elements.size());
loadShaderTextureCube(variable, elements);
if (command[0] == '#')
{
// Skip comments
continue;
}
// Invalid command
std::cerr << "MaterialLoader::load(): Invalid command \"" << command << "\" on line " << lineNumber << " in \"" << filename << "\"" << std::endl;
} }
} }
@ -235,6 +328,30 @@ Material* MaterialLoader::load(const std::string& filename)
return material; return material;
} }
Shader* MaterialLoader::loadShader(const std::string& filename)
{
auto it = shaderCache.find(filename);
if (it != shaderCache.end())
{
return it->second;
}
std::string fullFilename = std::string("data/shaders/") + filename;
// Load shader
Shader* shader = new Shader();
if (!shader->loadSource(fullFilename))
{
delete shader;
return nullptr;
}
// Add shader to cache
shaderCache[filename] = shader;
return shader;
}
Texture2D* MaterialLoader::loadTexture2D(const std::string& filename) Texture2D* MaterialLoader::loadTexture2D(const std::string& filename)
{ {
// Check if texture exists in cache // Check if texture exists in cache

+ 34
- 47
src/render-passes.cpp View File

@ -18,6 +18,7 @@
*/ */
#include "render-passes.hpp" #include "render-passes.hpp"
#include "configuration.hpp"
#include "ui/ui.hpp" #include "ui/ui.hpp"
#include <iostream> #include <iostream>
#include <limits> #include <limits>
@ -386,27 +387,14 @@ void ShadowMapRenderPass::render(RenderContext* renderContext)
// Render operations // Render operations
for (const RenderOperation& operation: *operations) for (const RenderOperation& operation: *operations)
{ {
// Skip render operations with unsupported materials
/*
if (operation.material->getMaterialFormatID() != static_cast<unsigned int>(MaterialFormat::PHYSICAL))
// Skip operations with no materials and materials with no shadows
if (operation.material == nullptr || (operation.material->getFlags() & MATERIAL_FLAG_DISABLE_SHADOW_CASTING))
{ {
continue; continue;
} }
*/
// Skip non shadow casters
/*
const PhysicalMaterial* material = static_cast<const PhysicalMaterial*>(operation.material);
if (!material->shadowCaster)
{
continue;
}
*/
// TODO: Perform culling for subfrustums // TODO: Perform culling for subfrustums
// Select permutation // Select permutation
std::uint32_t targetPermutation = (operation.pose != nullptr) ? skinnedPermutation : unskinnedPermutation; std::uint32_t targetPermutation = (operation.pose != nullptr) ? skinnedPermutation : unskinnedPermutation;
if (permutation != targetPermutation) if (permutation != targetPermutation)
@ -585,8 +573,7 @@ void LightingRenderPass::render(RenderContext* renderContext)
// Enable alpha blending // Enable alpha blending
//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_BLEND);
glDisable(GL_BLEND);
Vector4 splitDistances; Vector4 splitDistances;
@ -658,19 +645,23 @@ void LightingRenderPass::render(RenderContext* renderContext)
GLuint boundVAO = 0; GLuint boundVAO = 0;
// Sort operations // Sort operations
//operations->sort(RenderOpCompare());
operations->sort(RenderOpCompare());
// Render operations // Render operations
for (const RenderOperation& operation: *operations) for (const RenderOperation& operation: *operations)
{ {
/*
bool hasTranslucency = material->flags & (unsigned int)PhysicalMaterial::Flags::TRANSLUCENT;
// Skip operations without materials
if (!operation.material)
{
continue;
}
bool hasTranslucency = operation.material->getFlags() & MATERIAL_FLAG_TRANSLUCENT;
if (hasTranslucency && !blending) if (hasTranslucency && !blending)
{ {
glEnable(GL_BLEND); glEnable(GL_BLEND);
blending = true; blending = true;
} }
*/
// Select permutation // Select permutation
std::uint32_t targetPermutation = (operation.pose != nullptr) ? skinnedPermutation : unskinnedPermutation; std::uint32_t targetPermutation = (operation.pose != nullptr) ? skinnedPermutation : unskinnedPermutation;
@ -738,10 +729,6 @@ void LightingRenderPass::render(RenderContext* renderContext)
} }
operation.material->upload(); operation.material->upload();
} }
else
{
//std::cerr << "NULL MATERIAL!!!" << std::endl;
}
if (boundVAO != operation.vao) if (boundVAO != operation.vao)
{ {
@ -758,31 +745,21 @@ void LightingRenderPass::render(RenderContext* renderContext)
bool LightingRenderPass::RenderOpCompare::operator()(const RenderOperation& opA, const RenderOperation& opB) const 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))
{
if (!opA.material)
return false; return false;
}
else if (opB.material->getMaterialFormatID() != static_cast<unsigned int>(MaterialFormat::PHYSICAL))
{
else if (!opB.material);
return true; return true;
}
// Cast materials
const PhysicalMaterial* materialA = static_cast<const PhysicalMaterial*>(opA.material);
const PhysicalMaterial* materialB = static_cast<const PhysicalMaterial*>(opB.material);
// Determine transparency // Determine transparency
bool transparentA = materialA->flags & (unsigned int)PhysicalMaterial::Flags::TRANSLUCENT;
bool transparentB = materialB->flags & (unsigned int)PhysicalMaterial::Flags::TRANSLUCENT;
bool transparentA = opA.material->getFlags() & MATERIAL_FLAG_TRANSLUCENT;
bool transparentB = opB.material->getFlags() & MATERIAL_FLAG_TRANSLUCENT;
if (transparentA) if (transparentA)
{ {
if (transparentB) if (transparentB)
{ {
// A and B are both transparent, render back to front // A and B are both transparent, render back to front
return (opA.depth <= opB.depth);
return (opA.depth >= opB.depth);
} }
else else
{ {
@ -799,15 +776,25 @@ bool LightingRenderPass::RenderOpCompare::operator()(const RenderOperation& opA,
} }
else else
{ {
// A and B are both opaque, sort by material
return (opA.material < opB.material);
// A and B are both opaque, render front to back
//return (opA.depth > opB.depth);
// 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()); return (opA.material->getShader() < opB.material->getShader());
} }

Loading…
Cancel
Save