|
|
@@ -20,22 +20,20 @@
|
|
|
// THE SOFTWARE.
|
|
|
//
|
|
|
|
|
|
+#include "../Precompiled.h"
|
|
|
+
|
|
|
#include "../Graphics/Camera.h"
|
|
|
#include "../Graphics/Geometry.h"
|
|
|
#include "../Graphics/Graphics.h"
|
|
|
#include "../Graphics/GraphicsImpl.h"
|
|
|
#include "../Graphics/Material.h"
|
|
|
-#include "../Scene/Node.h"
|
|
|
#include "../Graphics/Renderer.h"
|
|
|
-#include "../Core/Profiler.h"
|
|
|
-#include "../Scene/Scene.h"
|
|
|
#include "../Graphics/ShaderVariation.h"
|
|
|
-#include "../Container/Sort.h"
|
|
|
#include "../Graphics/Technique.h"
|
|
|
#include "../Graphics/Texture2D.h"
|
|
|
#include "../Graphics/VertexBuffer.h"
|
|
|
#include "../Graphics/View.h"
|
|
|
-#include "../Graphics/Zone.h"
|
|
|
+#include "../Scene/Scene.h"
|
|
|
|
|
|
#include "../DebugNew.h"
|
|
|
|
|
|
@@ -75,25 +73,25 @@ void CalculateShadowMatrix(Matrix4& dest, LightBatchQueue* queue, unsigned split
|
|
|
{
|
|
|
Camera* shadowCamera = queue->shadowSplits_[split].shadowCamera_;
|
|
|
const IntRect& viewport = queue->shadowSplits_[split].shadowViewport_;
|
|
|
-
|
|
|
+
|
|
|
Matrix3x4 posAdjust(translation, Quaternion::IDENTITY, 1.0f);
|
|
|
Matrix3x4 shadowView(shadowCamera->GetView());
|
|
|
Matrix4 shadowProj(shadowCamera->GetProjection());
|
|
|
Matrix4 texAdjust(Matrix4::IDENTITY);
|
|
|
-
|
|
|
+
|
|
|
Texture2D* shadowMap = queue->shadowMap_;
|
|
|
if (!shadowMap)
|
|
|
return;
|
|
|
-
|
|
|
+
|
|
|
float width = (float)shadowMap->GetWidth();
|
|
|
float height = (float)shadowMap->GetHeight();
|
|
|
-
|
|
|
+
|
|
|
Vector3 offset(
|
|
|
(float)viewport.left_ / width,
|
|
|
(float)viewport.top_ / height,
|
|
|
0.0f
|
|
|
);
|
|
|
-
|
|
|
+
|
|
|
Vector3 scale(
|
|
|
0.5f * (float)viewport.Width() / width,
|
|
|
0.5f * (float)viewport.Height() / height,
|
|
|
@@ -105,13 +103,13 @@ void CalculateShadowMatrix(Matrix4& dest, LightBatchQueue* queue, unsigned split
|
|
|
offset.x_ += scale.x_ + pixelUVOffset.x_ / width;
|
|
|
offset.y_ += scale.y_ + pixelUVOffset.y_ / height;
|
|
|
|
|
|
- #ifdef URHO3D_OPENGL
|
|
|
+#ifdef URHO3D_OPENGL
|
|
|
offset.z_ = 0.5f;
|
|
|
scale.z_ = 0.5f;
|
|
|
offset.y_ = 1.0f - offset.y_;
|
|
|
- #else
|
|
|
+#else
|
|
|
scale.y_ = -scale.y_;
|
|
|
- #endif
|
|
|
+#endif
|
|
|
|
|
|
// If using 4 shadow samples, offset the position diagonally by half pixel
|
|
|
if (renderer->GetShadowQuality() & SHADOWQUALITY_HIGH_16BIT)
|
|
|
@@ -121,7 +119,7 @@ void CalculateShadowMatrix(Matrix4& dest, LightBatchQueue* queue, unsigned split
|
|
|
}
|
|
|
texAdjust.SetTranslation(offset);
|
|
|
texAdjust.SetScale(scale);
|
|
|
-
|
|
|
+
|
|
|
dest = texAdjust * shadowProj * shadowView * posAdjust;
|
|
|
}
|
|
|
|
|
|
@@ -132,7 +130,7 @@ void CalculateSpotMatrix(Matrix4& dest, Light* light, const Vector3& translation
|
|
|
Matrix3x4 spotView = Matrix3x4(lightNode->GetWorldPosition(), lightNode->GetWorldRotation(), 1.0f).Inverse();
|
|
|
Matrix4 spotProj(Matrix4::ZERO);
|
|
|
Matrix4 texAdjust(Matrix4::IDENTITY);
|
|
|
-
|
|
|
+
|
|
|
// Make the projected light slightly smaller than the shadow map to prevent light spill
|
|
|
float h = 1.005f / tanf(light->GetFov() * M_DEGTORAD * 0.5f);
|
|
|
float w = h / light->GetAspectRatio();
|
|
|
@@ -140,39 +138,41 @@ void CalculateSpotMatrix(Matrix4& dest, Light* light, const Vector3& translation
|
|
|
spotProj.m11_ = h;
|
|
|
spotProj.m22_ = 1.0f / Max(light->GetRange(), M_EPSILON);
|
|
|
spotProj.m32_ = 1.0f;
|
|
|
-
|
|
|
- #ifdef URHO3D_OPENGL
|
|
|
+
|
|
|
+#ifdef URHO3D_OPENGL
|
|
|
texAdjust.SetTranslation(Vector3(0.5f, 0.5f, 0.5f));
|
|
|
texAdjust.SetScale(Vector3(0.5f, -0.5f, 0.5f));
|
|
|
- #else
|
|
|
+#else
|
|
|
texAdjust.SetTranslation(Vector3(0.5f, 0.5f, 0.0f));
|
|
|
texAdjust.SetScale(Vector3(0.5f, -0.5f, 1.0f));
|
|
|
- #endif
|
|
|
-
|
|
|
+#endif
|
|
|
+
|
|
|
dest = texAdjust * spotProj * spotView * posAdjust;
|
|
|
}
|
|
|
|
|
|
void Batch::CalculateSortKey()
|
|
|
{
|
|
|
- unsigned shaderID = ((*((unsigned*)&vertexShader_) / sizeof(ShaderVariation)) + (*((unsigned*)&pixelShader_) / sizeof(ShaderVariation))) & 0x3fff;
|
|
|
+ unsigned shaderID = (unsigned)(
|
|
|
+ ((*((unsigned*)&vertexShader_) / sizeof(ShaderVariation)) + (*((unsigned*)&pixelShader_) / sizeof(ShaderVariation))) &
|
|
|
+ 0x3fff);
|
|
|
if (!isBase_)
|
|
|
shaderID |= 0x8000;
|
|
|
if (pass_ && pass_->GetAlphaMask())
|
|
|
shaderID |= 0x4000;
|
|
|
-
|
|
|
- unsigned lightQueueID = (*((unsigned*)&lightQueue_) / sizeof(LightBatchQueue)) & 0xffff;
|
|
|
- unsigned materialID = (*((unsigned*)&material_) / sizeof(Material)) & 0xffff;
|
|
|
- unsigned geometryID = (*((unsigned*)&geometry_) / sizeof(Geometry)) & 0xffff;
|
|
|
-
|
|
|
+
|
|
|
+ unsigned lightQueueID = (unsigned)((*((unsigned*)&lightQueue_) / sizeof(LightBatchQueue)) & 0xffff);
|
|
|
+ unsigned materialID = (unsigned)((*((unsigned*)&material_) / sizeof(Material)) & 0xffff);
|
|
|
+ unsigned geometryID = (unsigned)((*((unsigned*)&geometry_) / sizeof(Geometry)) & 0xffff);
|
|
|
+
|
|
|
sortKey_ = (((unsigned long long)shaderID) << 48) | (((unsigned long long)lightQueueID) << 32) |
|
|
|
- (((unsigned long long)materialID) << 16) | geometryID;
|
|
|
+ (((unsigned long long)materialID) << 16) | geometryID;
|
|
|
}
|
|
|
|
|
|
void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) const
|
|
|
{
|
|
|
if (!vertexShader_ || !pixelShader_)
|
|
|
return;
|
|
|
-
|
|
|
+
|
|
|
Graphics* graphics = view->GetGraphics();
|
|
|
Renderer* renderer = view->GetRenderer();
|
|
|
Node* cameraNode = camera_ ? camera_->GetNode() : 0;
|
|
|
@@ -209,34 +209,34 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
|
|
|
graphics->SetDepthTest(pass_->GetDepthTestMode());
|
|
|
graphics->SetDepthWrite(pass_->GetDepthWrite() && allowDepthWrite);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// Set global (per-frame) shader parameters
|
|
|
if (graphics->NeedParameterUpdate(SP_FRAME, (void*)0))
|
|
|
view->SetGlobalShaderParameters();
|
|
|
-
|
|
|
+
|
|
|
// Set camera & viewport shader parameters
|
|
|
unsigned cameraHash = (unsigned)(size_t)camera_;
|
|
|
IntRect viewport = graphics->GetViewport();
|
|
|
IntVector2 viewSize = IntVector2(viewport.Width(), viewport.Height());
|
|
|
- unsigned viewportHash = viewSize.x_ | (viewSize.y_ << 16);
|
|
|
+ unsigned viewportHash = (unsigned)(viewSize.x_ | (viewSize.y_ << 16));
|
|
|
if (graphics->NeedParameterUpdate(SP_CAMERA, reinterpret_cast<const void*>(cameraHash + viewportHash)))
|
|
|
{
|
|
|
view->SetCameraShaderParameters(camera_, true);
|
|
|
// During renderpath commands the G-Buffer or viewport texture is assumed to always be viewport-sized
|
|
|
view->SetGBufferShaderParameters(viewSize, IntRect(0, 0, viewSize.x_, viewSize.y_));
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// Set model or skinning transforms
|
|
|
if (setModelTransform && graphics->NeedParameterUpdate(SP_OBJECT, worldTransform_))
|
|
|
{
|
|
|
if (geometryType_ == GEOM_SKINNED)
|
|
|
{
|
|
|
- graphics->SetShaderParameter(VSP_SKINMATRICES, reinterpret_cast<const float*>(worldTransform_),
|
|
|
+ graphics->SetShaderParameter(VSP_SKINMATRICES, reinterpret_cast<const float*>(worldTransform_),
|
|
|
12 * numWorldTransforms_);
|
|
|
}
|
|
|
else
|
|
|
graphics->SetShaderParameter(VSP_MODEL, *worldTransform_);
|
|
|
-
|
|
|
+
|
|
|
// Set the orientation for billboards, either from the object itself or from the camera
|
|
|
if (geometryType_ == GEOM_BILLBOARD)
|
|
|
{
|
|
|
@@ -246,7 +246,7 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
|
|
|
graphics->SetShaderParameter(VSP_BILLBOARDROT, cameraNode->GetWorldRotation().RotationMatrix());
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// Set zone-related shader parameters
|
|
|
BlendMode blend = graphics->GetBlendMode();
|
|
|
// If the pass is additive, override fog color to black so that shaders do not need a separate additive path
|
|
|
@@ -257,8 +257,9 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
|
|
|
if (zone_ && graphics->NeedParameterUpdate(SP_ZONE, reinterpret_cast<const void*>(zoneHash)))
|
|
|
{
|
|
|
graphics->SetShaderParameter(VSP_AMBIENTSTARTCOLOR, zone_->GetAmbientStartColor());
|
|
|
- graphics->SetShaderParameter(VSP_AMBIENTENDCOLOR, zone_->GetAmbientEndColor().ToVector4() - zone_->GetAmbientStartColor().ToVector4());
|
|
|
-
|
|
|
+ graphics->SetShaderParameter(VSP_AMBIENTENDCOLOR,
|
|
|
+ zone_->GetAmbientEndColor().ToVector4() - zone_->GetAmbientStartColor().ToVector4());
|
|
|
+
|
|
|
const BoundingBox& box = zone_->GetBoundingBox();
|
|
|
Vector3 boxSize = box.Size();
|
|
|
Matrix3x4 adjust(Matrix3x4::IDENTITY);
|
|
|
@@ -266,10 +267,10 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
|
|
|
adjust.SetTranslation(Vector3(0.5f, 0.5f, 0.5f));
|
|
|
Matrix3x4 zoneTransform = adjust * zone_->GetInverseWorldTransform();
|
|
|
graphics->SetShaderParameter(VSP_ZONE, zoneTransform);
|
|
|
-
|
|
|
+
|
|
|
graphics->SetShaderParameter(PSP_AMBIENTCOLOR, zone_->GetAmbientColor());
|
|
|
graphics->SetShaderParameter(PSP_FOGCOLOR, overrideFogColorToBlack ? Color::BLACK : zone_->GetFogColor());
|
|
|
-
|
|
|
+
|
|
|
float farClip = camera_->GetFarClip();
|
|
|
float fogStart = Min(zone_->GetFogStart(), farClip);
|
|
|
float fogEnd = Min(zone_->GetFogEnd(), farClip);
|
|
|
@@ -277,7 +278,7 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
|
|
|
fogStart = fogEnd * (1.0f - M_LARGE_EPSILON);
|
|
|
float fogRange = Max(fogEnd - fogStart, M_EPSILON);
|
|
|
Vector4 fogParams(fogEnd / farClip, farClip / fogRange, 0.0f, 0.0f);
|
|
|
-
|
|
|
+
|
|
|
Node* zoneNode = zone_->GetNode();
|
|
|
if (zone_->GetHeightFog() && zoneNode)
|
|
|
{
|
|
|
@@ -285,10 +286,10 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
|
|
|
fogParams.z_ = worldFogHeightVec.y_;
|
|
|
fogParams.w_ = zone_->GetFogHeightScale() / Max(zoneNode->GetWorldScale().y_, M_EPSILON);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
graphics->SetShaderParameter(PSP_FOGPARAMS, fogParams);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// Set light-related shader parameters
|
|
|
if (lightQueue_)
|
|
|
{
|
|
|
@@ -313,42 +314,42 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
|
|
|
switch (light->GetLightType())
|
|
|
{
|
|
|
case LIGHT_DIRECTIONAL:
|
|
|
- {
|
|
|
- Matrix4 shadowMatrices[MAX_CASCADE_SPLITS];
|
|
|
- unsigned numSplits = Min(MAX_CASCADE_SPLITS, (int)lightQueue_->shadowSplits_.Size());
|
|
|
+ {
|
|
|
+ Matrix4 shadowMatrices[MAX_CASCADE_SPLITS];
|
|
|
+ unsigned numSplits = (unsigned)Min(MAX_CASCADE_SPLITS, (int)lightQueue_->shadowSplits_.Size());
|
|
|
|
|
|
- for (unsigned i = 0; i < numSplits; ++i)
|
|
|
- CalculateShadowMatrix(shadowMatrices[i], lightQueue_, i, renderer, Vector3::ZERO);
|
|
|
+ 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;
|
|
|
+ graphics->SetShaderParameter(VSP_LIGHTMATRICES, shadowMatrices[0].Data(), 16 * numSplits);
|
|
|
+ }
|
|
|
+ break;
|
|
|
|
|
|
case LIGHT_SPOT:
|
|
|
- {
|
|
|
- Matrix4 shadowMatrices[2];
|
|
|
+ {
|
|
|
+ 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);
|
|
|
+ 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;
|
|
|
+ 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;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -364,55 +365,56 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
|
|
|
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));
|
|
|
+ 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)
|
|
|
{
|
|
|
- CalculateShadowMatrix(shadowMatrices[i], lightQueue_, i, renderer, isLightVolume ? cameraEffectivePos :
|
|
|
- Vector3::ZERO);
|
|
|
+ Matrix4 shadowMatrices[MAX_CASCADE_SPLITS];
|
|
|
+ unsigned numSplits = (unsigned)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);
|
|
|
}
|
|
|
- graphics->SetShaderParameter(PSP_LIGHTMATRICES, shadowMatrices[0].Data(), 16 * numSplits);
|
|
|
- }
|
|
|
- break;
|
|
|
+ break;
|
|
|
|
|
|
case LIGHT_SPOT:
|
|
|
- {
|
|
|
- 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);
|
|
|
- }
|
|
|
+ Matrix4 shadowMatrices[2];
|
|
|
|
|
|
- graphics->SetShaderParameter(PSP_LIGHTMATRICES, shadowMatrices[0].Data(), isShadowed ? 32 : 16);
|
|
|
- }
|
|
|
- break;
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+ 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;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -421,21 +423,21 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
|
|
|
{
|
|
|
{
|
|
|
// Calculate point light shadow sampling offsets (unrolled cube map)
|
|
|
- unsigned faceWidth = shadowMap->GetWidth() / 2;
|
|
|
- unsigned faceHeight = shadowMap->GetHeight() / 3;
|
|
|
+ unsigned faceWidth = (unsigned)(shadowMap->GetWidth() / 2);
|
|
|
+ unsigned faceHeight = (unsigned)(shadowMap->GetHeight() / 3);
|
|
|
float width = (float)shadowMap->GetWidth();
|
|
|
float height = (float)shadowMap->GetHeight();
|
|
|
- #ifdef URHO3D_OPENGL
|
|
|
+#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
|
|
|
+#else
|
|
|
float mulX = (float)(faceWidth - 4) / width;
|
|
|
float mulY = (float)(faceHeight - 4) / height;
|
|
|
float addX = 2.5f / width;
|
|
|
float addY = 2.5f / height;
|
|
|
- #endif
|
|
|
+#endif
|
|
|
// If using 4 shadow samples, offset the position diagonally by half pixel
|
|
|
if (renderer->GetShadowQuality() & SHADOWQUALITY_HIGH_16BIT)
|
|
|
{
|
|
|
@@ -469,7 +471,8 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
|
|
|
float fadeStart = light->GetShadowFadeDistance();
|
|
|
float fadeEnd = light->GetShadowDistance();
|
|
|
if (fadeStart > 0.0f && fadeEnd > 0.0f && fadeEnd > fadeStart)
|
|
|
- intensity = Lerp(intensity, 1.0f, Clamp((light->GetDistance() - fadeStart) / (fadeEnd - fadeStart), 0.0f, 1.0f));
|
|
|
+ intensity =
|
|
|
+ Lerp(intensity, 1.0f, Clamp((light->GetDistance() - fadeStart) / (fadeEnd - fadeStart), 0.0f, 1.0f));
|
|
|
float pcfValues = (1.0f - intensity);
|
|
|
float samples = renderer->GetShadowQuality() >= SHADOWQUALITY_HIGH_16BIT ? 4.0f : 1.0f;
|
|
|
|
|
|
@@ -492,17 +495,17 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
|
|
|
}
|
|
|
}
|
|
|
else if (lightQueue_->vertexLights_.Size() && graphics->HasShaderParameter(VSP_VERTEXLIGHTS) &&
|
|
|
- graphics->NeedParameterUpdate(SP_LIGHT, lightQueue_))
|
|
|
+ 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)
|
|
|
@@ -519,26 +522,26 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
|
|
|
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);
|
|
|
}
|
|
|
}
|
|
|
@@ -552,7 +555,7 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
|
|
|
for (HashMap<StringHash, MaterialShaderParameter>::ConstIterator i = parameters.Begin(); i != parameters.End(); ++i)
|
|
|
graphics->SetShaderParameter(i->first_, i->second_.value_);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
const HashMap<TextureUnit, SharedPtr<Texture> >& textures = material_->GetTextures();
|
|
|
for (HashMap<TextureUnit, SharedPtr<Texture> >::ConstIterator i = textures.Begin(); i != textures.End(); ++i)
|
|
|
{
|
|
|
@@ -560,7 +563,7 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
|
|
|
graphics->SetTexture(i->first_, i->second_.Get());
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// Set light-related textures
|
|
|
if (light)
|
|
|
{
|
|
|
@@ -581,12 +584,12 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
|
|
|
graphics->SetTexture(TU_LIGHTSHAPE, shapeTexture);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// Set zone texture if necessary
|
|
|
- #ifdef DESKTOP_GRAPHICS
|
|
|
+#ifdef DESKTOP_GRAPHICS
|
|
|
if (zone_ && graphics->HasTextureUnit(TU_ZONE))
|
|
|
graphics->SetTexture(TU_ZONE, zone_->GetZoneTexture());
|
|
|
- #endif
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
void Batch::Draw(View* view, bool allowDepthWrite) const
|
|
|
@@ -603,14 +606,14 @@ void BatchGroup::SetTransforms(void* lockedData, unsigned& freeIndex)
|
|
|
// Do not use up buffer space if not going to draw as instanced
|
|
|
if (geometryType_ != GEOM_INSTANCED)
|
|
|
return;
|
|
|
-
|
|
|
+
|
|
|
startIndex_ = freeIndex;
|
|
|
Matrix3x4* dest = (Matrix3x4*)lockedData;
|
|
|
dest += freeIndex;
|
|
|
-
|
|
|
+
|
|
|
for (unsigned i = 0; i < instances_.Size(); ++i)
|
|
|
*dest++ = *instances_[i].worldTransform_;
|
|
|
-
|
|
|
+
|
|
|
freeIndex += instances_.Size();
|
|
|
}
|
|
|
|
|
|
@@ -618,7 +621,7 @@ void BatchGroup::Draw(View* view, bool allowDepthWrite) const
|
|
|
{
|
|
|
Graphics* graphics = view->GetGraphics();
|
|
|
Renderer* renderer = view->GetRenderer();
|
|
|
-
|
|
|
+
|
|
|
if (instances_.Size() && !geometry_->IsEmpty())
|
|
|
{
|
|
|
// Draw as individual objects if instancing not supported or could not fill the instancing buffer
|
|
|
@@ -626,15 +629,15 @@ void BatchGroup::Draw(View* view, bool allowDepthWrite) const
|
|
|
if (!instanceBuffer || geometryType_ != GEOM_INSTANCED || startIndex_ == M_MAX_UNSIGNED)
|
|
|
{
|
|
|
Batch::Prepare(view, false, allowDepthWrite);
|
|
|
-
|
|
|
+
|
|
|
graphics->SetIndexBuffer(geometry_->GetIndexBuffer());
|
|
|
graphics->SetVertexBuffers(geometry_->GetVertexBuffers(), geometry_->GetVertexElementMasks());
|
|
|
-
|
|
|
+
|
|
|
for (unsigned i = 0; i < instances_.Size(); ++i)
|
|
|
{
|
|
|
if (graphics->NeedParameterUpdate(SP_OBJECT, instances_[i].worldTransform_))
|
|
|
graphics->SetShaderParameter(VSP_MODEL, *instances_[i].worldTransform_);
|
|
|
-
|
|
|
+
|
|
|
graphics->Draw(geometry_->GetPrimitiveType(), geometry_->GetIndexStart(), geometry_->GetIndexCount(),
|
|
|
geometry_->GetVertexStart(), geometry_->GetVertexCount());
|
|
|
}
|
|
|
@@ -642,20 +645,20 @@ void BatchGroup::Draw(View* view, bool allowDepthWrite) const
|
|
|
else
|
|
|
{
|
|
|
Batch::Prepare(view, false, allowDepthWrite);
|
|
|
-
|
|
|
+
|
|
|
// Get the geometry vertex buffers, then add the instancing stream buffer
|
|
|
// Hack: use a const_cast to avoid dynamic allocation of new temp vectors
|
|
|
- Vector<SharedPtr<VertexBuffer> >& vertexBuffers = const_cast<Vector<SharedPtr<VertexBuffer> >&>
|
|
|
- (geometry_->GetVertexBuffers());
|
|
|
+ Vector<SharedPtr<VertexBuffer> >& vertexBuffers = const_cast<Vector<SharedPtr<VertexBuffer> >&>(
|
|
|
+ geometry_->GetVertexBuffers());
|
|
|
PODVector<unsigned>& elementMasks = const_cast<PODVector<unsigned>&>(geometry_->GetVertexElementMasks());
|
|
|
vertexBuffers.Push(SharedPtr<VertexBuffer>(instanceBuffer));
|
|
|
elementMasks.Push(instanceBuffer->GetElementMask());
|
|
|
-
|
|
|
+
|
|
|
graphics->SetIndexBuffer(geometry_->GetIndexBuffer());
|
|
|
graphics->SetVertexBuffers(vertexBuffers, elementMasks, startIndex_);
|
|
|
graphics->DrawInstanced(geometry_->GetPrimitiveType(), geometry_->GetIndexStart(), geometry_->GetIndexCount(),
|
|
|
geometry_->GetVertexStart(), geometry_->GetVertexCount(), instances_.Size());
|
|
|
-
|
|
|
+
|
|
|
// Remove the instancing buffer & element mask now
|
|
|
vertexBuffers.Pop();
|
|
|
elementMasks.Pop();
|
|
|
@@ -665,11 +668,8 @@ void BatchGroup::Draw(View* view, bool allowDepthWrite) const
|
|
|
|
|
|
unsigned BatchGroupKey::ToHash() const
|
|
|
{
|
|
|
- return ((unsigned)(size_t)zone_) / sizeof(Zone) +
|
|
|
- ((unsigned)(size_t)lightQueue_) / sizeof(LightBatchQueue) +
|
|
|
- ((unsigned)(size_t)pass_) / sizeof(Pass) +
|
|
|
- ((unsigned)(size_t)material_) / sizeof(Material) +
|
|
|
- ((unsigned)(size_t)geometry_) / sizeof(Geometry);
|
|
|
+ return (unsigned)((size_t)zone_ / sizeof(Zone) + (size_t)lightQueue_ / sizeof(LightBatchQueue) + (size_t)pass_ / sizeof(Pass) +
|
|
|
+ (size_t)material_ / sizeof(Material) + (size_t)geometry_ / sizeof(Geometry));
|
|
|
}
|
|
|
|
|
|
void BatchQueue::Clear(int maxSortedInstances)
|
|
|
@@ -677,21 +677,21 @@ void BatchQueue::Clear(int maxSortedInstances)
|
|
|
batches_.Clear();
|
|
|
sortedBatches_.Clear();
|
|
|
batchGroups_.Clear();
|
|
|
- maxSortedInstances_ = maxSortedInstances;
|
|
|
+ maxSortedInstances_ = (unsigned)maxSortedInstances;
|
|
|
}
|
|
|
|
|
|
void BatchQueue::SortBackToFront()
|
|
|
{
|
|
|
sortedBatches_.Resize(batches_.Size());
|
|
|
-
|
|
|
+
|
|
|
for (unsigned i = 0; i < batches_.Size(); ++i)
|
|
|
sortedBatches_[i] = &batches_[i];
|
|
|
-
|
|
|
+
|
|
|
Sort(sortedBatches_.Begin(), sortedBatches_.End(), CompareBatchesBackToFront);
|
|
|
-
|
|
|
+
|
|
|
// Do not actually sort batch groups, just list them
|
|
|
sortedBatchGroups_.Resize(batchGroups_.Size());
|
|
|
-
|
|
|
+
|
|
|
unsigned index = 0;
|
|
|
for (HashMap<BatchGroupKey, BatchGroup>::Iterator i = batchGroups_.Begin(); i != batchGroups_.End(); ++i)
|
|
|
sortedBatchGroups_[index++] = &i->second_;
|
|
|
@@ -700,12 +700,12 @@ void BatchQueue::SortBackToFront()
|
|
|
void BatchQueue::SortFrontToBack()
|
|
|
{
|
|
|
sortedBatches_.Clear();
|
|
|
-
|
|
|
+
|
|
|
for (unsigned i = 0; i < batches_.Size(); ++i)
|
|
|
sortedBatches_.Push(&batches_[i]);
|
|
|
-
|
|
|
+
|
|
|
SortFrontToBack2Pass(sortedBatches_);
|
|
|
-
|
|
|
+
|
|
|
// Sort each group front to back
|
|
|
for (HashMap<BatchGroupKey, BatchGroup>::Iterator i = batchGroups_.Begin(); i != batchGroups_.End(); ++i)
|
|
|
{
|
|
|
@@ -723,13 +723,13 @@ void BatchQueue::SortFrontToBack()
|
|
|
i->second_.distance_ = minDistance;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
sortedBatchGroups_.Resize(batchGroups_.Size());
|
|
|
-
|
|
|
+
|
|
|
unsigned index = 0;
|
|
|
for (HashMap<BatchGroupKey, BatchGroup>::Iterator i = batchGroups_.Begin(); i != batchGroups_.End(); ++i)
|
|
|
sortedBatchGroups_[index++] = &i->second_;
|
|
|
-
|
|
|
+
|
|
|
SortFrontToBack2Pass(reinterpret_cast<PODVector<Batch*>& >(sortedBatchGroups_));
|
|
|
}
|
|
|
|
|
|
@@ -737,21 +737,21 @@ void BatchQueue::SortFrontToBack2Pass(PODVector<Batch*>& batches)
|
|
|
{
|
|
|
// Mobile devices likely use a tiled deferred approach, with which front-to-back sorting is irrelevant. The 2-pass
|
|
|
// method is also time consuming, so just sort with state having priority
|
|
|
- #ifdef GL_ES_VERSION_2_0
|
|
|
+#ifdef GL_ES_VERSION_2_0
|
|
|
Sort(batches.Begin(), batches.End(), CompareBatchesState);
|
|
|
- #else
|
|
|
+#else
|
|
|
// For desktop, first sort by distance and remap shader/material/geometry IDs in the sort key
|
|
|
Sort(batches.Begin(), batches.End(), CompareBatchesFrontToBack);
|
|
|
-
|
|
|
+
|
|
|
unsigned freeShaderID = 0;
|
|
|
unsigned short freeMaterialID = 0;
|
|
|
unsigned short freeGeometryID = 0;
|
|
|
-
|
|
|
+
|
|
|
for (PODVector<Batch*>::Iterator i = batches.Begin(); i != batches.End(); ++i)
|
|
|
{
|
|
|
Batch* batch = *i;
|
|
|
-
|
|
|
- unsigned shaderID = (batch->sortKey_ >> 32);
|
|
|
+
|
|
|
+ unsigned shaderID = (unsigned)(batch->sortKey_ >> 32);
|
|
|
HashMap<unsigned, unsigned>::ConstIterator j = shaderRemapping_.Find(shaderID);
|
|
|
if (j != shaderRemapping_.End())
|
|
|
shaderID = j->second_;
|
|
|
@@ -760,7 +760,7 @@ void BatchQueue::SortFrontToBack2Pass(PODVector<Batch*>& batches)
|
|
|
shaderID = shaderRemapping_[shaderID] = freeShaderID | (shaderID & 0xc0000000);
|
|
|
++freeShaderID;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
unsigned short materialID = (unsigned short)(batch->sortKey_ & 0xffff0000);
|
|
|
HashMap<unsigned short, unsigned short>::ConstIterator k = materialRemapping_.Find(materialID);
|
|
|
if (k != materialRemapping_.End())
|
|
|
@@ -770,7 +770,7 @@ void BatchQueue::SortFrontToBack2Pass(PODVector<Batch*>& batches)
|
|
|
materialID = materialRemapping_[materialID] = freeMaterialID;
|
|
|
++freeMaterialID;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
unsigned short geometryID = (unsigned short)(batch->sortKey_ & 0xffff);
|
|
|
HashMap<unsigned short, unsigned short>::ConstIterator l = geometryRemapping_.Find(geometryID);
|
|
|
if (l != geometryRemapping_.End())
|
|
|
@@ -780,17 +780,17 @@ void BatchQueue::SortFrontToBack2Pass(PODVector<Batch*>& batches)
|
|
|
geometryID = geometryRemapping_[geometryID] = freeGeometryID;
|
|
|
++freeGeometryID;
|
|
|
}
|
|
|
-
|
|
|
- batch->sortKey_ = (((unsigned long long)shaderID) << 32) || (((unsigned long long)materialID) << 16) | geometryID;
|
|
|
+
|
|
|
+ batch->sortKey_ = (((unsigned long long)shaderID) << 32) | (((unsigned long long)materialID) << 16) | geometryID;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
shaderRemapping_.Clear();
|
|
|
materialRemapping_.Clear();
|
|
|
geometryRemapping_.Clear();
|
|
|
-
|
|
|
+
|
|
|
// Finally sort again with the rewritten ID's
|
|
|
Sort(batches.Begin(), batches.End(), CompareBatchesState);
|
|
|
- #endif
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
void BatchQueue::SetTransforms(void* lockedData, unsigned& freeIndex)
|
|
|
@@ -803,24 +803,24 @@ void BatchQueue::Draw(View* view, bool markToStencil, bool usingLightOptimizatio
|
|
|
{
|
|
|
Graphics* graphics = view->GetGraphics();
|
|
|
Renderer* renderer = view->GetRenderer();
|
|
|
-
|
|
|
+
|
|
|
// If View has set up its own light optimizations, do not disturb the stencil/scissor test settings
|
|
|
if (!usingLightOptimization)
|
|
|
{
|
|
|
graphics->SetScissorTest(false);
|
|
|
-
|
|
|
+
|
|
|
// During G-buffer rendering, mark opaque pixels' lightmask to stencil buffer if requested
|
|
|
if (!markToStencil)
|
|
|
graphics->SetStencilTest(false);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// Instanced
|
|
|
for (PODVector<BatchGroup*>::ConstIterator i = sortedBatchGroups_.Begin(); i != sortedBatchGroups_.End(); ++i)
|
|
|
{
|
|
|
BatchGroup* group = *i;
|
|
|
if (markToStencil)
|
|
|
graphics->SetStencilTest(true, CMP_ALWAYS, OP_REF, OP_KEEP, OP_KEEP, group->lightMask_);
|
|
|
-
|
|
|
+
|
|
|
group->Draw(view, allowDepthWrite);
|
|
|
}
|
|
|
// Non-instanced
|
|
|
@@ -837,7 +837,7 @@ void BatchQueue::Draw(View* view, bool markToStencil, bool usingLightOptimizatio
|
|
|
else
|
|
|
graphics->SetScissorTest(false);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
batch->Draw(view, allowDepthWrite);
|
|
|
}
|
|
|
}
|
|
|
@@ -845,13 +845,13 @@ void BatchQueue::Draw(View* view, bool markToStencil, bool usingLightOptimizatio
|
|
|
unsigned BatchQueue::GetNumInstances() const
|
|
|
{
|
|
|
unsigned total = 0;
|
|
|
-
|
|
|
+
|
|
|
for (HashMap<BatchGroupKey, BatchGroup>::ConstIterator i = batchGroups_.Begin(); i != batchGroups_.End(); ++i)
|
|
|
{
|
|
|
- if (i->second_.geometryType_ == GEOM_INSTANCED)
|
|
|
+ if (i->second_.geometryType_ == GEOM_INSTANCED)
|
|
|
total += i->second_.instances_.Size();
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
return total;
|
|
|
}
|
|
|
|