diff --git a/src/Magnum/Shaders/Phong.frag b/src/Magnum/Shaders/Phong.frag index 42e05b121..01060818f 100644 --- a/src/Magnum/Shaders/Phong.frag +++ b/src/Magnum/Shaders/Phong.frag @@ -113,6 +113,16 @@ uniform highp uint objectId; /* defaults to zero */ #endif #if LIGHT_COUNT +/* Needs to be last because it uses locations 12 to 12 + LIGHT_COUNT - 1 */ +#ifdef EXPLICIT_UNIFORM_LOCATION +layout(location = 12) +#endif +uniform highp vec4 lightPositions[LIGHT_COUNT] + #ifndef GL_ES + = vec4[](LIGHT_POSITION_INITIALIZER) + #endif + ; + /* Needs to be last because it uses locations 12 + LIGHT_COUNT to 12 + 2*LIGHT_COUNT - 1. Location 12 is lightPositions. Also it can't be specified as 12 + LIGHT_COUNT because that requires ARB_enhanced_layouts. @@ -202,8 +212,7 @@ layout(std140 MaterialUniform materials[MATERIAL_COUNT]; }; -/* Keep in sync with Phong.vert. Can't "outsource" to a common file because - the #extension directive needs to be always before any code. */ +#if LIGHT_COUNT struct LightUniform { highp vec4 position; lowp vec3 colorReserved; @@ -214,7 +223,6 @@ struct LightUniform { #define light_range rangeReservedReservedReserved.x }; -#if LIGHT_COUNT layout(std140 #ifdef EXPLICIT_BINDING , binding = 5 @@ -293,8 +301,7 @@ in mediump vec3 transformedTangent; in mediump vec3 transformedBitangent; #endif #endif -in highp vec4 lightDirections[LIGHT_COUNT]; -in highp vec3 cameraDirection; +in highp vec3 transformedPosition; #endif #if defined(AMBIENT_TEXTURE) || defined(DIFFUSE_TEXTURE) || defined(SPECULAR_TEXTURE) || defined(NORMAL_TEXTURE) @@ -441,17 +448,26 @@ void main() { #endif ; + highp const vec4 lightPosition = + #ifndef UNIFORM_BUFFERS + lightPositions[i] + #else + lights[lightOffset + i].position + #endif + ; + highp const vec4 lightDirection = vec4(lightPosition.xyz - transformedPosition*lightPosition.w, lightPosition.w); + /* Attenuation. Directional lights have the .w component set to 0, use that to make the distance zero -- which will then ensure the attenuation is always 1.0 */ - highp float dist = length(lightDirections[i].xyz)*lightDirections[i].w; + highp float dist = length(lightDirection.xyz)*lightDirection.w; /* If range is 0 for whatever reason, clamp it to a small value to avoid a NaN when dist is 0 as well (which is the case for directional lights). */ highp float attenuation = clamp(1.0 - pow(dist/max(lightRange, 0.0001), 4.0), 0.0, 1.0); attenuation = attenuation*attenuation/(1.0 + dist*dist); - highp vec3 normalizedLightDirection = normalize(lightDirections[i].xyz); + highp vec3 normalizedLightDirection = normalize(lightDirection.xyz); lowp float intensity = max(0.0, dot(normalizedTransformedNormal, normalizedLightDirection))*attenuation; fragmentColor += vec4(finalDiffuseColor.rgb*lightColor*intensity, finalDiffuseColor.a/float( #ifndef UNIFORM_BUFFERS @@ -465,7 +481,7 @@ void main() { if(intensity > 0.001) { highp vec3 reflection = reflect(-normalizedLightDirection, normalizedTransformedNormal); /* Use attenuation for the specularity as well */ - mediump float specularity = clamp(pow(max(0.0, dot(normalize(cameraDirection), reflection)), shininess), 0.0, 1.0)*attenuation; + mediump float specularity = clamp(pow(max(0.0, dot(normalize(-transformedPosition), reflection)), shininess), 0.0, 1.0)*attenuation; fragmentColor += vec4(finalSpecularColor.rgb*lightSpecularColor.rgb*specularity, finalSpecularColor.a); } } diff --git a/src/Magnum/Shaders/Phong.vert b/src/Magnum/Shaders/Phong.vert index 2769fa980..4578d03e2 100644 --- a/src/Magnum/Shaders/Phong.vert +++ b/src/Magnum/Shaders/Phong.vert @@ -69,7 +69,7 @@ uniform highp mat4 projectionMatrix #endif ; -#if LIGHT_COUNT +#ifdef HAS_LIGHTS #ifdef EXPLICIT_UNIFORM_LOCATION layout(location = 2) #endif @@ -99,18 +99,6 @@ layout(location = 4) uniform highp uint textureLayer; /* defaults to zero */ #endif -#if LIGHT_COUNT -/* Needs to be last because it uses locations 11 to 11 + LIGHT_COUNT - 1 */ -#ifdef EXPLICIT_UNIFORM_LOCATION -layout(location = 12) -#endif -uniform highp vec4 lightPositions[LIGHT_COUNT] - #ifndef GL_ES - = vec4[](LIGHT_POSITION_INITIALIZER) - #endif - ; -#endif - /* Uniform buffers */ #else @@ -191,28 +179,6 @@ layout(std140 TextureTransformationUniform textureTransformations[DRAW_COUNT]; }; #endif - -#if LIGHT_COUNT -/* Keep in sync with Phong.frag. Can't "outsource" to a common file because - the #extension directive needs to be always before any code. */ -struct LightUniform { - highp vec4 position; - lowp vec3 colorReserved; - #define light_color colorReserved.xyz - lowp vec4 specularColorReserved; - #define light_specularColor specularColorReserved.xyz - lowp vec4 rangeReservedReservedReserved; - #define light_range rangeReservedReservedReserved.x -}; - -layout(std140 - #ifdef EXPLICIT_BINDING - , binding = 5 - #endif -) uniform Light { - LightUniform lights[LIGHT_COUNT]; -}; -#endif #endif /* Inputs */ @@ -222,7 +188,7 @@ layout(location = POSITION_ATTRIBUTE_LOCATION) #endif in highp vec4 position; -#if LIGHT_COUNT +#ifdef HAS_LIGHTS #ifdef EXPLICIT_ATTRIB_LOCATION layout(location = NORMAL_ATTRIBUTE_LOCATION) #endif @@ -315,7 +281,7 @@ out lowp vec4 interpolatedVertexColor; flat out highp uint interpolatedInstanceObjectId; #endif -#if LIGHT_COUNT +#ifdef HAS_LIGHTS out mediump vec3 transformedNormal; #ifdef NORMAL_TEXTURE #ifndef BITANGENT @@ -325,8 +291,7 @@ out mediump vec3 transformedTangent; out mediump vec3 transformedBitangent; #endif #endif -out highp vec4 lightDirections[LIGHT_COUNT]; -out highp vec3 cameraDirection; +out highp vec3 transformedPosition; #endif #ifdef MULTI_DRAW @@ -348,7 +313,7 @@ void main() { #endif highp const mat4 transformationMatrix = transformationMatrices[drawId]; - #if LIGHT_COUNT + #ifdef HAS_LIGHTS mediump const mat3 normalMatrix = mat3(draws[drawId].normalMatrix); #endif #ifdef TEXTURE_TRANSFORMATION @@ -357,9 +322,6 @@ void main() { highp const uint textureLayer = floatBitsToUint(textureTransformations[drawId].textureTransformation_layer); #endif #endif - #if LIGHT_COUNT - mediump const uint lightOffset = draws[drawId].draw_lightOffset; - #endif #endif /* Transformed vertex position */ @@ -368,9 +330,12 @@ void main() { instancedTransformationMatrix* #endif position; - highp vec3 transformedPosition = transformedPosition4.xyz/transformedPosition4.w; + #ifndef HAS_LIGHTS + highp vec3 + #endif + transformedPosition = transformedPosition4.xyz/transformedPosition4.w; - #if LIGHT_COUNT + #ifdef HAS_LIGHTS /* Transformed normal and tangent vector */ transformedNormal = normalMatrix* #ifdef INSTANCED_TRANSFORMATION @@ -397,27 +362,6 @@ void main() { bitangent; #endif #endif - - /* Direction to the light. Directional lights have the last component set - to 0, which gets used to ignore the transformed position. */ - #ifndef UNIFORM_BUFFERS - for(int i = 0; i < LIGHT_COUNT; ++i) - #else - for(uint i = 0u, actualLightCount = min(uint(LIGHT_COUNT), draws[drawId].draw_lightCount); i < actualLightCount; ++i) - #endif - { - highp const vec4 lightPosition = - #ifndef UNIFORM_BUFFERS - lightPositions[i] - #else - lights[lightOffset + i].position - #endif - ; - lightDirections[i] = vec4(lightPosition.xyz - transformedPosition*lightPosition.w, lightPosition.w); - } - - /* Direction to the camera */ - cameraDirection = -transformedPosition; #endif /* Transform the position */ diff --git a/src/Magnum/Shaders/PhongGL.cpp b/src/Magnum/Shaders/PhongGL.cpp index 0190c050e..586f15cbe 100644 --- a/src/Magnum/Shaders/PhongGL.cpp +++ b/src/Magnum/Shaders/PhongGL.cpp @@ -153,7 +153,7 @@ PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount GL::Shader frag = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Fragment); #ifndef MAGNUM_TARGET_GLES - std::string lightInitializerVertex, lightInitializerFragment; + std::string lightInitializer; if(!(flags >= Flag::UniformBuffers) && lightCount) { using namespace Containers::Literals; @@ -167,39 +167,37 @@ PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount constexpr Containers::StringView lightColorInitializerItem = "vec3(1.0), "_s; constexpr Containers::StringView lightRangeInitializerItem = "1.0/0.0, "_s; - lightInitializerVertex.reserve( + lightInitializer.reserve( lightPositionInitializerPreamble.size() + - lightCount*(lightPositionInitializerItem.size())); + lightColorInitializerPreamble.size() + + lightRangeInitializerPreamble.size() + + lightCount*(lightPositionInitializerItem.size() + + lightColorInitializerItem.size() + + lightRangeInitializerItem.size())); - lightInitializerVertex.append(lightPositionInitializerPreamble); + lightInitializer.append(lightPositionInitializerPreamble); for(std::size_t i = 0; i != lightCount; ++i) - lightInitializerVertex.append(lightPositionInitializerItem); + lightInitializer.append(lightPositionInitializerItem); /* Drop the last comma and add a newline at the end */ - lightInitializerVertex[lightInitializerVertex.size() - 2] = '\n'; - lightInitializerVertex.resize(lightInitializerVertex.size() - 1); - - lightInitializerFragment.reserve( - lightColorInitializerPreamble.size() + - lightRangeInitializerPreamble.size() + - lightCount*(lightColorInitializerItem.size() + - lightRangeInitializerItem.size())); + lightInitializer[lightInitializer.size() - 2] = '\n'; + lightInitializer.resize(lightInitializer.size() - 1); - lightInitializerFragment.append(lightColorInitializerPreamble); + lightInitializer.append(lightColorInitializerPreamble); for(std::size_t i = 0; i != lightCount; ++i) - lightInitializerFragment.append(lightColorInitializerItem); + lightInitializer.append(lightColorInitializerItem); /* Drop the last comma and add a newline at the end */ - lightInitializerFragment[lightInitializerFragment.size() - 2] = '\n'; - lightInitializerFragment.resize(lightInitializerFragment.size() - 1); + lightInitializer[lightInitializer.size() - 2] = '\n'; + lightInitializer.resize(lightInitializer.size() - 1); - lightInitializerFragment.append(lightRangeInitializerPreamble); + lightInitializer.append(lightRangeInitializerPreamble); for(std::size_t i = 0; i != lightCount; ++i) - lightInitializerFragment.append(lightRangeInitializerItem); + lightInitializer.append(lightRangeInitializerItem); /* Drop the last comma and add a newline at the end */ - lightInitializerFragment[lightInitializerFragment.size() - 2] = '\n'; - lightInitializerFragment.resize(lightInitializerFragment.size() - 1); + lightInitializer[lightInitializer.size() - 2] = '\n'; + lightInitializer.resize(lightInitializer.size() - 1); } #endif @@ -211,7 +209,7 @@ PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount #ifndef MAGNUM_TARGET_GLES2 .addSource(flags & Flag::TextureArrays ? "#define TEXTURE_ARRAYS\n" : "") #endif - .addSource(Utility::formatString("#define LIGHT_COUNT {}\n", lightCount)) + .addSource(lightCount ? "#define HAS_LIGHTS\n" : "") #ifndef MAGNUM_TARGET_GLES2 .addSource(flags >= Flag::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n" : "") #endif @@ -221,17 +219,12 @@ PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount if(flags >= Flag::UniformBuffers) { vert.addSource(Utility::formatString( "#define UNIFORM_BUFFERS\n" - "#define DRAW_COUNT {}\n" - "#define LIGHT_COUNT {}\n", + "#define DRAW_COUNT {}\n", drawCount, lightCount)); vert.addSource(flags >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : ""); } #endif - #ifndef MAGNUM_TARGET_GLES - if(!(flags >= Flag::UniformBuffers) && lightCount) - vert.addSource(std::move(lightInitializerVertex)); - #endif vert.addSource(rs.get("generic.glsl")) .addSource(rs.get("Phong.vert")); frag.addSource(flags & Flag::AmbientTexture ? "#define AMBIENT_TEXTURE\n" : "") @@ -275,7 +268,7 @@ PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount } #ifndef MAGNUM_TARGET_GLES if(!(flags >= Flag::UniformBuffers) && lightCount) - frag.addSource(std::move(lightInitializerFragment)); + frag.addSource(std::move(lightInitializer)); #endif frag.addSource(rs.get("generic.glsl")) .addSource(rs.get("Phong.frag"));