void Light::SetIntensitySortValue(const BoundingBox& box) { // When sorting lights for object's maximum light cap, give priority based on attenuation and intensity switch (lightType_) { case LIGHT_DIRECTIONAL: sortValue_ = 1.0f / GetIntensityDivisor(); break; case LIGHT_SPOT: { Vector3 centerPos = box.Center(); Vector3 lightPos = node_->GetWorldPosition(); Vector3 lightDir = node_->GetWorldDirection(); Ray lightRay(lightPos, lightDir); Vector3 centerProj = lightRay.Project(centerPos); float centerDistance = (centerProj - lightPos).Length(); Ray centerRay(centerProj, centerPos - centerProj); float centerAngle = centerRay.HitDistance(box) / centerDistance; // Check if a corner of the bounding box is closer to the light ray than the center, use its angle in that case Vector3 cornerPos = centerPos + box.HalfSize() * Vector3(centerPos.x_ < centerProj.x_ ? 1.0f : -1.0f, centerPos.y_ < centerProj.y_ ? 1.0f : -1.0f, centerPos.z_ < centerProj.z_ ? 1.0f : -1.0f); Vector3 cornerProj = lightRay.Project(cornerPos); float cornerDistance = (cornerProj - lightPos).Length(); float cornerAngle = (cornerPos - cornerProj).Length() / cornerDistance; float spotAngle = Min(centerAngle, cornerAngle); float maxAngle = tanf(fov_ * M_DEGTORAD * 0.5f); float spotFactor = Min(spotAngle / maxAngle, 1.0f); // We do not know the actual range attenuation ramp, so take only spot attenuation into account float att = Max(1.0f - spotFactor * spotFactor, M_EPSILON); sortValue_ = 1.0f / GetIntensityDivisor(att); } break; case LIGHT_POINT: { Vector3 centerPos = box.Center(); Vector3 lightPos = node_->GetWorldPosition(); Vector3 lightDir = (centerPos - lightPos).Normalized(); Ray lightRay(lightPos, lightDir); float distance = lightRay.HitDistance(box); float normDistance = distance / range_; float att = Max(1.0f - normDistance * normDistance, M_EPSILON); sortValue_ = 1.0f / (Max(color_.SumRGB(), 0.0f) * att + M_EPSILON); } break; } }
void Octant::Initialize(const BoundingBox& box) { worldBoundingBox_ = box; center_ = box.Center(); halfSize_ = 0.5f * box.Size(); cullingBox_ = BoundingBox(worldBoundingBox_.min_ - halfSize_, worldBoundingBox_.max_ + halfSize_); }
void PhysicsWorld::GetRigidBodies(PODVector<RigidBody*>& result, const BoundingBox& box, unsigned collisionMask) { ATOMIC_PROFILE(PhysicsBoxQuery); result.Clear(); btBoxShape boxShape(ToBtVector3(box.HalfSize())); UniquePtr<btRigidBody> tempRigidBody(new btRigidBody(1.0f, 0, &boxShape)); tempRigidBody->setWorldTransform(btTransform(btQuaternion::getIdentity(), ToBtVector3(box.Center()))); tempRigidBody->activate(); world_->addRigidBody(tempRigidBody.Get()); PhysicsQueryCallback callback(result, collisionMask); world_->contactTest(tempRigidBody.Get(), callback); world_->removeRigidBody(tempRigidBody.Get()); }
void Light::SetupShadowViews(Camera* mainCamera, Vector<AutoPtr<ShadowView> >& shadowViews, size_t& useIndex) { size_t numViews = NumShadowViews(); if (!numViews) return; if (shadowViews.Size() < useIndex + numViews) shadowViews.Resize(useIndex + numViews); int numVerticalSplits = (lightType == LIGHT_POINT || (lightType == LIGHT_DIRECTIONAL && NumShadowSplits() > 2)) ? 2 : 1; int actualShadowMapSize = shadowRect.Height() / numVerticalSplits; for (size_t i = 0; i < numViews; ++i) { if (!shadowViews[useIndex + i]) shadowViews[useIndex + i] = new ShadowView(); ShadowView* view = shadowViews[useIndex + i].Get(); view->Clear(); view->light = this; Camera& shadowCamera = view->shadowCamera; switch (lightType) { case LIGHT_DIRECTIONAL: { IntVector2 topLeft(shadowRect.left, shadowRect.top); if (i & 1) topLeft.x += actualShadowMapSize; if (i & 2) topLeft.y += actualShadowMapSize; view->viewport = IntRect(topLeft.x, topLeft.y, topLeft.x + actualShadowMapSize, topLeft.y + actualShadowMapSize); float splitStart = Max(mainCamera->NearClip(), (i == 0) ? 0.0f : ShadowSplit(i - 1)); float splitEnd = Min(mainCamera->FarClip(), ShadowSplit(i)); float extrusionDistance = mainCamera->FarClip(); // Calculate initial position & rotation shadowCamera.SetTransform(mainCamera->WorldPosition() - extrusionDistance * WorldDirection(), WorldRotation()); // Calculate main camera shadowed frustum in light's view space Frustum splitFrustum = mainCamera->WorldSplitFrustum(splitStart, splitEnd); const Matrix3x4& lightView = shadowCamera.ViewMatrix(); Frustum lightViewFrustum = splitFrustum.Transformed(lightView); // Fit the frustum inside a bounding box BoundingBox shadowBox; shadowBox.Define(lightViewFrustum); // If shadow camera is far away from the frustum, can bring it closer for better depth precision /// \todo The minimum distance is somewhat arbitrary float minDistance = mainCamera->FarClip() * 0.25f; if (shadowBox.min.z > minDistance) { float move = shadowBox.min.z - minDistance; shadowCamera.Translate(Vector3(0.0f, 0.f, move)); shadowBox.min.z -= move, shadowBox.max.z -= move; } shadowCamera.SetOrthographic(true); shadowCamera.SetFarClip(shadowBox.max.z); Vector3 center = shadowBox.Center(); Vector3 size = shadowBox.Size(); shadowCamera.SetOrthoSize(Vector2(size.x, size.y)); shadowCamera.SetZoom(1.0f); // Center shadow camera to the view space bounding box Vector3 pos(shadowCamera.WorldPosition()); Quaternion rot(shadowCamera.WorldRotation()); Vector3 adjust(center.x, center.y, 0.0f); shadowCamera.Translate(rot * adjust, TS_WORLD); // Snap to whole texels { Vector3 viewPos(rot.Inverse() * shadowCamera.WorldPosition()); float invSize = 1.0f / actualShadowMapSize; Vector2 texelSize(size.x * invSize, size.y * invSize); Vector3 snap(-fmodf(viewPos.x, texelSize.x), -fmodf(viewPos.y, texelSize.y), 0.0f); shadowCamera.Translate(rot * snap, TS_WORLD); } } break; case LIGHT_POINT: { static const Quaternion pointLightFaceRotations[] = { Quaternion(0.0f, 90.0f, 0.0f), Quaternion(0.0f, -90.0f, 0.0f), Quaternion(-90.0f, 0.0f, 0.0f), Quaternion(90.0f, 0.0f, 0.0f), Quaternion(0.0f, 0.0f, 0.0f), Quaternion(0.0f, 180.0f, 0.0f) }; IntVector2 topLeft(shadowRect.left, shadowRect.top); if (i & 1) topLeft.y += actualShadowMapSize; topLeft.x += ((unsigned)i >> 1) * actualShadowMapSize; view->viewport = IntRect(topLeft.x, topLeft.y, topLeft.x + actualShadowMapSize, topLeft.y + actualShadowMapSize); shadowCamera.SetTransform(WorldPosition(), pointLightFaceRotations[i]); shadowCamera.SetFov(90.0f); // Adjust zoom to avoid edge sampling artifacts (there is a matching adjustment in the shadow sampling) shadowCamera.SetZoom(0.99f); shadowCamera.SetFarClip(Range()); shadowCamera.SetNearClip(Range() * 0.01f); shadowCamera.SetOrthographic(false); shadowCamera.SetAspectRatio(1.0f); } break; case LIGHT_SPOT: view->viewport = shadowRect; shadowCamera.SetTransform(WorldPosition(), WorldRotation()); shadowCamera.SetFov(fov); shadowCamera.SetZoom(1.0f); shadowCamera.SetFarClip(Range()); shadowCamera.SetNearClip(Range() * 0.01f); shadowCamera.SetOrthographic(false); shadowCamera.SetAspectRatio(1.0f); break; } } // Setup shadow matrices now as camera positions have been finalized if (lightType != LIGHT_POINT) { shadowMatrices.Resize(numViews); for (size_t i = 0; i < numViews; ++i) { ShadowView* view = shadowViews[useIndex + i].Get(); Camera& shadowCamera = view->shadowCamera; float width = (float)shadowMap->Width(); float height = (float)shadowMap->Height(); Vector3 offset((float)view->viewport.left / width, (float)view->viewport.top / height, 0.0f); Vector3 scale(0.5f * (float)view->viewport.Width() / width, 0.5f * (float)view->viewport.Height() / height, 1.0f); offset.x += scale.x; offset.y += scale.y; scale.y = -scale.y; // OpenGL has different depth range #ifdef TURSO3D_OPENGL offset.z = 0.5f; scale.z = 0.5f; #endif Matrix4 texAdjust(Matrix4::IDENTITY); texAdjust.SetTranslation(offset); texAdjust.SetScale(scale); shadowMatrices[i] = texAdjust * shadowCamera.ProjectionMatrix() * shadowCamera.ViewMatrix(); } } else { // Point lights use an extra constant instead shadowMatrices.Clear(); Vector2 textureSize((float)shadowMap->Width(), (float)shadowMap->Height()); pointShadowParameters = Vector4(actualShadowMapSize / textureSize.x, actualShadowMapSize / textureSize.y, (float)shadowRect.left / textureSize.x, (float)shadowRect.top / textureSize.y); } // Calculate shadow mapping constants Camera& shadowCamera = shadowViews[useIndex]->shadowCamera; float nearClip = shadowCamera.NearClip(); float farClip = shadowCamera.FarClip(); float q = farClip / (farClip - nearClip); float r = -q * nearClip; shadowParameters = Vector4(0.5f / (float)shadowMap->Width(), 0.5f / (float)shadowMap->Height(), q, r); useIndex += numViews; }