diff --git a/CMakeLists.txt b/CMakeLists.txt index 1cb2f6b..2ce4739 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,4 +16,6 @@ endif() file(GLOB RESOURCES_FILES src/*.h shaders/*.glsl) -include(../cmaketemplate/template.cmake) +set(CMAKE_TEMPLATE_PATH "../cmaketemplate") + +include(${CMAKE_TEMPLATE_PATH}/template.cmake) diff --git a/src/buffer.cpp b/src/buffer.cpp index a3f03d0..d8b2758 100644 --- a/src/buffer.cpp +++ b/src/buffer.cpp @@ -4,7 +4,7 @@ #include template -GLenum Buffer::getGLEnum(BufferType type) +GLenum TBuffer::getGLEnum(BufferType type) { GLenum typeEnum; @@ -25,7 +25,7 @@ GLenum Buffer::getGLEnum(BufferType type) } template -Buffer::BufferEditor::BufferEditor(Buffer *b) +TBuffer::BufferEditor::BufferEditor(TBuffer *b) { if(b->isDynamic()) { @@ -41,14 +41,14 @@ Buffer::BufferEditor::BufferEditor(Buffer *b) } template -Buffer::BufferEditor::~BufferEditor() +TBuffer::BufferEditor::~BufferEditor() { glUnmapBuffer(m_typeEnum); glBindBuffer(m_typeEnum, 0); } template -Buffer::Buffer(const std::vector &data, BufferType type, bool isDynamic) : +TBuffer::TBuffer(const std::vector &data, BufferType type, bool isDynamic) : m_type(type), m_isDynamic(isDynamic) { @@ -62,7 +62,7 @@ Buffer::Buffer(const std::vector &data, BufferType type, bool isDynamic) : } template -void Buffer::setVertexAttrib(int location, int nbComponents, int offset, int instanceDivisor) +void TBuffer::setVertexAttrib(int location, int nbComponents, int offset, int instanceDivisor) { if(m_type == VBO && SparrowRenderer::isModernOpenGLAvailable()) { @@ -76,19 +76,19 @@ void Buffer::setVertexAttrib(int location, int nbComponents, int offset, int } template -void Buffer::bind() +void TBuffer::bind() { glBindBuffer(getGLEnum(m_type), m_id); } template -void Buffer::unbind() +void TBuffer::unbind() { glBindBuffer(getGLEnum(m_type), 0); } template -Buffer::~Buffer() +TBuffer::~TBuffer() { glDeleteBuffers(1, m_id); } diff --git a/src/buffer.h b/src/buffer.h index c75ffd6..8985f60 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -6,9 +6,17 @@ #define BUFFER_OFFSET(i) ((char *)NULL + (i)) -template class Buffer { +public: + virtual ~Buffer(); + virtual void bind() = 0; + virtual void unbind() = 0; +}; + +template +class TBuffer : public Buffer +{ public: enum BufferType { @@ -23,19 +31,19 @@ public: T *ptr; public: - BufferEditor(Buffer *b); + BufferEditor(TBuffer *b); ~BufferEditor(); T* getPointer(); }; - Buffer(const std::vector &data, BufferType type, bool isDynamic = false); - ~Buffer(); + TBuffer(const std::vector &data, BufferType type, bool isDynamic = false); + ~TBuffer(); - void setVertexAttrib(int location, int nbComponents, int offset = 0, int instanceDivisor = 0); + virtual void setVertexAttrib(int location, int nbComponents, int offset = 0, int instanceDivisor = 0); - void bind(); - void unbind(); + virtual void bind(); + virtual void unbind(); GLuint getId() {return m_id;} BufferType getType() {return m_type;} diff --git a/src/forwardmodule.cpp b/src/forwardmodule.cpp index 160f709..2f41af0 100644 --- a/src/forwardmodule.cpp +++ b/src/forwardmodule.cpp @@ -3,7 +3,7 @@ #include "mesh.h" #include "shader.h" #include "light.h" - +#include "phongmaterial.h" #include "texture.h" #include @@ -14,91 +14,60 @@ void ForwardModule::renderGL(Camera* myCamera, Scene* scene) if(clearBeforeDrawing) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glViewport(0, 0, width, height); - - // render ambient lighting - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - glDisable(GL_BLEND); - - lightPass(myCamera, scene, NULL); - - // render directionnal lighting and point lighting - glDepthFunc(GL_LEQUAL); - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE); - glDepthMask(GL_FALSE); - - for(SceneIterator* lightIt = scene->getLights(); lightIt->isValid(); lightIt->next()) - lightPass(myCamera, scene, lightIt->getItem()); - - glDisable(GL_BLEND); - glDepthFunc(GL_LESS); - glDepthMask(GL_TRUE); -} - -void ForwardModule::lightPass(Camera* myCamera, Scene* scene, Light* light) -{ - if(isWireframe){ - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - }else{ - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } - // loop over all types of geometry - for(std::size_t i=0; igetFlags()) - break; - if(j == lightFlagList.size()) + for(Light *light : p.lights) { - fprintf(stderr, "WARNING : missing shader for the light"); - continue; - } - Shader* shader = shaders[i*lightFlagList.size() + j]; - shader->bind(); - - // bind light attributes - 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()) + if(light->getFlags() & Light::AMBIENT_FLAG) { - 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); + // render ambient lighting (opaque) + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glDisable(GL_BLEND); } - 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(SceneIterator* geometryIt = scene->getGeometry(); - geometryIt->isValid(); geometryIt->next()) - { - GeometryNode* node = geometryIt->getItem(); - shader->bindUnsignedInteger(shader->getLocation("object_identifier"), id); - if(node->mesh->hasInstances()) - id += node->mesh->instances_offsets.size(); else - ++id; - Material* mat = node->mesh->material; - unsigned int flags = mat->getFlags(); - if(node->mesh->hasInstances()) - flags |= INSTANCING_FLAG; - if(flags == geometryFlagList[i]) // if flag matches material { + // 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; @@ -116,10 +85,12 @@ void ForwardModule::lightPass(Camera* myCamera, Scene* scene, Light* light) } } } + + glDisable(GL_BLEND); + glDepthFunc(GL_LESS); + glDepthMask(GL_TRUE); } -// modern opengl methods - void ForwardModule::setShaderSource(ShaderSource* source) { if(shaderSources != NULL) @@ -129,72 +100,44 @@ void ForwardModule::setShaderSource(ShaderSource* source) void ForwardModule::compileShaders(Scene* scene) { - geometryFlagList.clear(); - lightFlagList.clear(); - for(Shader* s : shaders) - delete(s); - shaders.clear(); - - // get material flags - const int nb_geometry_flags = 1 << NB_FLAGS; - bool geometryFlags[nb_geometry_flags]; - for(int i=0; i* geometryIt = scene->getGeometry(); geometryIt->isValid(); geometryIt->next()) { - Mesh* m = geometryIt->getItem()->mesh; - unsigned int flags = m->material->getFlags(); - if(m->hasInstances()) - flags |= INSTANCING_FLAG; - geometryFlags[flags] = true; + GeometryNode* n = geometryIt->getItem(); + geometry[n->mesh->getFlags()].push_back(n); } - for(int i=0; i* lightIt = scene->getLights(); lightIt->isValid(); lightIt->next()) { Light* l = lightIt->getItem(); - lightFlags[Light::getFlags(l)] = true; + lights[l->getFlags()].push_back(l); } - for(int i=0; icompile(geomFlags, ambientFlags), geomIt.second, lights[ambientFlags])); } - - // shader compilation - for(int i : geometryFlagList) + // compile a shader for each combination of a geometry flag and a light flag + for(const auto &lightIt : lights) { - std::vector defines; - - std::size_t boundary = defines.size(); - for(int j : lightFlagList) + unsigned int lightFlags = lightIt.first; + if(lightFlags != ambientFlags) // ambient shaders are already ready { - while(defines.size() > boundary) - defines.pop_back(); - // set light defines - for(int k=0; kcompile(geomFlags, lightFlags), geomIt.second, lightIt.second)); } - // compilation - shaders.push_back(shaderSources->compile(defines.size(), defines.data())); } } } diff --git a/src/forwardmodule.h b/src/forwardmodule.h index 9112df0..11544f8 100644 --- a/src/forwardmodule.h +++ b/src/forwardmodule.h @@ -9,8 +9,10 @@ #include "shadersource.h" #include "material.h" #include "framebuffer.h" +#include "light.h" +#include -class Light; +class GeometryNode; class Scene; class PhongEntity; @@ -20,9 +22,10 @@ public: ForwardModule() : shaderSources(NULL), renderTarget(FrameBuffer::screen), - isWireframe(false), clearBeforeDrawing(false) - {} + { + ambientLight.initAmbientLight(); + } virtual void renderGL(Camera* myCamera, Scene* scene); virtual bool requiresModernOpenGL() {return true;} @@ -34,23 +37,36 @@ public: void compileShaders(Scene* scene); void setRenderTarget(const FrameBuffer* target); - void setWireframe(bool wireframe) {isWireframe = wireframe;} void setClearBeforeDrawing(bool clear) {clearBeforeDrawing = clear;} private: + struct Pass + { + Shader* shader; + const std::vector &geometry; + const std::vector &lights; + + Pass(Shader *myShader, + const std::vector &geomIt, + const std::vector &lightIt) : + shader(myShader), + geometry(geomIt), + lights(lightIt) + {} + }; + + std::unordered_map> geometry; + std::unordered_map> lights; + Light ambientLight; + std::vector passes; ShaderSource* shaderSources; - std::set shaders; - std::vector geometryFlagList; - std::vector lightFlagList; + const FrameBuffer* renderTarget; int width; int height; - bool isWireframe; bool clearBeforeDrawing; - - void lightPass(Camera* myCamera, Scene* scene, Light* light); }; #endif // FORWARDMODULE_H diff --git a/src/light.cpp b/src/light.cpp index 1c7d23f..8c30571 100644 --- a/src/light.cpp +++ b/src/light.cpp @@ -28,7 +28,7 @@ Light::Light() initPointLight(); } -void Light::initAmbientLight(glm::vec3 lightColor = glm::vec3(0.1f)) +void Light::initAmbientLight(glm::vec3 lightColor) { type = AMBIENT; position = glm::vec3(0); @@ -99,10 +99,8 @@ void Light::initShadowMap(int resWidth, int resHeight, glm::vec3 dim) ShaderSource source; source.setSource(shadowVertSource, ShaderSource::VERTEX); source.setSource(shadowFragSource, ShaderSource::FRAGMENT); - std::vector defines; - shaders[0] = source.compile(defines.size(), defines.data()); - defines.push_back("ALPHA_MASK"); - shaders[1] = source.compile(defines.size(), defines.data()); + shaders[0] = source.compile(Mesh::MESH_3D, getFlags()); + shaders[1] = source.compile(Mesh::MESH_3D & Mesh::MATERIAL_ALPHA_MASK, getFlags()); } void Light::generateShadowMap(Scene* scene) @@ -119,26 +117,14 @@ void Light::generateShadowMap(Scene* scene) geometryIt->isValid(); geometryIt->next()) { GeometryNode* node = geometryIt->getItem(); - Material* mat = node->mesh->material; - if(((PhongMaterial*)mat)->castShadow) + if(node->mesh->getFlags() & Mesh::MESH_SHADOWED) { // compute matrix attributes glm::mat4 lightMVP = getProjectionMatrix() * (getViewMatrix() * node->modelMatrix); - if(mat->getFlags() & ALPHA_MASK_FLAG) - { - PhongMaterial* pmat = (PhongMaterial*)mat; - shaders[1]->bind(); - pmat->alpha_mask->bind(ALPHA_MASK); - shaders[1]->bindMat4(shaders[1]->getLocation("MVP"), lightMVP); - shaders[1]->bindInteger(shaders[1]->getLocation("alphaMask"), ALPHA_MASK); - node->mesh->draw(shaders[1], false, true, false); - } - else - { - shaders[0]->bind(); - shaders[0]->bindMat4(shaders[1]->getLocation("MVP"), lightMVP); - node->mesh->draw(shaders[0], false, false, false); - } + int hasAlpha = (node->mesh->getFlags() & Mesh::MATERIAL_ALPHA_MASK) > 0; + shaders[hasAlpha]->bind(); + shaders[hasAlpha]->bindMat4(shaders[hasAlpha]->getLocation("MVP"), lightMVP); + node->mesh->draw(shaders[hasAlpha], false, hasAlpha, false); } } glCullFace(GL_BACK); @@ -158,7 +144,7 @@ void Light::setPosition(glm::vec3 new_pos) unsigned int Light::getFlags() { unsigned int flags = 0; - switch(l->getType()) + switch(type) { case AMBIENT : flags = 1 << AMBIENT_FLAG; @@ -173,7 +159,7 @@ unsigned int Light::getFlags() flags = 1 << SPOT_FLAG; break; } - if(l->isShadowCaster()) + if(shadowCaster) flags |= 1 << SHADOWMAP_FLAG; return flags; } diff --git a/src/light.h b/src/light.h index b44561a..21ee895 100644 --- a/src/light.h +++ b/src/light.h @@ -27,7 +27,7 @@ public: POINT_FLAG, SPOT_FLAG, SHADOWMAP_FLAG, - NB_LIGHT_FLAGS + NB_FLAGS }; static const char* flagStr[]; static const glm::mat4 biasMatrix; diff --git a/src/mesh.cpp b/src/mesh.cpp index c49f4c4..5efc443 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -17,6 +17,7 @@ const char* const Mesh::flagStr[Mesh::NB_FLAGS] = "TANGENT_SPACE", "BILLBOARD", + "SHADOWED" "COLOR_TEXTURE", "ALPHA_MASK", @@ -34,6 +35,7 @@ Mesh::Mesh() : material(NULL), isDoubleSided(false), isBillboard(false), + isShadowCaster(true), depth(0), vao(0), primitive_type(GL_TRIANGLES) @@ -74,21 +76,21 @@ void Mesh::initGL() // init positions VBO if(!positions3D.empty()) { - b = new Buffer(positions3D, Buffer::VBO); + b = new TBuffer(positions3D, TBuffer::VBO); b->setVertexAttrib(0, 3); addBuffer(b, POSITION_BUFFER); // init normals vbo if(!normals.empty()) { - b = new Buffer(normals, Buffer::VBO); + b = new TBuffer(normals, TBuffer::VBO); b->setVertexAttrib(1, 3); addBuffer(b, NORMAL_BUFFER); } // init tangents vbo if(!tangents.empty()) { - b = new Buffer(tangents, Buffer::VBO); + b = new TBuffer(tangents, TBuffer::VBO); b->setVertexAttrib(3, 3); b->setVertexAttrib(4, 3); addBuffer(b, TANGENT_BUFFER); @@ -96,7 +98,7 @@ void Mesh::initGL() } else if(!positions2D.empty()) { - b = new Buffer(positions2D, Buffer::VBO); + b = new TBuffer(positions2D, TBuffer::VBO); b->setVertexAttrib(0, 2); addBuffer(b, POSITION_BUFFER); } @@ -108,7 +110,7 @@ void Mesh::initGL() // init texCoords vbo if(!texCoords.empty()) { - b = new Buffer(texCoords, Buffer::VBO); + b = new TBuffer(texCoords, TBuffer::VBO); b->setVertexAttrib(2, 2); addBuffer(b, TEXCOORD_BUFFER); } @@ -116,7 +118,7 @@ void Mesh::initGL() // init instances vbo if(!instances_offsets.empty()) { - b = new Buffer(instances_offsets, Buffer::VBO); + b = new TBuffer(instances_offsets, TBuffer::VBO); b->setVertexAttrib(5, 3, 0, 1); addBuffer(b, INSTANCE_BUFFER); } @@ -124,7 +126,7 @@ void Mesh::initGL() // init EBO if(!indices.empty()) { - b = new Buffer(indices, Buffer::EBO); + b = new TBuffer(indices, TBuffer::EBO); addBuffer(b, INDICES_BUFFER); } diff --git a/src/mesh.h b/src/mesh.h index 19e9918..7540467 100644 --- a/src/mesh.h +++ b/src/mesh.h @@ -32,6 +32,7 @@ public: // 3D Geometric properties MESH_TANGENT_SPACE, MESH_BILLBOARD, + MESH_SHADOWED, // simple material (no lighting) MATERIAL_COLOR_TEXTURE, @@ -145,6 +146,12 @@ public: * a billboard mesh will always follow the camera orientation */ void setIsBillboard(bool val) {isBillboard = val;} + + /** + * @brief setIsShadowCaster allows to enable or disable, + * rendering of this mesh in the shadowmaps + */ + void setIsShadowCaster(bool val) {isShadowCaster = val;} /*************************************************************/ /* 3D MESH TOOLS */ @@ -196,6 +203,7 @@ protected: Material* material; bool isDoubleSided; bool isBillboard; + bool isShadowCaster; float depth; GLenum primitive_type; diff --git a/src/phongmaterial.h b/src/phongmaterial.h index f4e1841..487fa91 100644 --- a/src/phongmaterial.h +++ b/src/phongmaterial.h @@ -9,16 +9,6 @@ class Texture; class PhongMaterial : public Material { private: - enum TextureSlots - { - DIFFUSE_SLOT, - AMBIENT_SLOT, - NORMALS_SLOT, - SPECULAR_SLOT, - ALPHA_SLOT, - NB_PHONG_SLOTS - }; - glm::vec3 ambient; glm::vec3 diffuse; glm::vec3 specular; @@ -31,6 +21,15 @@ private: Texture* alpha_mask; public: + enum TextureSlots + { + DIFFUSE_SLOT, + AMBIENT_SLOT, + NORMALS_SLOT, + SPECULAR_SLOT, + ALPHA_SLOT, + NB_PHONG_SLOTS + }; PhongMaterial() : ambient(0), diff --git a/src/shadersource.cpp b/src/shadersource.cpp index 63a6617..e4d57c2 100644 --- a/src/shadersource.cpp +++ b/src/shadersource.cpp @@ -4,6 +4,7 @@ #include #include "shader.h" #include "mesh.h" +#include "light.h" ShaderSource::ShaderSource() { @@ -31,11 +32,19 @@ void ShaderSource::setSource(const char *source, SourceType type) Shader* ShaderSource::compile(unsigned int geomFlags, unsigned int lightFlags) { std::string header = "#version 330 core"; - for(int i=0; i> i) & 0x00000001) - header += "\n#define "+std::string(flagStr[i]); + header += "\n#define "+std::string(Mesh::flagStr[i]); } + + for(int i=0; i> i) & 0x00000001) + header += "\n#define "+std::string(Light::flagStr[i]); + } + header += "\n#line 1\n"; if(sources[VERTEX] == NULL || sources[FRAGMENT] == NULL) diff --git a/src/shadersource.h b/src/shadersource.h index 4697b9e..ed70e2e 100644 --- a/src/shadersource.h +++ b/src/shadersource.h @@ -21,7 +21,7 @@ public: void setSource(const char *source, SourceType type); - Shader* compile(int nbDefines = 0, const char** defines = NULL); + Shader* compile(unsigned int geomFlags, unsigned int lightFlags); private: std::string* sources[NB_TYPES];