diff --git a/CHANGELOG.md b/CHANGELOG.md index 09cde80181..2eea3946b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -95,6 +95,7 @@ Feature #5492: Let rain and snow collide with statics Feature #6149: Dehardcode Lua API_REVISION Feature #6152: Playing music via lua scripts + Feature #6188: Specular lighting from point light sources Feature #6447: Add LOD support to Object Paging Feature #6491: Add support for Qt6 Feature #6556: Lua API for sounds diff --git a/components/sceneutil/lightcontroller.cpp b/components/sceneutil/lightcontroller.cpp index 98af5d21c8..caff6826f5 100644 --- a/components/sceneutil/lightcontroller.cpp +++ b/components/sceneutil/lightcontroller.cpp @@ -36,9 +36,11 @@ namespace SceneUtil // if (time == mLastTime) // return; + osg::Light* light = node->getLight(nv->getTraversalNumber()); + if (mType == LT_Normal) { - node->getLight(nv->getTraversalNumber())->setDiffuse(mDiffuseColor); + light->setDiffuse(mDiffuseColor); traverse(node, nv); return; } @@ -63,7 +65,10 @@ namespace SceneUtil mPhase = mPhase <= 0.5f ? 1.f : 0.25f; } - node->getLight(nv->getTraversalNumber())->setDiffuse(mDiffuseColor * mBrightness * node->getActorFade()); + osg::Vec4f result = mDiffuseColor * mBrightness * node->getActorFade(); + + light->setDiffuse(result); + light->setSpecular(result); traverse(node, nv); } diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 6bca92fdb4..8f7304416b 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -536,6 +536,7 @@ namespace SceneUtil configurePosition(lightMat, light->getPosition() * mViewMatrix); configureAmbient(lightMat, light->getAmbient()); configureDiffuse(lightMat, light->getDiffuse()); + configureSpecular(lightMat, light->getSpecular()); configureAttenuation(lightMat, light->getConstantAttenuation(), light->getLinearAttenuation(), light->getQuadraticAttenuation(), lightList[i]->mLightSource->getRadius()); @@ -1214,6 +1215,7 @@ namespace SceneUtil auto& buf = getUBOManager()->getLightBuffer(frameNum); buf->setDiffuse(index, light->getDiffuse()); buf->setAmbient(index, light->getAmbient()); + buf->setSpecular(index, light->getSpecular()); buf->setAttenuationRadius(index, osg::Vec4(light->getConstantAttenuation(), light->getLinearAttenuation(), light->getQuadraticAttenuation(), lightSource->getRadius())); diff --git a/components/sceneutil/lightutil.cpp b/components/sceneutil/lightutil.cpp index 9c0ebdf5c2..f69461fa3c 100644 --- a/components/sceneutil/lightutil.cpp +++ b/components/sceneutil/lightutil.cpp @@ -124,7 +124,7 @@ namespace SceneUtil } light->setDiffuse(diffuse); light->setAmbient(ambient); - light->setSpecular(osg::Vec4f(0, 0, 0, 0)); + light->setSpecular(diffuse); // ESM format doesn't provide specular lightSource->setLight(light); diff --git a/files/shaders/compatibility/bs/default.frag b/files/shaders/compatibility/bs/default.frag index 8c429947b0..f1be8da80c 100644 --- a/files/shaders/compatibility/bs/default.frag +++ b/files/shaders/compatibility/bs/default.frag @@ -95,7 +95,7 @@ void main() #endif if (matSpec != vec3(0.0)) - gl_FragData[0].xyz += getSpecular(viewNormal, normalize(passViewPos.xyz), shininess, matSpec) * shadowing; + gl_FragData[0].xyz += matSpec * getSpecular(viewNormal, passViewPos, shininess, shadowing); gl_FragData[0] = applyFogAtDist(gl_FragData[0], euclideanDepth, linearDepth, far); diff --git a/files/shaders/compatibility/objects.frag b/files/shaders/compatibility/objects.frag index 4caf6c97e2..b86678af87 100644 --- a/files/shaders/compatibility/objects.frag +++ b/files/shaders/compatibility/objects.frag @@ -242,7 +242,7 @@ vec3 viewNormal = normalize(gl_NormalMatrix * normal); matSpec *= specStrength; if (matSpec != vec3(0.0)) { - gl_FragData[0].xyz += getSpecular(viewNormal, viewVec, shininess, matSpec) * shadowing; + gl_FragData[0].xyz += matSpec * getSpecular(viewNormal, passViewPos, shininess, shadowing); } gl_FragData[0] = applyFogAtPos(gl_FragData[0], passViewPos, far); diff --git a/files/shaders/compatibility/terrain.frag b/files/shaders/compatibility/terrain.frag index a2fbddf3f7..744a56d18b 100644 --- a/files/shaders/compatibility/terrain.frag +++ b/files/shaders/compatibility/terrain.frag @@ -108,7 +108,7 @@ void main() if (matSpec != vec3(0.0)) { - gl_FragData[0].xyz += getSpecular(viewNormal, normalize(passViewPos), shininess, matSpec) * shadowing; + gl_FragData[0].xyz += matSpec * getSpecular(viewNormal, passViewPos, shininess, shadowing); } gl_FragData[0] = applyFogAtDist(gl_FragData[0], euclideanDepth, linearDepth, far); diff --git a/files/shaders/lib/light/lighting.glsl b/files/shaders/lib/light/lighting.glsl index 8c1262ba4d..8351fce8a0 100644 --- a/files/shaders/lib/light/lighting.glsl +++ b/files/shaders/lib/light/lighting.glsl @@ -90,15 +90,47 @@ void doLighting(vec3 viewPos, vec3 viewNormal, out vec3 diffuseLight, out vec3 a } } -vec3 getSpecular(vec3 viewNormal, vec3 viewDirection, float shininess, vec3 matSpec) +float calcSpecIntensity(vec3 viewNormal, vec3 viewDir, float shininess, vec3 lightDir) { - vec3 lightDir = normalize(lcalcPosition(0)); - float NdotL = dot(viewNormal, lightDir); - if (NdotL <= 0.0) - return vec3(0.0); - vec3 halfVec = normalize(lightDir - viewDirection); - float NdotH = dot(viewNormal, halfVec); - return pow(max(NdotH, 0.0), max(1e-4, shininess)) * lcalcSpecular(0).xyz * matSpec; + if (dot(viewNormal, lightDir) > 0.0) + { + vec3 halfVec = normalize(lightDir - viewDir); + float NdotH = max(dot(viewNormal, halfVec), 0.0); + return pow(NdotH, shininess); + } + + return 0.0; +} + +vec3 getSpecular(vec3 viewNormal, vec3 viewPos, float shininess, float shadowing) +{ + shininess = max(shininess, 1e-4); + vec3 viewDir = normalize(viewPos); + vec3 specularLight = lcalcSpecular(0).xyz * calcSpecIntensity(viewNormal, viewDir, shininess, normalize(lcalcPosition(0))); + specularLight *= shadowing; + + for (int i = @startLight; i < @endLight; ++i) + { +#if @lightingMethodUBO + int lightIndex = PointLightIndex[i]; +#else + int lightIndex = i; +#endif + + vec3 lightPos = lcalcPosition(lightIndex) - viewPos; + float lightDistance = length(lightPos); + +#if !@lightingMethodFFP + if (lightDistance > lcalcRadius(lightIndex) * 2.0) + continue; +#endif + + float illumination = lcalcIllumination(lightIndex, lightDistance); + float intensity = calcSpecIntensity(viewNormal, viewDir, shininess, normalize(lightPos)); + specularLight += lcalcSpecular(lightIndex).xyz * intensity * illumination; + } + + return specularLight; } #endif