diff --git a/data/shaders/instanced_grass.vert b/data/shaders/instanced_grass.vert new file mode 100644 index 000000000..d12261cbe --- /dev/null +++ b/data/shaders/instanced_grass.vert @@ -0,0 +1,25 @@ +uniform vec3 windDir; +uniform mat4 ViewProjectionMatrix; +uniform mat4 ViewMatrix; + +in vec3 Origin; +in vec3 Orientation; + +in vec3 Position; +in vec3 Normal; +in vec2 Texcoord; +in vec4 Color; + +out vec3 nor; +out vec2 uv; + + +void main() +{ + mat4 ModelMatrix = mat4(1.); + ModelMatrix[3].xyz += Origin; + mat4 TransposeInverseModelView = transpose(inverse(ViewMatrix * ModelMatrix)); + gl_Position = ViewProjectionMatrix * ModelMatrix * vec4(Position + windDir * Color.r, 1.); + nor = (TransposeInverseModelView * vec4(Normal, 0.)).xyz; + uv = Texcoord; +} diff --git a/src/graphics/shaders.cpp b/src/graphics/shaders.cpp index 364b09275..26004c88c 100644 --- a/src/graphics/shaders.cpp +++ b/src/graphics/shaders.cpp @@ -319,8 +319,10 @@ void Shaders::loadShaders() MeshShader::ObjectPass1Shader::init(); MeshShader::ObjectRefPass1Shader::init(); MeshShader::InstancedObjectPass1Shader::init(); + MeshShader::InstancedGrassPass1Shader::init(); MeshShader::ObjectPass2Shader::init(); MeshShader::InstancedObjectPass2Shader::init(); + MeshShader::InstancedGrassPass2Shader::init(); MeshShader::DetailledObjectPass2Shader::init(); MeshShader::ObjectRimLimitShader::init(); MeshShader::UntexturedObjectShader::init(); @@ -528,6 +530,42 @@ namespace MeshShader glUniformMatrix4fv(uniform_VM, 1, GL_FALSE, ViewMatrix.pointer()); } + GLuint InstancedGrassPass1Shader::Program; + GLuint InstancedGrassPass1Shader::attrib_position; + GLuint InstancedGrassPass1Shader::attrib_normal; + GLuint InstancedGrassPass1Shader::attrib_origin; + GLuint InstancedGrassPass1Shader::attrib_texcoord; + GLuint InstancedGrassPass1Shader::attrib_color; + GLuint InstancedGrassPass1Shader::uniform_MP; + GLuint InstancedGrassPass1Shader::uniform_VM; + GLuint InstancedGrassPass1Shader::uniform_windDir; + GLuint InstancedGrassPass1Shader::uniform_tex; + + void InstancedGrassPass1Shader::init() + { + Program = LoadProgram( + GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanced_grass.vert").c_str(), + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/encode_normal.frag").c_str(), + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/objectref_pass1.frag").c_str()); + attrib_origin = glGetAttribLocation(Program, "Origin"); + attrib_position = glGetAttribLocation(Program, "Position"); + attrib_normal = glGetAttribLocation(Program, "Normal"); + attrib_color = glGetAttribLocation(Program, "Color"); + attrib_texcoord = glGetAttribLocation(Program, "Texcoord"); + uniform_MP = glGetUniformLocation(Program, "ViewProjectionMatrix"); + uniform_VM = glGetUniformLocation(Program, "ViewMatrix"); + uniform_windDir = glGetUniformLocation(Program, "windDir"); + uniform_tex = glGetUniformLocation(Program, "tex"); + } + + void InstancedGrassPass1Shader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &ViewMatrix, const core::vector3df &windDir, unsigned TU_tex) + { + glUniformMatrix4fv(uniform_MP, 1, GL_FALSE, ModelViewProjectionMatrix.pointer()); + glUniformMatrix4fv(uniform_VM, 1, GL_FALSE, ViewMatrix.pointer()); + glUniform3f(uniform_windDir, windDir.X, windDir.Y, windDir.Z); + glUniform1i(uniform_tex, TU_tex); + } + // Solid Lit pass shaders GLuint ObjectPass2Shader::Program; @@ -871,6 +909,52 @@ namespace MeshShader glUniform3f(uniform_windDir, windDirection.X, windDirection.Y, windDirection.Z); } + GLuint InstancedGrassPass2Shader::Program; + GLuint InstancedGrassPass2Shader::attrib_position; + GLuint InstancedGrassPass2Shader::attrib_texcoord; + GLuint InstancedGrassPass2Shader::attrib_color; + GLuint InstancedGrassPass2Shader::uniform_VP; + GLuint InstancedGrassPass2Shader::uniform_screen; + GLuint InstancedGrassPass2Shader::uniform_ambient; + GLuint InstancedGrassPass2Shader::uniform_windDir; + GLuint InstancedGrassPass2Shader::TU_Albedo; + + void InstancedGrassPass2Shader::init() + { + Program = LoadProgram( + GL_VERTEX_SHADER, file_manager->getAsset("shaders/instanced_grass.vert").c_str(), + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getLightFactor.frag").c_str(), + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/objectref_pass2.frag").c_str()); + attrib_position = glGetAttribLocation(Program, "Position"); + attrib_texcoord = glGetAttribLocation(Program, "Texcoord"); + attrib_color = glGetAttribLocation(Program, "Color"); + uniform_VP = glGetUniformLocation(Program, "ViewProjectionMatrix"); + GLuint uniform_Albedo = glGetUniformLocation(Program, "Albedo"); + GLuint uniform_DiffuseMap = glGetUniformLocation(Program, "DiffuseMap"); + GLuint uniform_SpecularMap = glGetUniformLocation(Program, "SpecularMap"); + GLuint uniform_SSAO = glGetUniformLocation(Program, "SSAO"); + uniform_screen = glGetUniformLocation(Program, "screen"); + uniform_ambient = glGetUniformLocation(Program, "ambient"); + uniform_windDir = glGetUniformLocation(Program, "windDir"); + TU_Albedo = 3; + + glUseProgram(Program); + glUniform1i(uniform_DiffuseMap, 0); + glUniform1i(uniform_SpecularMap, 1); + glUniform1i(uniform_SSAO, 2); + glUniform1i(uniform_Albedo, TU_Albedo); + glUseProgram(0); + } + + void InstancedGrassPass2Shader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::vector3df &windDirection) + { + glUniformMatrix4fv(uniform_VP, 1, GL_FALSE, ModelViewProjectionMatrix.pointer()); + glUniform2f(uniform_screen, UserConfigParams::m_width, UserConfigParams::m_height); + const video::SColorf s = irr_driver->getSceneManager()->getAmbientLight(); + glUniform3f(uniform_ambient, s.r, s.g, s.b); + glUniform3f(uniform_windDir, windDirection.X, windDirection.Y, windDirection.Z); + } + GLuint SphereMapShader::Program; GLuint SphereMapShader::attrib_position; GLuint SphereMapShader::attrib_normal; diff --git a/src/graphics/shaders.hpp b/src/graphics/shaders.hpp index e68d00848..a4ee2b631 100644 --- a/src/graphics/shaders.hpp +++ b/src/graphics/shaders.hpp @@ -88,6 +88,17 @@ public: static void setUniforms(const core::matrix4 &ViewProjectionMatrix, const core::matrix4 &ViewMatrix); }; +class InstancedGrassPass1Shader +{ +public: + static GLuint Program; + static GLuint attrib_position, attrib_normal, attrib_origin, attrib_color, attrib_texcoord; + static GLuint uniform_MP, uniform_VM, uniform_windDir, uniform_tex; + + static void init(); + static void setUniforms(const core::matrix4 &ViewProjectionMatrix, const core::matrix4 &ViewMatrix, const core::vector3df &windDir, unsigned TU_tex); +}; + class ObjectPass2Shader { public: @@ -183,6 +194,18 @@ public: static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::vector3df &windDirection); }; +class InstancedGrassPass2Shader +{ +public: + static GLuint Program; + static GLuint attrib_position, attrib_texcoord, attrib_color, attrib_origin; + static GLuint uniform_VP, uniform_TM, uniform_screen, uniform_ambient, uniform_windDir; + static GLuint TU_Albedo; + + static void init(); + static void setUniforms(const core::matrix4 &ViewProjectionMatrix, const core::vector3df &windDirection); +}; + class SphereMapShader { public: diff --git a/src/graphics/stkinstancedscenenode.cpp b/src/graphics/stkinstancedscenenode.cpp index d562dbdb2..bbe1a0c5e 100644 --- a/src/graphics/stkinstancedscenenode.cpp +++ b/src/graphics/stkinstancedscenenode.cpp @@ -29,6 +29,10 @@ void STKInstancedSceneNode::initinstancedvaostate(GLMesh &mesh, GeometricMateria mesh.vao_first_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, MeshShader::InstancedObjectPass1Shader::attrib_position, -1, -1, MeshShader::InstancedObjectPass1Shader::attrib_normal, -1, -1, -1, mesh.Stride); break; + case FPSM_GRASS: + mesh.vao_first_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, + MeshShader::InstancedGrassPass1Shader::attrib_position, MeshShader::InstancedGrassPass1Shader::attrib_texcoord, -1, MeshShader::InstancedGrassPass1Shader::attrib_normal, -1, -1, MeshShader::InstancedGrassPass1Shader::attrib_color, mesh.Stride); + break; default: return; } @@ -46,6 +50,10 @@ void STKInstancedSceneNode::initinstancedvaostate(GLMesh &mesh, GeometricMateria mesh.vao_second_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, MeshShader::InstancedObjectPass2Shader::attrib_position, MeshShader::InstancedObjectPass2Shader::attrib_texcoord, -1, -1, -1, -1, -1, mesh.Stride); break; + case SM_GRASS: + mesh.vao_second_pass = createVAO(mesh.vertex_buffer, mesh.index_buffer, + MeshShader::InstancedGrassPass2Shader::attrib_position, MeshShader::InstancedGrassPass2Shader::attrib_texcoord, -1, -1, -1, -1, MeshShader::InstancedGrassPass2Shader::attrib_color, mesh.Stride); + break; default: return; } @@ -97,11 +105,24 @@ static void drawFSPMDefault(GLMesh &mesh, const core::matrix4 &ModelViewProjecti MeshShader::InstancedObjectPass1Shader::setUniforms(ModelViewProjectionMatrix, irr_driver->getVideoDriver()->getTransform(video::ETS_VIEW)); - printf("instance count is %d\n", instance_count); glBindVertexArray(mesh.vao_first_pass); glDrawElementsInstanced(ptype, count, itype, 0, instance_count); } +static void drawFSPMGrass(GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, const core::vector3df &windDir, size_t instance_count) +{ + irr_driver->IncreaseObjectCount(); + GLenum ptype = mesh.PrimitiveType; + GLenum itype = mesh.IndexType; + size_t count = mesh.IndexCount; + + setTexture(0, mesh.textures[0], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); + MeshShader::InstancedGrassPass1Shader::setUniforms(ModelViewProjectionMatrix, irr_driver->getVideoDriver()->getTransform(video::ETS_VIEW), windDir, 0); + + glBindVertexArray(mesh.vao_first_pass); + glDrawElementsInstanced(ptype, count, itype, 0, instance_count); +} + static void drawSMDefault(GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, size_t instance_count) { irr_driver->IncreaseObjectCount(); @@ -113,11 +134,25 @@ static void drawSMDefault(GLMesh &mesh, const core::matrix4 &ModelViewProjection MeshShader::InstancedObjectPass2Shader::setUniforms(ModelViewProjectionMatrix, core::matrix4::EM4CONST_IDENTITY); - assert(mesh.vao_second_pass); glBindVertexArray(mesh.vao_second_pass); glDrawElementsInstanced(ptype, count, itype, 0, instance_count); } +static void drawSMGrass(GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix, const core::vector3df &windDir, size_t instance_count) +{ + irr_driver->IncreaseObjectCount(); + GLenum ptype = mesh.PrimitiveType; + GLenum itype = mesh.IndexType; + size_t count = mesh.IndexCount; + + setTexture(MeshShader::InstancedGrassPass2Shader::TU_Albedo, mesh.textures[0], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); + + MeshShader::InstancedGrassPass2Shader::setUniforms(ModelViewProjectionMatrix, windDir); + + glBindVertexArray(mesh.vao_second_pass); + glDrawElementsInstanced(ptype, count, itype, 0, instance_count); +} + void STKInstancedSceneNode::render() { setFirstTimeMaterial(); @@ -127,17 +162,30 @@ void STKInstancedSceneNode::render() ModelViewProjectionMatrix = irr_driver->getVideoDriver()->getTransform(video::ETS_PROJECTION); ModelViewProjectionMatrix *= irr_driver->getVideoDriver()->getTransform(video::ETS_VIEW); - glUseProgram(MeshShader::InstancedObjectPass1Shader::Program); + if (!GeometricMesh[FPSM_DEFAULT].empty()) + glUseProgram(MeshShader::InstancedObjectPass1Shader::Program); for (unsigned i = 0; i < GeometricMesh[FPSM_DEFAULT].size(); i++) drawFSPMDefault(*GeometricMesh[FPSM_DEFAULT][i], ModelViewProjectionMatrix, instance_pos.size() / 3); + + windDir = getWind(); + if (!GeometricMesh[FPSM_GRASS].empty()) + glUseProgram(MeshShader::InstancedGrassPass1Shader::Program); + for (unsigned i = 0; i < GeometricMesh[FPSM_GRASS].size(); i++) + drawFSPMGrass(*GeometricMesh[FPSM_GRASS][i], ModelViewProjectionMatrix, windDir, instance_pos.size() / 3); return; } if (irr_driver->getPhase() == SOLID_LIT_PASS) { - glUseProgram(MeshShader::InstancedObjectPass2Shader::Program); + if (!ShadedMesh[SM_DEFAULT].empty()) + glUseProgram(MeshShader::InstancedObjectPass2Shader::Program); for (unsigned i = 0; i < ShadedMesh[FPSM_DEFAULT].size(); i++) drawSMDefault(*ShadedMesh[FPSM_DEFAULT][i], ModelViewProjectionMatrix, instance_pos.size() / 3); + + if (!ShadedMesh[SM_GRASS].empty()) + glUseProgram(MeshShader::InstancedGrassPass2Shader::Program); + for (unsigned i = 0; i < ShadedMesh[SM_GRASS].size(); i++) + drawSMGrass(*ShadedMesh[SM_GRASS][i], ModelViewProjectionMatrix, windDir, instance_pos.size() / 3); return; } } diff --git a/src/graphics/stkinstancedscenenode.hpp b/src/graphics/stkinstancedscenenode.hpp index 96a82e792..fead359a8 100644 --- a/src/graphics/stkinstancedscenenode.hpp +++ b/src/graphics/stkinstancedscenenode.hpp @@ -16,6 +16,7 @@ protected: bool isMaterialInitialized; void setFirstTimeMaterial(); void initinstancedvaostate(GLMesh &mesh, GeometricMaterial GeoMat, ShadedMaterial ShadedMat); + core::vector3df windDir; public: STKInstancedSceneNode(irr::scene::IMesh* mesh, ISceneNode* parent, irr::scene::ISceneManager* mgr, irr::s32 id, const irr::core::vector3df& position = irr::core::vector3df(0, 0, 0), diff --git a/src/graphics/stkmesh.cpp b/src/graphics/stkmesh.cpp index 8f1f07d22..2a0b8084e 100644 --- a/src/graphics/stkmesh.cpp +++ b/src/graphics/stkmesh.cpp @@ -205,6 +205,21 @@ void computeTIMV(core::matrix4 &TransposeInverseModelView) TransposeInverseModelView = TransposeInverseModelView.getTransposed(); } +core::vector3df getWind() +{ + const core::vector3df pos = irr_driver->getVideoDriver()->getTransform(video::ETS_WORLD).getTranslation(); + const float time = irr_driver->getDevice()->getTimer()->getTime() / 1000.0f; + GrassShaderProvider *gsp = (GrassShaderProvider *)irr_driver->getCallback(ES_GRASS); + float m_speed = gsp->getSpeed(), m_amplitude = gsp->getAmplitude(); + + float strength = (pos.X + pos.Y + pos.Z) * 1.2f + time * m_speed; + strength = noise2d(strength / 10.0f) * m_amplitude * 5; + // * 5 is to work with the existing amplitude values. + + // Pre-multiply on the cpu + return irr_driver->getWind() * strength; +} + void drawObjectPass1(const GLMesh &mesh, const core::matrix4 & ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView) { irr_driver->IncreaseObjectCount(); diff --git a/src/graphics/stkmesh.hpp b/src/graphics/stkmesh.hpp index d24834ed7..576fee180 100644 --- a/src/graphics/stkmesh.hpp +++ b/src/graphics/stkmesh.hpp @@ -64,6 +64,8 @@ void computeMVP(core::matrix4 &ModelViewProjectionMatrix); void computeTIMV(core::matrix4 &TransposeInverseModelView); bool isObject(video::E_MATERIAL_TYPE type); +core::vector3df getWind(); + // Pass 1 shader (ie shaders that outputs normals and depth) void drawObjectPass1(const GLMesh &mesh, const core::matrix4 & ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView); void drawNormalPass(const GLMesh &mesh, const core::matrix4 & ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView);