diff --git a/data/shaders/instanciedshadow.vert b/data/shaders/instanciedshadow.vert new file mode 100644 index 000000000..64cefb5c8 --- /dev/null +++ b/data/shaders/instanciedshadow.vert @@ -0,0 +1,14 @@ +in vec3 Origin; +in vec3 Orientation; +in vec3 Scale; + +in vec3 Position; + +mat4 getWorldMatrix(vec3 translation, vec3 rotation, vec3 scale); +mat4 getInverseWorldMatrix(vec3 translation, vec3 rotation, vec3 scale); + +void main(void) +{ + mat4 ModelMatrix = getWorldMatrix(Origin, Orientation, Scale); + gl_Position = ModelMatrix * vec4(Position, 1.); +} \ No newline at end of file diff --git a/data/shaders/shadow.geom b/data/shaders/shadow.geom index 2eef2aa72..02681265b 100644 --- a/data/shaders/shadow.geom +++ b/data/shaders/shadow.geom @@ -1,4 +1,4 @@ -uniform mat4 ModelViewProjectionMatrix[4]; +uniform mat4 ViewProjectionMatrix[4]; #if __VERSION__ >= 400 layout(triangles, invocations=4) in; @@ -17,7 +17,7 @@ void emitToLayer(int layerId) for(int i=0; i<3; i++) { uv = tc[i]; - gl_Position = ModelViewProjectionMatrix[layerId] * gl_in[i].gl_Position; + gl_Position = ViewProjectionMatrix[layerId] * gl_in[i].gl_Position; EmitVertex(); } EndPrimitive(); diff --git a/data/shaders/shadow.vert b/data/shaders/shadow.vert index e58ec7c63..e7e382f7d 100644 --- a/data/shaders/shadow.vert +++ b/data/shaders/shadow.vert @@ -1,10 +1,10 @@ +uniform mat4 ModelMatrix; + in vec3 Position; in vec2 Texcoord; - out vec2 tc; - void main(void) { tc = Texcoord; diff --git a/src/graphics/shaders.cpp b/src/graphics/shaders.cpp index cf3f9cd77..62f632a33 100644 --- a/src/graphics/shaders.cpp +++ b/src/graphics/shaders.cpp @@ -344,6 +344,7 @@ void Shaders::loadShaders() MeshShader::DisplaceShader::init(); MeshShader::DisplaceMaskShader::init(); MeshShader::ShadowShader::init(); + MeshShader::InstancedShadowShader::init(); MeshShader::RefShadowShader::init(); MeshShader::GrassShadowShader::init(); MeshShader::SkyboxShader::init(); @@ -1379,7 +1380,8 @@ namespace MeshShader GLuint ShadowShader::Program; GLuint ShadowShader::attrib_position; - GLuint ShadowShader::uniform_MVP; + GLuint ShadowShader::uniform_VP; + GLuint ShadowShader::uniform_MM; void ShadowShader::init() { @@ -1394,17 +1396,57 @@ namespace MeshShader GL_GEOMETRY_SHADER, file_manager->getAsset("shaders/shadow.geom").c_str(), GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/white.frag").c_str()); attrib_position = glGetAttribLocation(Program, "Position"); - uniform_MVP = glGetUniformLocation(Program, "ModelViewProjectionMatrix"); + uniform_VP = glGetUniformLocation(Program, "ViewProjectionMatrix[0]"); + uniform_MM = glGetUniformLocation(Program, "ModelMatrix"); } - void ShadowShader::setUniforms(const std::vector &ModelViewProjectionMatrix) + void ShadowShader::setUniforms(const core::matrix4 &ModelMatrix, const std::vector &ViewProjectionMatrix) { - size_t size = ModelViewProjectionMatrix.size(); + size_t size = ViewProjectionMatrix.size(); float *tmp = new float[16 * size]; for (unsigned i = 0; i < size; i++) { - memcpy(&tmp[16 * i], ModelViewProjectionMatrix[i].pointer(), 16 * sizeof(float)); + memcpy(&tmp[16 * i], ViewProjectionMatrix[i].pointer(), 16 * sizeof(float)); } - glUniformMatrix4fv(uniform_MVP, size, GL_FALSE, tmp); + glUniformMatrix4fv(uniform_VP, size, GL_FALSE, tmp); + glUniformMatrix4fv(uniform_MM, 1, GL_FALSE, ModelMatrix.pointer()); + delete[] tmp; + } + + GLuint InstancedShadowShader::Program; + GLuint InstancedShadowShader::attrib_position; + GLuint InstancedShadowShader::attrib_origin; + GLuint InstancedShadowShader::attrib_orientation; + GLuint InstancedShadowShader::attrib_scale; + GLuint InstancedShadowShader::uniform_VP; + + void InstancedShadowShader::init() + { + // Geometry shader needed + if (irr_driver->getGLSLVersion() < 150) + { + attrib_position = -1; + return; + } + Program = LoadProgram( + GL_VERTEX_SHADER, file_manager->getAsset("shaders/utils/getworldmatrix.vert").c_str(), + GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanciedshadow.vert").c_str(), + GL_GEOMETRY_SHADER, file_manager->getAsset("shaders/shadow.geom").c_str(), + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/white.frag").c_str()); + attrib_position = glGetAttribLocation(Program, "Position"); + attrib_origin = glGetAttribLocation(Program, "Origin"); + attrib_orientation = glGetAttribLocation(Program, "Orientation"); + attrib_scale = glGetAttribLocation(Program, "Scale"); + uniform_VP = glGetUniformLocation(Program, "ViewProjectionMatrix[0]"); + } + + void InstancedShadowShader::setUniforms(const std::vector &ViewProjectionMatrix) + { + size_t size = ViewProjectionMatrix.size(); + float *tmp = new float[16 * size]; + for (unsigned i = 0; i < size; i++) { + memcpy(&tmp[16 * i], ViewProjectionMatrix[i].pointer(), 16 * sizeof(float)); + } + glUniformMatrix4fv(uniform_VP, size, GL_FALSE, tmp); delete[] tmp; } diff --git a/src/graphics/shaders.hpp b/src/graphics/shaders.hpp index 1bc18b7eb..2803edaee 100644 --- a/src/graphics/shaders.hpp +++ b/src/graphics/shaders.hpp @@ -326,10 +326,21 @@ class ShadowShader public: static GLuint Program; static GLuint attrib_position; - static GLuint uniform_MVP; + static GLuint uniform_VP, uniform_MM; static void init(); - static void setUniforms(const std::vector &ModelViewProjectionMatrix); + static void setUniforms(const core::matrix4 &ModelMatrix, const std::vector &ViewProjectionMatrix); +}; + +class InstancedShadowShader +{ +public: + static GLuint Program; + static GLuint attrib_position, attrib_origin, attrib_orientation, attrib_scale; + static GLuint uniform_VP; + + static void init(); + static void setUniforms(const std::vector &ViewProjectionMatrix); }; class RefShadowShader diff --git a/src/graphics/stkinstancedscenenode.cpp b/src/graphics/stkinstancedscenenode.cpp index e080a2a52..72cb76f82 100644 --- a/src/graphics/stkinstancedscenenode.cpp +++ b/src/graphics/stkinstancedscenenode.cpp @@ -76,6 +76,9 @@ void STKInstancedSceneNode::initinstancedvaostate(GLMesh &mesh, GeometricMateria glBindBuffer(GL_ARRAY_BUFFER, instances_vbo); glBufferData(GL_ARRAY_BUFFER, instance_pos.size() * sizeof(float), instance_pos.data(), GL_STATIC_DRAW); setInstanceAttribPointer(); + mesh.vao_shadow_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, MeshShader::InstancedShadowShader::attrib_position, -1, -1, -1, -1, -1, -1, mesh.Stride); + glBindBuffer(GL_ARRAY_BUFFER, instances_vbo); + setInstanceAttribPointer(); break; case FPSM_ALPHA_REF_TEXTURE: mesh.vao_first_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, @@ -178,6 +181,21 @@ static void drawFSPMDefault(GLMesh &mesh, const core::matrix4 &ModelViewProjecti glDrawElementsInstanced(ptype, count, itype, 0, instance_count); } +static void drawShadowDefault(GLMesh &mesh, size_t instance_count) +{ + irr_driver->IncreaseObjectCount(); + GLenum ptype = mesh.PrimitiveType; + GLenum itype = mesh.IndexType; + size_t count = mesh.IndexCount; + + std::vector ShadowMVP(irr_driver->getShadowViewProj()); + MeshShader::InstancedShadowShader::setUniforms(ShadowMVP); + + assert(mesh.vao_shadow_pass); + glBindVertexArray(mesh.vao_shadow_pass); + glDrawElementsInstanced(ptype, count, itype, 0, instance_count); +} + static void drawFSPMAlphaRefTexture(GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, size_t instance_count) { irr_driver->IncreaseObjectCount(); @@ -302,4 +320,13 @@ void STKInstancedSceneNode::render() drawSMGrass(*ShadedMesh[SM_GRASS][i], ModelViewProjectionMatrix, windDir, instance_pos.size() / 9); return; } + + if (irr_driver->getPhase() == SHADOW_PASS) + { + if (!GeometricMesh[FPSM_DEFAULT].empty()) + glUseProgram(MeshShader::InstancedShadowShader::Program); + for (unsigned i = 0; i < GeometricMesh[FPSM_DEFAULT].size(); i++) + drawShadowDefault(*GeometricMesh[FPSM_DEFAULT][i], instance_pos.size() / 9); + return; + } } diff --git a/src/graphics/stkmesh.cpp b/src/graphics/stkmesh.cpp index ab2733512..f9646269a 100644 --- a/src/graphics/stkmesh.cpp +++ b/src/graphics/stkmesh.cpp @@ -685,8 +685,6 @@ void drawShadow(const GLMesh &mesh) size_t count = mesh.IndexCount; std::vector ShadowMVP(irr_driver->getShadowViewProj()); - for (unsigned i = 0; i < ShadowMVP.size(); i++) - ShadowMVP[i] *= irr_driver->getVideoDriver()->getTransform(video::ETS_WORLD); /* if (type == irr_driver->getShader(ES_GRASS) || type == irr_driver->getShader(ES_GRASS_REF)) { @@ -695,7 +693,7 @@ void drawShadow(const GLMesh &mesh) MeshShader::GrassShadowShader::setUniforms(ShadowMVP, windDir, 0); }*/ - MeshShader::ShadowShader::setUniforms(ShadowMVP); + MeshShader::ShadowShader::setUniforms(irr_driver->getVideoDriver()->getTransform(video::ETS_WORLD), ShadowMVP); assert(mesh.vao_shadow_pass); glBindVertexArray(mesh.vao_shadow_pass);