|
|
@@ -290,180 +290,130 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
|
|
|
// Set light-related shader parameters
|
|
|
if (lightQueue_)
|
|
|
{
|
|
|
- if (lightQueue_->vertexLights_.Size() && graphics->HasShaderParameter(VSP_VERTEXLIGHTS) && graphics->NeedParameterUpdate(
|
|
|
- SP_LIGHT, reinterpret_cast<void*>((unsigned)(size_t)lightQueue_ + 0x80000000)))
|
|
|
- {
|
|
|
- Vector4 vertexLights[MAX_VERTEX_LIGHTS * 3];
|
|
|
- const PODVector<Light*>& lights = lightQueue_->vertexLights_;
|
|
|
-
|
|
|
- for (unsigned i = 0; i < lights.Size(); ++i)
|
|
|
- {
|
|
|
- Light* vertexLight = lights[i];
|
|
|
- Node* vertexLightNode = vertexLight->GetNode();
|
|
|
- LightType type = vertexLight->GetLightType();
|
|
|
-
|
|
|
- // Attenuation
|
|
|
- float invRange, cutoff, invCutoff;
|
|
|
- if (type == LIGHT_DIRECTIONAL)
|
|
|
- invRange = 0.0f;
|
|
|
- else
|
|
|
- invRange = 1.0f / Max(vertexLight->GetRange(), M_EPSILON);
|
|
|
- if (type == LIGHT_SPOT)
|
|
|
- {
|
|
|
- cutoff = Cos(vertexLight->GetFov() * 0.5f);
|
|
|
- invCutoff = 1.0f / (1.0f - cutoff);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- cutoff = -1.0f;
|
|
|
- invCutoff = 1.0f;
|
|
|
- }
|
|
|
-
|
|
|
- // Color
|
|
|
- float fade = 1.0f;
|
|
|
- float fadeEnd = vertexLight->GetDrawDistance();
|
|
|
- float fadeStart = vertexLight->GetFadeDistance();
|
|
|
-
|
|
|
- // Do fade calculation for light if both fade & draw distance defined
|
|
|
- if (vertexLight->GetLightType() != LIGHT_DIRECTIONAL && fadeEnd > 0.0f && fadeStart > 0.0f && fadeStart < fadeEnd)
|
|
|
- fade = Min(1.0f - (vertexLight->GetDistance() - fadeStart) / (fadeEnd - fadeStart), 1.0f);
|
|
|
-
|
|
|
- Color color = vertexLight->GetEffectiveColor() * fade;
|
|
|
- vertexLights[i * 3] = Vector4(color.r_, color.g_, color.b_, invRange);
|
|
|
-
|
|
|
- // Direction
|
|
|
- vertexLights[i * 3 + 1] = Vector4(-(vertexLightNode->GetWorldDirection()), cutoff);
|
|
|
-
|
|
|
- // Position
|
|
|
- vertexLights[i * 3 + 2] = Vector4(vertexLightNode->GetWorldPosition(), invCutoff);
|
|
|
- }
|
|
|
-
|
|
|
- graphics->SetShaderParameter(VSP_VERTEXLIGHTS, vertexLights[0].Data(), lights.Size() * 3 * 4);
|
|
|
- }
|
|
|
- else if (light && graphics->NeedParameterUpdate(SP_LIGHT, lightQueue_))
|
|
|
+ if (light && graphics->NeedParameterUpdate(SP_LIGHT, lightQueue_))
|
|
|
{
|
|
|
// Deferred light volume batches operate in a camera-centered space. Detect from material, zone & pass all being null
|
|
|
bool isLightVolume = !material_ && !pass_ && !zone_;
|
|
|
-
|
|
|
+
|
|
|
Matrix3x4 cameraEffectiveTransform = camera_->GetEffectiveWorldTransform();
|
|
|
Vector3 cameraEffectivePos = cameraEffectiveTransform.Translation();
|
|
|
-
|
|
|
+
|
|
|
Node* lightNode = light->GetNode();
|
|
|
Matrix3 lightWorldRotation = lightNode->GetWorldRotation().RotationMatrix();
|
|
|
-
|
|
|
+
|
|
|
graphics->SetShaderParameter(VSP_LIGHTDIR, lightWorldRotation * Vector3::BACK);
|
|
|
-
|
|
|
+
|
|
|
float atten = 1.0f / Max(light->GetRange(), M_EPSILON);
|
|
|
graphics->SetShaderParameter(VSP_LIGHTPOS, Vector4(lightNode->GetWorldPosition(), atten));
|
|
|
-
|
|
|
+
|
|
|
if (graphics->HasShaderParameter(VSP_LIGHTMATRICES))
|
|
|
{
|
|
|
switch (light->GetLightType())
|
|
|
{
|
|
|
case LIGHT_DIRECTIONAL:
|
|
|
- {
|
|
|
- Matrix4 shadowMatrices[MAX_CASCADE_SPLITS];
|
|
|
- unsigned numSplits = Min(MAX_CASCADE_SPLITS, (int)lightQueue_->shadowSplits_.Size());
|
|
|
-
|
|
|
- for (unsigned i = 0; i < numSplits; ++i)
|
|
|
- CalculateShadowMatrix(shadowMatrices[i], lightQueue_, i, renderer, Vector3::ZERO);
|
|
|
-
|
|
|
- graphics->SetShaderParameter(VSP_LIGHTMATRICES, shadowMatrices[0].Data(), 16 * numSplits);
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
+ {
|
|
|
+ Matrix4 shadowMatrices[MAX_CASCADE_SPLITS];
|
|
|
+ unsigned numSplits = Min(MAX_CASCADE_SPLITS, (int)lightQueue_->shadowSplits_.Size());
|
|
|
+
|
|
|
+ for (unsigned i = 0; i < numSplits; ++i)
|
|
|
+ CalculateShadowMatrix(shadowMatrices[i], lightQueue_, i, renderer, Vector3::ZERO);
|
|
|
+
|
|
|
+ graphics->SetShaderParameter(VSP_LIGHTMATRICES, shadowMatrices[0].Data(), 16 * numSplits);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
case LIGHT_SPOT:
|
|
|
- {
|
|
|
- Matrix4 shadowMatrices[2];
|
|
|
-
|
|
|
- CalculateSpotMatrix(shadowMatrices[0], light, Vector3::ZERO);
|
|
|
- bool isShadowed = shadowMap && graphics->HasTextureUnit(TU_SHADOWMAP);
|
|
|
- if (isShadowed)
|
|
|
- CalculateShadowMatrix(shadowMatrices[1], lightQueue_, 0, renderer, Vector3::ZERO);
|
|
|
-
|
|
|
- graphics->SetShaderParameter(VSP_LIGHTMATRICES, shadowMatrices[0].Data(), isShadowed ? 32 : 16);
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
+ {
|
|
|
+ Matrix4 shadowMatrices[2];
|
|
|
+
|
|
|
+ CalculateSpotMatrix(shadowMatrices[0], light, Vector3::ZERO);
|
|
|
+ bool isShadowed = shadowMap && graphics->HasTextureUnit(TU_SHADOWMAP);
|
|
|
+ if (isShadowed)
|
|
|
+ CalculateShadowMatrix(shadowMatrices[1], lightQueue_, 0, renderer, Vector3::ZERO);
|
|
|
+
|
|
|
+ graphics->SetShaderParameter(VSP_LIGHTMATRICES, shadowMatrices[0].Data(), isShadowed ? 32 : 16);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
case LIGHT_POINT:
|
|
|
- {
|
|
|
- Matrix4 lightVecRot(lightNode->GetWorldRotation().RotationMatrix());
|
|
|
- // HLSL compiler will pack the parameters as if the matrix is only 3x4, so must be careful to not overwrite
|
|
|
- // the next parameter
|
|
|
- #ifdef URHO3D_OPENGL
|
|
|
- graphics->SetShaderParameter(VSP_LIGHTMATRICES, lightVecRot.Data(), 16);
|
|
|
- #else
|
|
|
- graphics->SetShaderParameter(VSP_LIGHTMATRICES, lightVecRot.Data(), 12);
|
|
|
- #endif
|
|
|
- }
|
|
|
- break;
|
|
|
+ {
|
|
|
+ Matrix4 lightVecRot(lightNode->GetWorldRotation().RotationMatrix());
|
|
|
+ // HLSL compiler will pack the parameters as if the matrix is only 3x4, so must be careful to not overwrite
|
|
|
+ // the next parameter
|
|
|
+#ifdef URHO3D_OPENGL
|
|
|
+ graphics->SetShaderParameter(VSP_LIGHTMATRICES, lightVecRot.Data(), 16);
|
|
|
+#else
|
|
|
+ graphics->SetShaderParameter(VSP_LIGHTMATRICES, lightVecRot.Data(), 12);
|
|
|
+#endif
|
|
|
+ }
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
float fade = 1.0f;
|
|
|
float fadeEnd = light->GetDrawDistance();
|
|
|
float fadeStart = light->GetFadeDistance();
|
|
|
-
|
|
|
+
|
|
|
// Do fade calculation for light if both fade & draw distance defined
|
|
|
if (light->GetLightType() != LIGHT_DIRECTIONAL && fadeEnd > 0.0f && fadeStart > 0.0f && fadeStart < fadeEnd)
|
|
|
fade = Min(1.0f - (light->GetDistance() - fadeStart) / (fadeEnd - fadeStart), 1.0f);
|
|
|
-
|
|
|
+
|
|
|
// Negative lights will use subtract blending, so write absolute RGB values to the shader parameter
|
|
|
graphics->SetShaderParameter(PSP_LIGHTCOLOR, Color(light->GetEffectiveColor().Abs(),
|
|
|
light->GetEffectiveSpecularIntensity()) * fade);
|
|
|
graphics->SetShaderParameter(PSP_LIGHTDIR, lightWorldRotation * Vector3::BACK);
|
|
|
graphics->SetShaderParameter(PSP_LIGHTPOS, Vector4((isLightVolume ? (lightNode->GetWorldPosition() -
|
|
|
cameraEffectivePos) : lightNode->GetWorldPosition()), atten));
|
|
|
-
|
|
|
+
|
|
|
if (graphics->HasShaderParameter(PSP_LIGHTMATRICES))
|
|
|
{
|
|
|
switch (light->GetLightType())
|
|
|
{
|
|
|
case LIGHT_DIRECTIONAL:
|
|
|
+ {
|
|
|
+ Matrix4 shadowMatrices[MAX_CASCADE_SPLITS];
|
|
|
+ unsigned numSplits = Min(MAX_CASCADE_SPLITS, (int)lightQueue_->shadowSplits_.Size());
|
|
|
+
|
|
|
+ for (unsigned i = 0; i < numSplits; ++i)
|
|
|
{
|
|
|
- Matrix4 shadowMatrices[MAX_CASCADE_SPLITS];
|
|
|
- unsigned numSplits = Min(MAX_CASCADE_SPLITS, (int)lightQueue_->shadowSplits_.Size());
|
|
|
-
|
|
|
- for (unsigned i = 0; i < numSplits; ++i)
|
|
|
- {
|
|
|
- CalculateShadowMatrix(shadowMatrices[i], lightQueue_, i, renderer, isLightVolume ? cameraEffectivePos :
|
|
|
- Vector3::ZERO);
|
|
|
- }
|
|
|
- graphics->SetShaderParameter(PSP_LIGHTMATRICES, shadowMatrices[0].Data(), 16 * numSplits);
|
|
|
+ CalculateShadowMatrix(shadowMatrices[i], lightQueue_, i, renderer, isLightVolume ? cameraEffectivePos :
|
|
|
+ Vector3::ZERO);
|
|
|
}
|
|
|
- break;
|
|
|
-
|
|
|
+ graphics->SetShaderParameter(PSP_LIGHTMATRICES, shadowMatrices[0].Data(), 16 * numSplits);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
case LIGHT_SPOT:
|
|
|
+ {
|
|
|
+ Matrix4 shadowMatrices[2];
|
|
|
+
|
|
|
+ CalculateSpotMatrix(shadowMatrices[0], light, cameraEffectivePos);
|
|
|
+ bool isShadowed = lightQueue_->shadowMap_ != 0;
|
|
|
+ if (isShadowed)
|
|
|
{
|
|
|
- Matrix4 shadowMatrices[2];
|
|
|
-
|
|
|
- CalculateSpotMatrix(shadowMatrices[0], light, cameraEffectivePos);
|
|
|
- bool isShadowed = lightQueue_->shadowMap_ != 0;
|
|
|
- if (isShadowed)
|
|
|
- {
|
|
|
- CalculateShadowMatrix(shadowMatrices[1], lightQueue_, 0, renderer, isLightVolume ? cameraEffectivePos :
|
|
|
- Vector3::ZERO);
|
|
|
- }
|
|
|
-
|
|
|
- graphics->SetShaderParameter(PSP_LIGHTMATRICES, shadowMatrices[0].Data(), isShadowed ? 32 : 16);
|
|
|
+ CalculateShadowMatrix(shadowMatrices[1], lightQueue_, 0, renderer, isLightVolume ? cameraEffectivePos :
|
|
|
+ Vector3::ZERO);
|
|
|
}
|
|
|
- break;
|
|
|
-
|
|
|
+
|
|
|
+ graphics->SetShaderParameter(PSP_LIGHTMATRICES, shadowMatrices[0].Data(), isShadowed ? 32 : 16);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
case LIGHT_POINT:
|
|
|
- {
|
|
|
- Matrix4 lightVecRot(lightNode->GetWorldRotation().RotationMatrix());
|
|
|
- // HLSL compiler will pack the parameters as if the matrix is only 3x4, so must be careful to not overwrite
|
|
|
- // the next parameter
|
|
|
- #ifdef URHO3D_OPENGL
|
|
|
- graphics->SetShaderParameter(PSP_LIGHTMATRICES, lightVecRot.Data(), 16);
|
|
|
- #else
|
|
|
- graphics->SetShaderParameter(PSP_LIGHTMATRICES, lightVecRot.Data(), 12);
|
|
|
- #endif
|
|
|
- }
|
|
|
- break;
|
|
|
+ {
|
|
|
+ Matrix4 lightVecRot(lightNode->GetWorldRotation().RotationMatrix());
|
|
|
+ // HLSL compiler will pack the parameters as if the matrix is only 3x4, so must be careful to not overwrite
|
|
|
+ // the next parameter
|
|
|
+#ifdef URHO3D_OPENGL
|
|
|
+ graphics->SetShaderParameter(PSP_LIGHTMATRICES, lightVecRot.Data(), 16);
|
|
|
+#else
|
|
|
+ graphics->SetShaderParameter(PSP_LIGHTMATRICES, lightVecRot.Data(), 12);
|
|
|
+#endif
|
|
|
+ }
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// Set shadow mapping shader parameters
|
|
|
if (shadowMap)
|
|
|
{
|
|
|
@@ -473,17 +423,17 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
|
|
|
unsigned faceHeight = shadowMap->GetHeight() / 3;
|
|
|
float width = (float)shadowMap->GetWidth();
|
|
|
float height = (float)shadowMap->GetHeight();
|
|
|
- #ifdef URHO3D_OPENGL
|
|
|
- float mulX = (float)(faceWidth - 3) / width;
|
|
|
- float mulY = (float)(faceHeight - 3) / height;
|
|
|
- float addX = 1.5f / width;
|
|
|
- float addY = 1.5f / height;
|
|
|
- #else
|
|
|
- float mulX = (float)(faceWidth - 4) / width;
|
|
|
- float mulY = (float)(faceHeight - 4) / height;
|
|
|
- float addX = 2.5f / width;
|
|
|
- float addY = 2.5f / height;
|
|
|
- #endif
|
|
|
+#ifdef URHO3D_OPENGL
|
|
|
+ float mulX = (float)(faceWidth - 3) / width;
|
|
|
+ float mulY = (float)(faceHeight - 3) / height;
|
|
|
+ float addX = 1.5f / width;
|
|
|
+ float addY = 1.5f / height;
|
|
|
+#else
|
|
|
+ float mulX = (float)(faceWidth - 4) / width;
|
|
|
+ float mulY = (float)(faceHeight - 4) / height;
|
|
|
+ float addX = 2.5f / width;
|
|
|
+ float addY = 2.5f / height;
|
|
|
+#endif
|
|
|
// If using 4 shadow samples, offset the position diagonally by half pixel
|
|
|
if (renderer->GetShadowQuality() & SHADOWQUALITY_HIGH_16BIT)
|
|
|
{
|
|
|
@@ -492,7 +442,7 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
|
|
|
}
|
|
|
graphics->SetShaderParameter(PSP_SHADOWCUBEADJUST, Vector4(mulX, mulY, addX, addY));
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
{
|
|
|
// Calculate shadow camera depth parameters for point light shadows and shadow fade parameters for
|
|
|
// directional light shadows, stored in the same uniform
|
|
|
@@ -501,17 +451,17 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
|
|
|
float farClip = shadowCamera->GetFarClip();
|
|
|
float q = farClip / (farClip - nearClip);
|
|
|
float r = -q * nearClip;
|
|
|
-
|
|
|
+
|
|
|
const CascadeParameters& parameters = light->GetShadowCascade();
|
|
|
float viewFarClip = camera_->GetFarClip();
|
|
|
float shadowRange = parameters.GetShadowRange();
|
|
|
float fadeStart = parameters.fadeStart_ * shadowRange / viewFarClip;
|
|
|
float fadeEnd = shadowRange / viewFarClip;
|
|
|
float fadeRange = fadeEnd - fadeStart;
|
|
|
-
|
|
|
+
|
|
|
graphics->SetShaderParameter(PSP_SHADOWDEPTHFADE, Vector4(q, r, fadeStart, 1.0f / fadeRange));
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
{
|
|
|
float intensity = light->GetShadowIntensity();
|
|
|
float fadeStart = light->GetShadowFadeDistance();
|
|
|
@@ -523,11 +473,11 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
|
|
|
|
|
|
graphics->SetShaderParameter(PSP_SHADOWINTENSITY, Vector4(pcfValues / samples, intensity, 0.0f, 0.0f));
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
float sizeX = 1.0f / (float)shadowMap->GetWidth();
|
|
|
float sizeY = 1.0f / (float)shadowMap->GetHeight();
|
|
|
graphics->SetShaderParameter(PSP_SHADOWMAPINVSIZE, Vector4(sizeX, sizeY, 0.0f, 0.0f));
|
|
|
-
|
|
|
+
|
|
|
Vector4 lightSplits(M_LARGE_VALUE, M_LARGE_VALUE, M_LARGE_VALUE, M_LARGE_VALUE);
|
|
|
if (lightQueue_->shadowSplits_.Size() > 1)
|
|
|
lightSplits.x_ = lightQueue_->shadowSplits_[0].farSplit_ / camera_->GetFarClip();
|
|
|
@@ -535,10 +485,60 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
|
|
|
lightSplits.y_ = lightQueue_->shadowSplits_[1].farSplit_ / camera_->GetFarClip();
|
|
|
if (lightQueue_->shadowSplits_.Size() > 3)
|
|
|
lightSplits.z_ = lightQueue_->shadowSplits_[2].farSplit_ / camera_->GetFarClip();
|
|
|
-
|
|
|
+
|
|
|
graphics->SetShaderParameter(PSP_SHADOWSPLITS, lightSplits);
|
|
|
}
|
|
|
}
|
|
|
+ else if (lightQueue_->vertexLights_.Size() && graphics->HasShaderParameter(VSP_VERTEXLIGHTS) &&
|
|
|
+ graphics->NeedParameterUpdate(SP_LIGHT, lightQueue_))
|
|
|
+ {
|
|
|
+ Vector4 vertexLights[MAX_VERTEX_LIGHTS * 3];
|
|
|
+ const PODVector<Light*>& lights = lightQueue_->vertexLights_;
|
|
|
+
|
|
|
+ for (unsigned i = 0; i < lights.Size(); ++i)
|
|
|
+ {
|
|
|
+ Light* vertexLight = lights[i];
|
|
|
+ Node* vertexLightNode = vertexLight->GetNode();
|
|
|
+ LightType type = vertexLight->GetLightType();
|
|
|
+
|
|
|
+ // Attenuation
|
|
|
+ float invRange, cutoff, invCutoff;
|
|
|
+ if (type == LIGHT_DIRECTIONAL)
|
|
|
+ invRange = 0.0f;
|
|
|
+ else
|
|
|
+ invRange = 1.0f / Max(vertexLight->GetRange(), M_EPSILON);
|
|
|
+ if (type == LIGHT_SPOT)
|
|
|
+ {
|
|
|
+ cutoff = Cos(vertexLight->GetFov() * 0.5f);
|
|
|
+ invCutoff = 1.0f / (1.0f - cutoff);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ cutoff = -1.0f;
|
|
|
+ invCutoff = 1.0f;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Color
|
|
|
+ float fade = 1.0f;
|
|
|
+ float fadeEnd = vertexLight->GetDrawDistance();
|
|
|
+ float fadeStart = vertexLight->GetFadeDistance();
|
|
|
+
|
|
|
+ // Do fade calculation for light if both fade & draw distance defined
|
|
|
+ if (vertexLight->GetLightType() != LIGHT_DIRECTIONAL && fadeEnd > 0.0f && fadeStart > 0.0f && fadeStart < fadeEnd)
|
|
|
+ fade = Min(1.0f - (vertexLight->GetDistance() - fadeStart) / (fadeEnd - fadeStart), 1.0f);
|
|
|
+
|
|
|
+ Color color = vertexLight->GetEffectiveColor() * fade;
|
|
|
+ vertexLights[i * 3] = Vector4(color.r_, color.g_, color.b_, invRange);
|
|
|
+
|
|
|
+ // Direction
|
|
|
+ vertexLights[i * 3 + 1] = Vector4(-(vertexLightNode->GetWorldDirection()), cutoff);
|
|
|
+
|
|
|
+ // Position
|
|
|
+ vertexLights[i * 3 + 2] = Vector4(vertexLightNode->GetWorldPosition(), invCutoff);
|
|
|
+ }
|
|
|
+
|
|
|
+ graphics->SetShaderParameter(VSP_VERTEXLIGHTS, vertexLights[0].Data(), lights.Size() * 3 * 4);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// Set material-specific shader parameters and textures
|