141 lines
5.5 KiB
C++
141 lines
5.5 KiB
C++
#include "forwardmodule.h"
|
|
#include "scene.h"
|
|
#include "mesh.h"
|
|
#include "shader.h"
|
|
#include "light.h"
|
|
#include "phongmaterial.h"
|
|
#include "texture.h"
|
|
#include <glm/ext.hpp>
|
|
|
|
void ForwardModule::renderGL(Camera* myCamera, Scene* scene)
|
|
{
|
|
// bind target
|
|
glViewport(0, 0, width, height);
|
|
|
|
for(const Pass &p : passes)
|
|
{
|
|
for(Light *light : p.lights)
|
|
{
|
|
if(light->getFlags() & (1 << Light::AMBIENT_FLAG))
|
|
{
|
|
// render ambient lighting (opaque)
|
|
glEnable(GL_DEPTH_TEST);
|
|
glDepthFunc(GL_LESS);
|
|
glDisable(GL_BLEND);
|
|
}
|
|
else
|
|
{
|
|
// render directionnal lighting and point lighting (additive light)
|
|
glDepthFunc(GL_LEQUAL);
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_ONE, GL_ONE);
|
|
glDepthMask(GL_FALSE);
|
|
}
|
|
Shader *shader = p.shader;
|
|
shader->bind();
|
|
switch(light->getType())
|
|
{
|
|
case Light::AMBIENT:
|
|
shader->bindVec3(shader->getLocation("lightColor"), light->getColor()); // add attribute, and setter for ambient lighting
|
|
break;
|
|
case Light::DIRECTIONNAL:
|
|
shader->bindVec3(shader->getLocation("dirLight"), -light->getDir());
|
|
shader->bindVec3(shader->getLocation("lightColor"), light->getColor());
|
|
if(light->isShadowCaster())
|
|
{
|
|
light->getShadowMap()->bind(PhongMaterial::NB_PHONG_SLOTS); // NB_PHONG_SLOTS has the value of the first available slot after the phong material texture slots
|
|
shader->bindInteger(shader->getLocation("shadowMap"), PhongMaterial::NB_PHONG_SLOTS);
|
|
}
|
|
break;
|
|
case Light::POINT:
|
|
shader->bindVec3(shader->getLocation("pointLight"), light->getPos());
|
|
shader->bindVec3(shader->getLocation("lightColor"), light->getColor());
|
|
shader->bindFloat(shader->getLocation("attenuation"), light->getAttenuation());
|
|
break;
|
|
case Light::SPOT:
|
|
shader->bindVec3(shader->getLocation("lightColor"), light->getColor());
|
|
// TODO add cutoff and attenuation
|
|
break;
|
|
}
|
|
unsigned int id = 2;
|
|
for(GeometryNode *node : p.geometry)
|
|
{
|
|
shader->bindUnsignedInteger(shader->getLocation("object_identifier"), id);
|
|
if(node->mesh->instances_offsets.empty())
|
|
++id;
|
|
else
|
|
id += node->mesh->instances_offsets.size();
|
|
// compute matrix attributes
|
|
glm::mat4 modelViewMatrix = myCamera->getViewMatrix() * node->modelMatrix;
|
|
glm::mat4 mvp = myCamera->getProjectionMatrix() * modelViewMatrix;
|
|
glm::mat4 normalMatrix = glm::transpose(glm::inverse(modelViewMatrix));
|
|
if(light != NULL && light->isShadowCaster())
|
|
{
|
|
glm::mat4 lightMVP = Light::biasMatrix * light->getProjectionMatrix() * light->getViewMatrix() * node->modelMatrix;
|
|
shader->bindMat4(shader->getLocation("lightMVP"), lightMVP);
|
|
}
|
|
shader->bindMat4(shader->getLocation("viewMatrix"), myCamera->getViewMatrix());
|
|
shader->bindMat4(shader->getLocation("modelViewMatrix"), modelViewMatrix);
|
|
shader->bindMat3(shader->getLocation("normalMatrix"), glm::mat3(normalMatrix));
|
|
shader->bindMat4(shader->getLocation("MVP"), mvp);
|
|
node->mesh->draw(shader);
|
|
}
|
|
}
|
|
}
|
|
|
|
glDisable(GL_BLEND);
|
|
glDepthFunc(GL_LESS);
|
|
glDepthMask(GL_TRUE);
|
|
}
|
|
|
|
void ForwardModule::setShaderSource(ShaderSource* source)
|
|
{
|
|
if(shaderSources != NULL)
|
|
delete(shaderSources);
|
|
shaderSources = source;
|
|
}
|
|
|
|
void ForwardModule::compileShaders(Scene* scene)
|
|
{
|
|
for(Pass &p : passes)
|
|
delete(p.shader);
|
|
passes.clear();
|
|
// list all geometry types
|
|
geometry.clear();
|
|
for(SceneIterator<GeometryNode*>* geometryIt = scene->getGeometry();
|
|
geometryIt->isValid(); geometryIt->next())
|
|
{
|
|
GeometryNode* n = geometryIt->getItem();
|
|
geometry[n->mesh->getFlags()].push_back(n);
|
|
}
|
|
// list all light types
|
|
lights.clear();
|
|
lights[ambientLight.getFlags()].push_back(&ambientLight);
|
|
for(SceneIterator<Light*>* lightIt = scene->getLights();
|
|
lightIt->isValid(); lightIt->next())
|
|
{
|
|
Light* l = lightIt->getItem();
|
|
lights[l->getFlags()].push_back(l);
|
|
}
|
|
// compile shaders and add the pass for the ambient light first
|
|
unsigned int ambientFlags = ambientLight.getFlags();
|
|
for(const auto &geomIt : geometry)
|
|
{
|
|
unsigned int geomFlags = geomIt.first;
|
|
passes.push_back(Pass(shaderSources->compile(geomFlags, ambientFlags), geomIt.second, lights[ambientFlags]));
|
|
}
|
|
// compile a shader for each combination of a geometry flag and a light flag
|
|
for(const auto &lightIt : lights)
|
|
{
|
|
unsigned int lightFlags = lightIt.first;
|
|
if(lightFlags != ambientFlags) // ambient shaders are already ready
|
|
{
|
|
for(const auto &geomIt : geometry)
|
|
{
|
|
unsigned int geomFlags = geomIt.first;
|
|
passes.push_back(Pass(shaderSources->compile(geomFlags, lightFlags), geomIt.second, lightIt.second));
|
|
}
|
|
}
|
|
}
|
|
}
|