/** * @brief * Returns the current joint anchor position */ void RagdollJoint::GetCurrentAnchor(Vector3 &vPosition) const { const Joint *pJoint = static_cast<Joint*>(m_pJointHandler->GetElement()); if (pJoint) pJoint->GetCurrentPivotPoint(vPosition); // We need to calculate the current anchor by hand :( else { // Get the attached body const RagdollBody *pAttachedBody = m_pParentRagdoll->GetBody(sAttached); if (pAttachedBody && pAttachedBody->bEnabled) { // Get the attached physics body const Body *pBody = static_cast<Body*>(pAttachedBody->GetBody()); if (pBody) { // Get initial physics body transform matrix Matrix3x4 mInitTrans; mInitTrans.FromQuatTrans(pAttachedBody->qRot, pAttachedBody->vPos); // Get current physics body transform matrix Matrix3x4 mTrans; pBody->GetTransformMatrix(mTrans); // Get the current joint anchor in local space const Vector3 vLocalAnchor = mInitTrans.GetInverted()*vJointAnchor; // Get the current joint anchor in world space vPosition = vLocalAnchor; vPosition *= mTrans; } } } }
/** * @brief * Gets the current camera viewport corners */ bool SNCamera::GetViewportCorners(Vector3 &vUpperRight, Vector3 &vLowerRight, Vector3 &vLowerLeft, Vector3 &vUpperLeft, bool bContainerSpace, float fDistance) { // Get the viewport const Renderer &cRenderer = GetSceneContext()->GetRendererContext().GetRenderer(); const uint32 nViewportWidth = static_cast<uint32>(cRenderer.GetViewport().GetWidth()); const uint32 nViewportHeight = static_cast<uint32>(cRenderer.GetViewport().GetHeight()); // Get near x/y/z const float fAspectRadio = static_cast<float>(nViewportWidth)/(static_cast<float>(nViewportHeight)*m_fAspect); const float e = static_cast<float>(1/Math::Tan(Math::DegToRad*m_fFOV*0.5f)); // Get viewport corners vUpperRight.SetXYZ( fDistance/e, fAspectRadio*fDistance/e, -fDistance); vLowerRight.SetXYZ( fDistance/e, -fAspectRadio*fDistance/e, -fDistance); vLowerLeft.SetXYZ(-fDistance/e, -fAspectRadio*fDistance/e, -fDistance); vUpperLeft.SetXYZ(-fDistance/e, fAspectRadio*fDistance/e, -fDistance); // Transform the corners into container space? if (bContainerSpace) { Matrix3x4 mWorld = GetViewMatrix(); mWorld.Invert(); vUpperRight = mWorld*vUpperRight; vLowerRight = mWorld*vLowerRight; vLowerLeft = mWorld*vLowerLeft; vUpperLeft = mWorld*vUpperLeft; } // Done return true; }
const Matrix3x4& Light::GetVolumeTransform(Camera* camera) { if (!node_) return Matrix3x4::IDENTITY; switch (lightType_) { case LIGHT_DIRECTIONAL: { Matrix3x4 quadTransform; Vector3 near, far; // Position the directional light quad in halfway between far & near planes to prevent depth clipping camera->GetFrustumSize(near, far); quadTransform.SetTranslation(Vector3(0.0f, 0.0f, (camera->GetNearClip() + camera->GetFarClip()) * 0.5f)); quadTransform.SetScale(Vector3(far.x_, far.y_, 1.0f)); // Will be oversized, but doesn't matter (gets frustum clipped) volumeTransform_ = camera->GetEffectiveWorldTransform() * quadTransform; break; } case LIGHT_SPOT: { float yScale = tanf(fov_ * M_DEGTORAD * 0.5f) * range_; float xScale = aspectRatio_ * yScale; volumeTransform_ = Matrix3x4(node_->GetWorldPosition(), node_->GetWorldRotation(), Vector3(xScale, yScale, range_)); } break; case LIGHT_POINT: volumeTransform_ = Matrix3x4(node_->GetWorldPosition(), Quaternion::IDENTITY, range_); break; } return volumeTransform_; }
void NavArea::DrawDebugGeometry(DebugRenderer* debug, bool depthTest) { if (debug && IsEnabledEffective()) { Matrix3x4 mat; mat.SetTranslation(node_->GetWorldPosition()); debug->AddBoundingBox(boundingBox_, mat, Color::GREEN, depthTest); } }
Matrix3x4 Light::GetFullscreenQuadTransform(Camera* camera) { Matrix3x4 quadTransform; Vector3 near, far; // Position the directional light quad in halfway between far & near planes to prevent depth clipping camera->GetFrustumSize(near, far); quadTransform.SetTranslation(Vector3(0.0f, 0.0f, (camera->GetNearClip() + camera->GetFarClip()) * 0.5f)); quadTransform.SetScale(Vector3(far.x_, far.y_, 1.0f)); // Will be oversized, but doesn't matter (gets frustum clipped) return camera->GetEffectiveWorldTransform() * quadTransform; }
void Node::SetParent(Node* parent) { if (parent) { Matrix3x4 oldWorldTransform = GetWorldTransform(); parent->AddChild(this); Matrix3x4 newTransform = parent->GetWorldTransform().Inverse() * oldWorldTransform; SetTransform(newTransform.Translation(), newTransform.Rotation(), newTransform.Scale()); } }
void Camera::updateFrustum() { if (projectionDirty_) updateProjection(); Matrix3x4 transform = Matrix3x4::translationMatrix(position); transform.rotateY(degToRad(-yaw - 180.0f)); transform.rotateX(degToRad(-pitch)); frustum_.setTransform(transform); frustumDirty_ = false; }
void RectangularMatrixTest::row() { const Matrix3x4 a(Vector4(1.0f, 2.0f, 3.0f, 4.0f), Vector4(5.0f, 6.0f, 7.0f, 8.0f), Vector4(9.0f, 10.0f, 11.0f, 12.0f)); CORRADE_COMPARE(a.row(1), Vector3(2.0f, 6.0f, 10.0f)); }
void RectangularMatrixTest::data() { Matrix3x4 m; Vector4 vector(4.0f, 5.0f, 6.0f, 7.0f); m[2] = vector; m[1][1] = 1.0f; m[0][2] = 1.5f; CORRADE_COMPARE(m[1][1], 1.0f); CORRADE_COMPARE(m[0][2], 1.5f); CORRADE_COMPARE(m[2], vector); CORRADE_COMPARE(m, Matrix3x4(Vector4(0.0f, 0.0f, 1.5f, 0.0f), Vector4(0.0f, 1.0f, 0.0f, 0.0f), Vector4(4.0f, 5.0f, 6.0f, 7.0f))); /* Pointer chasings, i.e. *(b.data()[1]), are not possible */ constexpr Matrix3x4 a(Vector4(3.0f, 5.0f, 8.0f, 4.0f), Vector4(4.5f, 4.0f, 7.0f, 3.0f), Vector4(7.0f, -1.7f, 8.0f, 0.0f)); constexpr Vector4 b = a[2]; constexpr Float c = a[1][2]; constexpr Float d = *a.data(); CORRADE_COMPARE(b, Vector4(7.0f, -1.7f, 8.0f, 0.0f)); CORRADE_COMPARE(c, 7.0f); CORRADE_COMPARE(d, 3.0f); }
//[-------------------------------------------------------] //[ Public virtual PLPhysics::Joint functions ] //[-------------------------------------------------------] void JointUniversal::GetCurrentPivotPoint(Vector3 &vPosition) const { const PLPhysics::Body *pParentBody = GetParentBody(); if (pParentBody) { // Get transform matrix Quaternion qQ; pParentBody->GetRotation(qQ); Vector3 vPos; pParentBody->GetPosition(vPos); Matrix3x4 mTrans; mTrans.FromQuatTrans(qQ, vPos); // Get the current joint anchor in world space vPosition = m_vLocalAnchor; vPosition *= mTrans; } }
/** * @brief * Returns the view matrix */ Matrix3x4 &SNCamera::GetViewMatrix() { // Calculate view matrix if required if (m_bAutoUpdate && (m_nInternalCameraFlags & RecalculateViewMatrix)) { // Calculate view matrix m_mView.View(CalculateViewRotation(), GetTransform().GetPosition()); if (GetFlags() & FlipY) { Matrix3x4 mScale; mScale.SetScaleMatrix(1.0f, -1.0f, 1.0f); m_mView *= mScale; } // Recalculation done m_nInternalCameraFlags &= ~RecalculateViewMatrix; } // Return the view matrix return m_mView; }
BoundingBox CollisionShape::GetWorldBoundingBox() const { if (shape_ && node_) { // Use the rigid body's world transform if possible, as it may be different from the rendering transform RigidBody* body = GetComponent<RigidBody>(); Matrix3x4 worldTransform = body ? Matrix3x4(body->GetPosition(), body->GetRotation(), node_->GetWorldScale()) : node_->GetWorldTransform(); Vector3 worldPosition(worldTransform * position_); Quaternion worldRotation(worldTransform.Rotation() * rotation_); btTransform shapeWorldTransform(ToBtQuaternion(worldRotation), ToBtVector3(worldPosition)); btVector3 aabbMin, aabbMax; shape_->getAabb(shapeWorldTransform, aabbMin, aabbMax); return BoundingBox(ToVector3(aabbMin), ToVector3(aabbMax)); } else return BoundingBox(); }
void Skybox::UpdateBatches(const FrameInfo& frame) { distance_ = 0.0f; if (frame.frameNumber_ != lastFrame_) { customWorldTransforms_.Clear(); lastFrame_ = frame.frameNumber_; } // Add camera position to fix the skybox in space. Use effective world transform to take reflection into account Matrix3x4 customWorldTransform = node_->GetWorldTransform(); customWorldTransform.SetTranslation(node_->GetWorldPosition() + frame.camera_->GetEffectiveWorldTransform().Translation()); HashMap<Camera*, Matrix3x4>::Iterator it = customWorldTransforms_.Insert(MakePair(frame.camera_, customWorldTransform)); for (unsigned i = 0; i < batches_.Size(); ++i) { batches_[i].worldTransform_ = &it->second_; batches_[i].distance_ = 0.0f; } }
void RectangularMatrixTest::diagonal() { Vector3 diagonal(-1.0f, 5.0f, 11.0f); Matrix4x3 a(Vector3(-1.0f, 1.0f, 3.0f), Vector3( 4.0f, 5.0f, 7.0f), Vector3( 8.0f, 9.0f, 11.0f), Vector3(12.0f, 13.0f, 15.0f)); CORRADE_COMPARE(a.diagonal(), diagonal); Matrix3x4 b(Vector4(-1.0f, 4.0f, 8.0f, 12.0f), Vector4( 1.0f, 5.0f, 9.0f, 13.0f), Vector4( 3.0f, 7.0f, 11.0f, 15.0f)); CORRADE_COMPARE(b.diagonal(), diagonal); }
void CollisionShape::DrawDebugGeometry(DebugRenderer* debug, bool depthTest) { if (debug && physicsWorld_ && shape_ && node_ && IsEnabledEffective()) { physicsWorld_->SetDebugRenderer(debug); physicsWorld_->SetDebugDepthTest(depthTest); // Use the rigid body's world transform if possible, as it may be different from the rendering transform Matrix3x4 worldTransform; RigidBody* body = GetComponent<RigidBody>(); bool bodyActive = false; if (body) { worldTransform = Matrix3x4(body->GetPosition(), body->GetRotation(), node_->GetWorldScale()); bodyActive = body->IsActive(); } else worldTransform = node_->GetWorldTransform(); Vector3 position = position_; // For terrains, undo the height centering performed automatically by Bullet if (shapeType_ == SHAPE_TERRAIN && geometry_) { HeightfieldData* heightfield = static_cast<HeightfieldData*>(geometry_.Get()); position.y_ += (heightfield->minHeight_ + heightfield->maxHeight_) * 0.5f; } Vector3 worldPosition(worldTransform * position); Quaternion worldRotation(worldTransform.Rotation() * rotation_); btDiscreteDynamicsWorld* world = physicsWorld_->GetWorld(); world->debugDrawObject(btTransform(ToBtQuaternion(worldRotation), ToBtVector3(worldPosition)), shape_, bodyActive ? WHITE : GREEN); physicsWorld_->SetDebugRenderer(0); } }
void RectangularMatrixTest::vector() { typedef Vector<3, Int> Vector3i; typedef RectangularMatrix<4, 3, Int> Matrix4x3i; typedef Vector<12, Int> Vector12i; Matrix4x3i a(Vector3i(0, 1, 2), Vector3i(3, 4, 5), Vector3i(6, 7, 8), Vector3i(9, 10, 11)); Vector12i b(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); CORRADE_COMPARE(a.toVector(), b); CORRADE_COMPARE(Matrix4x3i::fromVector(b), a); }
Matrix3x4 SceneNode::getLocalTransform() { Matrix3x4 transform = Matrix3x4(); transform.translate(position_); transform.rotateX(radToDeg(rotation_.x_)); transform.rotateY(radToDeg(rotation_.y_)); transform.rotateZ(radToDeg(rotation_.z_)); transform.scale(scale_); return transform; }
void Node::SetParent(Node* parent) { if (parent) { Matrix3x4 oldWorldTransform = GetWorldTransform(); parent->AddChild(this); if (parent != scene_) { Matrix3x4 newTransform = parent->GetWorldTransform().Inverse() * oldWorldTransform; SetTransform(newTransform.Translation(), newTransform.Rotation(), newTransform.Scale()); } else { // The root node is assumed to have identity transform, so can disregard it SetTransform(oldWorldTransform.Translation(), oldWorldTransform.Rotation(), oldWorldTransform.Scale()); } } }
bool Serializer::WriteMatrix3x4(const Matrix3x4& value) { return Write(value.Data(), sizeof value) == sizeof value; }
bool DecalSet::AddDecal(Drawable* target, const Vector3& worldPosition, const Quaternion& worldRotation, float size, float aspectRatio, float depth, const Vector2& topLeftUV, const Vector2& bottomRightUV, float timeToLive, float normalCutoff, unsigned subGeometry) { URHO3D_PROFILE(AddDecal); // Do not add decals in headless mode if (!node_ || !GetSubsystem<Graphics>()) return false; if (!target || !target->GetNode()) { URHO3D_LOGERROR("Null target drawable for decal"); return false; } // Check for animated target and switch into skinned/static mode if necessary AnimatedModel* animatedModel = dynamic_cast<AnimatedModel*>(target); if ((animatedModel && !skinned_) || (!animatedModel && skinned_)) { RemoveAllDecals(); skinned_ = animatedModel != 0; bufferDirty_ = true; } // Center the decal frustum on the world position Vector3 adjustedWorldPosition = worldPosition - 0.5f * depth * (worldRotation * Vector3::FORWARD); /// \todo target transform is not right if adding a decal to StaticModelGroup Matrix3x4 targetTransform = target->GetNode()->GetWorldTransform().Inverse(); // For an animated model, adjust the decal position back to the bind pose // To do this, need to find the bone the decal is colliding with if (animatedModel) { Skeleton& skeleton = animatedModel->GetSkeleton(); unsigned numBones = skeleton.GetNumBones(); Bone* bestBone = 0; float bestSize = 0.0f; for (unsigned i = 0; i < numBones; ++i) { Bone* bone = skeleton.GetBone(i); if (!bone->node_ || !bone->collisionMask_) continue; // Represent the decal as a sphere, try to find the biggest colliding bone Sphere decalSphere (bone->node_->GetWorldTransform().Inverse() * worldPosition, 0.5f * size / bone->node_->GetWorldScale().Length()); if (bone->collisionMask_ & BONECOLLISION_BOX) { float size = bone->boundingBox_.HalfSize().Length(); if (bone->boundingBox_.IsInside(decalSphere) && size > bestSize) { bestBone = bone; bestSize = size; } } else if (bone->collisionMask_ & BONECOLLISION_SPHERE) { Sphere boneSphere(Vector3::ZERO, bone->radius_); float size = bone->radius_; if (boneSphere.IsInside(decalSphere) && size > bestSize) { bestBone = bone; bestSize = size; } } } if (bestBone) targetTransform = (bestBone->node_->GetWorldTransform() * bestBone->offsetMatrix_).Inverse(); } // Build the decal frustum Frustum decalFrustum; Matrix3x4 frustumTransform = targetTransform * Matrix3x4(adjustedWorldPosition, worldRotation, 1.0f); decalFrustum.DefineOrtho(size, aspectRatio, 1.0, 0.0f, depth, frustumTransform); Vector3 decalNormal = (targetTransform * Vector4(worldRotation * Vector3::BACK, 0.0f)).Normalized(); decals_.Resize(decals_.Size() + 1); Decal& newDecal = decals_.Back(); newDecal.timeToLive_ = timeToLive; Vector<PODVector<DecalVertex> > faces; PODVector<DecalVertex> tempFace; unsigned numBatches = target->GetBatches().Size(); // Use either a specified subgeometry in the target, or all if (subGeometry < numBatches) GetFaces(faces, target, subGeometry, decalFrustum, decalNormal, normalCutoff); else { for (unsigned i = 0; i < numBatches; ++i) GetFaces(faces, target, i, decalFrustum, decalNormal, normalCutoff); } // Clip the acquired faces against all frustum planes for (unsigned i = 0; i < NUM_FRUSTUM_PLANES; ++i) { for (unsigned j = 0; j < faces.Size(); ++j) { PODVector<DecalVertex>& face = faces[j]; if (face.Empty()) continue; ClipPolygon(tempFace, face, decalFrustum.planes_[i], skinned_); face = tempFace; } } // Now triangulate the resulting faces into decal vertices for (unsigned i = 0; i < faces.Size(); ++i) { PODVector<DecalVertex>& face = faces[i]; if (face.Size() < 3) continue; for (unsigned j = 2; j < face.Size(); ++j) { newDecal.AddVertex(face[0]); newDecal.AddVertex(face[j - 1]); newDecal.AddVertex(face[j]); } } // Check if resulted in no triangles if (newDecal.vertices_.Empty()) { decals_.Pop(); return true; } if (newDecal.vertices_.Size() > maxVertices_) { URHO3D_LOGWARNING("Can not add decal, vertex count " + String(newDecal.vertices_.Size()) + " exceeds maximum " + String(maxVertices_)); decals_.Pop(); return false; } if (newDecal.indices_.Size() > maxIndices_) { URHO3D_LOGWARNING("Can not add decal, index count " + String(newDecal.indices_.Size()) + " exceeds maximum " + String(maxIndices_)); decals_.Pop(); return false; } // Calculate UVs Matrix4 projection(Matrix4::ZERO); projection.m11_ = (1.0f / (size * 0.5f)); projection.m00_ = projection.m11_ / aspectRatio; projection.m22_ = 1.0f / depth; projection.m33_ = 1.0f; CalculateUVs(newDecal, frustumTransform.Inverse(), projection, topLeftUV, bottomRightUV); // Transform vertices to this node's local space and generate tangents Matrix3x4 decalTransform = node_->GetWorldTransform().Inverse() * target->GetNode()->GetWorldTransform(); TransformVertices(newDecal, skinned_ ? Matrix3x4::IDENTITY : decalTransform); GenerateTangents(&newDecal.vertices_[0], sizeof(DecalVertex), &newDecal.indices_[0], sizeof(unsigned short), 0, newDecal.indices_.Size(), offsetof(DecalVertex, normal_), offsetof(DecalVertex, texCoord_), offsetof(DecalVertex, tangent_)); newDecal.CalculateBoundingBox(); numVertices_ += newDecal.vertices_.Size(); numIndices_ += newDecal.indices_.Size(); // Remove oldest decals if total vertices exceeded while (decals_.Size() && (numVertices_ > maxVertices_ || numIndices_ > maxIndices_)) RemoveDecals(1); URHO3D_LOGDEBUG("Added decal with " + String(newDecal.vertices_.Size()) + " vertices"); // If new decal is time limited, subscribe to scene post-update if (newDecal.timeToLive_ > 0.0f && !subscribed_) UpdateEventSubscription(false); MarkDecalsDirty(); return true; }
void gl_RenderModel(GLSprite * spr, int cm) { // [BB/EP] Take care of gl_fogmode and ZADF_FORCE_GL_DEFAULTS. OVERRIDE_FOGMODE_IF_NECESSARY FSpriteModelFrame * smf = spr->modelframe; // Setup transformation. gl.MatrixMode(GL_MODELVIEW); gl.PushMatrix(); gl.DepthFunc(GL_LEQUAL); // [BB] In case the model should be rendered translucent, do back face culling. // This solves a few of the problems caused by the lack of depth sorting. // TO-DO: Implement proper depth sorting. if (!( spr->actor->RenderStyle == LegacyRenderStyles[STYLE_Normal] )) { gl.Enable(GL_CULL_FACE); glFrontFace(GL_CW); } int translation = 0; if ( !(smf->flags & MDL_IGNORETRANSLATION) ) translation = spr->actor->Translation; // y scale for a sprite means height, i.e. z in the world! float scaleFactorX = FIXED2FLOAT(spr->actor->scaleX) * smf->xscale; float scaleFactorY = FIXED2FLOAT(spr->actor->scaleX) * smf->yscale; float scaleFactorZ = FIXED2FLOAT(spr->actor->scaleY) * smf->zscale; float pitch = 0; float rotateOffset = 0; float angle = ANGLE_TO_FLOAT(spr->actor->angle); // [BB] Workaround for the missing pitch information. if ( (smf->flags & MDL_PITCHFROMMOMENTUM) ) { const double x = static_cast<double>(spr->actor->velx); const double y = static_cast<double>(spr->actor->vely); const double z = static_cast<double>(spr->actor->velz); // [BB] Calculate the pitch using spherical coordinates. pitch = float(atan( z/sqrt(x*x+y*y) ) / M_PI * 180); } if( smf->flags & MDL_ROTATING ) { const float time = smf->rotationSpeed*GetTimeFloat()/200.f; rotateOffset = float((time - xs_FloorToInt(time)) *360.f ); } if (gl_fogmode != 2 && (GLRenderer->mLightCount == 0 || !gl_light_models)) { // Model space => World space gl.Translatef(spr->x, spr->z, spr->y ); if ( !(smf->flags & MDL_ALIGNANGLE) ) gl.Rotatef(-angle, 0, 1, 0); // [BB] Change the angle so that the object is exactly facing the camera in the x/y plane. else gl.Rotatef( -ANGLE_TO_FLOAT ( R_PointToAngle ( spr->actor->x, spr->actor->y ) ), 0, 1, 0); // [BB] Change the pitch so that the object is vertically facing the camera (only makes sense combined with MDL_ALIGNANGLE). if ( (smf->flags & MDL_ALIGNPITCH) ) { const fixed_t distance = R_PointToDist2( spr->actor->x - viewx, spr->actor->y - viewy ); const float pitch = RAD2DEG ( atan2( FIXED2FLOAT ( spr->actor->z - viewz ), FIXED2FLOAT ( distance ) ) ); gl.Rotatef(pitch, 0, 0, 1); } // [BB] Workaround for the missing pitch information. if (pitch != 0) gl.Rotatef(pitch, 0, 0, 1); // [BB] Special flag for flat, beam like models. if ( (smf->flags & MDL_ROLLAGAINSTANGLE) ) gl.Rotatef( gl_RollAgainstAngleHelper ( spr->actor ), 1, 0, 0); // Model rotation. // [BB] Added Doomsday like rotation of the weapon pickup models. // The rotation angle is based on the elapsed time. if( smf->flags & MDL_ROTATING ) { gl.Translatef(smf->rotationCenterX, smf->rotationCenterY, smf->rotationCenterZ); gl.Rotatef(rotateOffset, smf->xrotate, smf->yrotate, smf->zrotate); gl.Translatef(-smf->rotationCenterX, -smf->rotationCenterY, -smf->rotationCenterZ); } // Scaling and model space offset. gl.Scalef(scaleFactorX, scaleFactorZ, scaleFactorY); // [BB] Apply zoffset here, needs to be scaled by 1 / smf->zscale, so that zoffset doesn't depend on the z-scaling. gl.Translatef(0., smf->zoffset / smf->zscale, 0.); gl_RenderFrameModels( smf, spr->actor->state, spr->actor->tics, RUNTIME_TYPE(spr->actor), cm, NULL, NULL, translation ); } else { Matrix3x4 ModelToWorld; Matrix3x4 NormalTransform; // For radial fog we need to pass coordinates in world space in order to calculate distances. // That means that the local transformations cannot be part of the modelview matrix ModelToWorld.MakeIdentity(); // Model space => World space ModelToWorld.Translate(spr->x, spr->z, spr->y); if ( !(smf->flags & MDL_ALIGNANGLE) ) ModelToWorld.Rotate(0,1,0, -angle); // [BB] Change the angle so that the object is exactly facing the camera in the x/y plane. else ModelToWorld.Rotate(0,1,0, -ANGLE_TO_FLOAT ( R_PointToAngle ( spr->actor->x, spr->actor->y ) ) ); // [BB] Change the pitch so that the object is vertically facing the camera (only makes sense combined with MDL_ALIGNANGLE). if ( (smf->flags & MDL_ALIGNPITCH) ) { const fixed_t distance = R_PointToDist2( spr->actor->x - viewx, spr->actor->y - viewy ); const float pitch = RAD2DEG ( atan2( FIXED2FLOAT ( spr->actor->z - viewz ), FIXED2FLOAT ( distance ) ) ); ModelToWorld.Rotate(0,0,1,pitch); } // [BB] Workaround for the missing pitch information. if (pitch != 0) ModelToWorld.Rotate(0,0,1,pitch); // [BB] Special flag for flat, beam like models. if ( (smf->flags & MDL_ROLLAGAINSTANGLE) ) ModelToWorld.Rotate(1, 0, 0, gl_RollAgainstAngleHelper ( spr->actor )); // Model rotation. // [BB] Added Doomsday like rotation of the weapon pickup models. // The rotation angle is based on the elapsed time. if( smf->flags & MDL_ROTATING ) { ModelToWorld.Translate(-smf->rotationCenterX, -smf->rotationCenterY, -smf->rotationCenterZ); ModelToWorld.Rotate(smf->xrotate, smf->yrotate, smf->zrotate, rotateOffset); ModelToWorld.Translate(smf->rotationCenterX, smf->rotationCenterY, smf->rotationCenterZ); } ModelToWorld.Scale(scaleFactorX, scaleFactorZ, scaleFactorY); // [BB] Apply zoffset here, needs to be scaled by 1 / smf->zscale, so that zoffset doesn't depend on the z-scaling. ModelToWorld.Translate(0., smf->zoffset / smf->zscale, 0.); if (!gl_light_models) { gl_RenderFrameModels( smf, spr->actor->state, spr->actor->tics, RUNTIME_TYPE(spr->actor), cm, &ModelToWorld, NULL, translation ); } else { // The normal transform matrix only contains the inverse rotations and scalings but not the translations NormalTransform.MakeIdentity(); NormalTransform.Scale(1.f/scaleFactorX, 1.f/scaleFactorZ, 1.f/scaleFactorY); if( smf->flags & MDL_ROTATING ) NormalTransform.Rotate(smf->xrotate, smf->yrotate, smf->zrotate, -rotateOffset); if (pitch != 0) NormalTransform.Rotate(0,0,1,-pitch); if (angle != 0) NormalTransform.Rotate(0,1,0, angle); gl_RenderFrameModels( smf, spr->actor->state, spr->actor->tics, RUNTIME_TYPE(spr->actor), cm, &ModelToWorld, &NormalTransform, translation ); } } gl.MatrixMode(GL_MODELVIEW); gl.PopMatrix(); gl.DepthFunc(GL_LESS); if (!( spr->actor->RenderStyle == LegacyRenderStyles[STYLE_Normal] )) gl.Disable(GL_CULL_FACE); }
const Matrix3x4& Sprite::GetTransform() const { if (positionDirty_) { Vector2 pos = floatPosition_; Matrix3x4 parentTransform; if (parent_) { Sprite* parentSprite = dynamic_cast<Sprite*>(parent_); if (parentSprite) parentTransform = parentSprite->GetTransform(); else { const IntVector2& parentScreenPos = parent_->GetScreenPosition() + parent_->GetChildOffset(); parentTransform = Matrix3x4::IDENTITY; parentTransform.SetTranslation(Vector3((float)parentScreenPos.x_, (float)parentScreenPos.y_, 0.0f)); } switch (GetHorizontalAlignment()) { case HA_LEFT: break; case HA_CENTER: pos.x_ += (float)(parent_->GetSize().x_ / 2); break; case HA_RIGHT: pos.x_ += (float)parent_->GetSize().x_; break; } switch (GetVerticalAlignment()) { case VA_TOP: break; case VA_CENTER: pos.y_ += (float)(parent_->GetSize().y_ / 2); break; case VA_BOTTOM: pos.y_ += (float)(parent_->GetSize().y_); break; } } else parentTransform = Matrix3x4::IDENTITY; Matrix3x4 hotspotAdjust(Matrix3x4::IDENTITY); hotspotAdjust.SetTranslation(Vector3((float)-hotSpot_.x_, (float)-hotSpot_.y_, 0.0f)); Matrix3x4 mainTransform(Vector3(pos, 0.0f), Quaternion(rotation_, Vector3::FORWARD), Vector3(scale_, 1.0f)); transform_ = parentTransform * mainTransform * hotspotAdjust; positionDirty_ = false; // Calculate an approximate screen position for GetElementAt(), or pixel-perfect child elements Vector3 topLeftCorner = transform_ * Vector3::ZERO; screenPosition_ = IntVector2((int)topLeftCorner.x_, (int)topLeftCorner.y_); } return transform_; }
void JSONValue::AddMatrix3x4(const Matrix3x4& value) { AddString(value.ToString()); }
//========================================================================== // // // //========================================================================== void GLSprite::Draw(int pass) { if (pass!=GLPASS_PLAIN && pass != GLPASS_ALL && pass!=GLPASS_TRANSLUCENT) return; bool additivefog = false; int rel = extralight*gl_weaponlight; if (pass==GLPASS_TRANSLUCENT) { // The translucent pass requires special setup for the various modes. // Brightmaps will only be used when doing regular drawing ops and having no fog if (!gl_isBlack(Colormap.FadeColor) || level.flags&LEVEL_HASFADETABLE || RenderStyle.BlendOp != STYLEOP_Add) { gl_RenderState.EnableBrightmap(false); } gl_SetRenderStyle(RenderStyle, false, // The rest of the needed checks are done inside gl_SetRenderStyle trans > 1.f - FLT_EPSILON && gl_usecolorblending && gl_fixedcolormap < CM_FIRSTSPECIALCOLORMAP && actor && fullbright && gltexture && !gltexture->GetTransparent()); if (hw_styleflags == STYLEHW_NoAlphaTest) { gl_RenderState.EnableAlphaTest(false); } else { gl_RenderState.AlphaFunc(GL_GEQUAL,trans*gl_mask_sprite_threshold); } if (RenderStyle.BlendOp == STYLEOP_Fuzz) { float fuzzalpha=0.44f; float minalpha=0.1f; // fog + fuzz don't work well without some fiddling with the alpha value! if (!gl_isBlack(Colormap.FadeColor)) { float xcamera=FIXED2FLOAT(viewx); float ycamera=FIXED2FLOAT(viewy); float dist=Dist2(xcamera,ycamera, x,y); if (!Colormap.FadeColor.a) Colormap.FadeColor.a=clamp<int>(255-lightlevel,60,255); // this value was determined by trial and error and is scale dependent! float factor=0.05f+exp(-Colormap.FadeColor.a*dist/62500.f); fuzzalpha*=factor; minalpha*=factor; } gl_RenderState.AlphaFunc(GL_GEQUAL,minalpha*gl_mask_sprite_threshold); gl.Color4f(0.2f,0.2f,0.2f,fuzzalpha); additivefog = true; } else if (RenderStyle.BlendOp == STYLEOP_Add && RenderStyle.DestAlpha == STYLEALPHA_One) { additivefog = true; } } if (RenderStyle.BlendOp!=STYLEOP_Fuzz) { if (actor) { lightlevel = gl_SetSpriteLighting(RenderStyle, actor, lightlevel, rel, &Colormap, ThingColor, trans, fullbright || gl_fixedcolormap >= CM_FIRSTSPECIALCOLORMAP, false); } else if (particle) { if (gl_light_particles) { lightlevel = gl_SetSpriteLight(particle, lightlevel, rel, &Colormap, trans, ThingColor); } else { gl_SetColor(lightlevel, rel, &Colormap, trans, ThingColor); } } else return; } if (gl_isBlack(Colormap.FadeColor)) foglevel=lightlevel; if (RenderStyle.Flags & STYLEF_FadeToBlack) { Colormap.FadeColor=0; additivefog = true; } if (RenderStyle.Flags & STYLEF_InvertOverlay) { Colormap.FadeColor = Colormap.FadeColor.InverseColor(); additivefog=false; } gl_SetFog(foglevel, rel, &Colormap, additivefog); if (gltexture) gltexture->BindPatch(Colormap.colormap,translation); else if (!modelframe) gl_RenderState.EnableTexture(false); if (!modelframe) { // [BB] Billboard stuff const bool drawWithXYBillboard = ( !(actor && actor->renderflags & RF_FORCEYBILLBOARD) //&& GLRenderer->mViewActor != NULL && (gl_billboard_mode == 1 || (actor && actor->renderflags & RF_FORCEXYBILLBOARD )) ); gl_RenderState.Apply(); gl.Begin(GL_TRIANGLE_STRIP); if ( drawWithXYBillboard ) { // Rotate the sprite about the vector starting at the center of the sprite // triangle strip and with direction orthogonal to where the player is looking // in the x/y plane. float xcenter = (x1+x2)*0.5; float ycenter = (y1+y2)*0.5; float zcenter = (z1+z2)*0.5; float angleRad = DEG2RAD(270. - float(GLRenderer->mAngles.Yaw)); Matrix3x4 mat; mat.MakeIdentity(); mat.Translate( xcenter, zcenter, ycenter); mat.Rotate(-sin(angleRad), 0, cos(angleRad), -GLRenderer->mAngles.Pitch); mat.Translate( -xcenter, -zcenter, -ycenter); Vector v1 = mat * Vector(x1,z1,y1); Vector v2 = mat * Vector(x2,z1,y2); Vector v3 = mat * Vector(x1,z2,y1); Vector v4 = mat * Vector(x2,z2,y2); if (gltexture) { gl.TexCoord2f(ul, vt); gl.Vertex3fv(&v1[0]); gl.TexCoord2f(ur, vt); gl.Vertex3fv(&v2[0]); gl.TexCoord2f(ul, vb); gl.Vertex3fv(&v3[0]); gl.TexCoord2f(ur, vb); gl.Vertex3fv(&v4[0]); } else // Particle { gl.Vertex3fv(&v1[0]); gl.Vertex3fv(&v2[0]); gl.Vertex3fv(&v3[0]); gl.Vertex3fv(&v4[0]); } } else { if (gltexture) { gl.TexCoord2f(ul, vt); gl.Vertex3f(x1, z1, y1); gl.TexCoord2f(ur, vt); gl.Vertex3f(x2, z1, y2); gl.TexCoord2f(ul, vb); gl.Vertex3f(x1, z2, y1); gl.TexCoord2f(ur, vb); gl.Vertex3f(x2, z2, y2); } else // Particle { gl.Vertex3f(x1, z1, y1); gl.Vertex3f(x2, z1, y2); gl.Vertex3f(x1, z2, y1); gl.Vertex3f(x2, z2, y2); } } gl.End(); } else { gl_RenderModel(this, Colormap.colormap); } if (pass==GLPASS_TRANSLUCENT) { gl_RenderState.EnableBrightmap(true); gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); gl_RenderState.BlendEquation(GL_FUNC_ADD); gl_RenderState.SetTextureMode(TM_MODULATE); // [BB] Restore the alpha test after drawing a smooth particle. if (hw_styleflags == STYLEHW_NoAlphaTest) { gl_RenderState.EnableAlphaTest(true); } else { gl_RenderState.AlphaFunc(GL_GEQUAL,gl_mask_sprite_threshold); } } gl_RenderState.EnableTexture(true); }
void Batch::Prepare(View* view, bool setModelTransform) const { if (!vertexShader_ || !pixelShader_) return; Graphics* graphics = view->GetGraphics(); Renderer* renderer = view->GetRenderer(); Node* cameraNode = camera_ ? camera_->GetNode() : 0; Light* light = lightQueue_ ? lightQueue_->light_ : 0; Texture2D* shadowMap = lightQueue_ ? lightQueue_->shadowMap_ : 0; // Set pass / material-specific renderstates if (pass_ && material_) { bool isShadowPass = pass_->GetType() == PASS_SHADOW; BlendMode blend = pass_->GetBlendMode(); // Turn additive blending into subtract if the light is negative if (light && light->IsNegative()) { if (blend == BLEND_ADD) blend = BLEND_SUBTRACT; else if (blend == BLEND_ADDALPHA) blend = BLEND_SUBTRACTALPHA; } graphics->SetBlendMode(blend); renderer->SetCullMode(isShadowPass ? material_->GetShadowCullMode() : material_->GetCullMode(), camera_); if (!isShadowPass) { const BiasParameters& depthBias = material_->GetDepthBias(); graphics->SetDepthBias(depthBias.constantBias_, depthBias.slopeScaledBias_); } graphics->SetDepthTest(pass_->GetDepthTestMode()); graphics->SetDepthWrite(pass_->GetDepthWrite()); } // Set shaders first. The available shader parameters and their register/uniform positions depend on the currently set shaders graphics->SetShaders(vertexShader_, pixelShader_); // Set global (per-frame) shader parameters if (graphics->NeedParameterUpdate(SP_FRAME, (void*)0)) view->SetGlobalShaderParameters(); // Set camera shader parameters unsigned cameraHash = overrideView_ ? (unsigned)(size_t)camera_ + 4 : (unsigned)(size_t)camera_; if (graphics->NeedParameterUpdate(SP_CAMERA, reinterpret_cast<void*>(cameraHash))) view->SetCameraShaderParameters(camera_, true, overrideView_); // Set viewport shader parameters IntVector2 rtSize = graphics->GetRenderTargetDimensions(); IntRect viewport = graphics->GetViewport(); unsigned viewportHash = (viewport.left_) | (viewport.top_ << 8) | (viewport.right_ << 16) | (viewport.bottom_ << 24); if (graphics->NeedParameterUpdate(SP_VIEWPORT, reinterpret_cast<void*>(viewportHash))) { float rtWidth = (float)rtSize.x_; float rtHeight = (float)rtSize.y_; float widthRange = 0.5f * viewport.Width() / rtWidth; float heightRange = 0.5f * viewport.Height() / rtHeight; #ifdef URHO3D_OPENGL Vector4 bufferUVOffset(((float)viewport.left_) / rtWidth + widthRange, 1.0f - (((float)viewport.top_) / rtHeight + heightRange), widthRange, heightRange); #else Vector4 bufferUVOffset((0.5f + (float)viewport.left_) / rtWidth + widthRange, (0.5f + (float)viewport.top_) / rtHeight + heightRange, widthRange, heightRange); #endif graphics->SetShaderParameter(VSP_GBUFFEROFFSETS, bufferUVOffset); float sizeX = 1.0f / rtWidth; float sizeY = 1.0f / rtHeight; graphics->SetShaderParameter(PSP_GBUFFERINVSIZE, Vector4(sizeX, sizeY, 0.0f, 0.0f)); } // Set model or skinning transforms if (setModelTransform && graphics->NeedParameterUpdate(SP_OBJECTTRANSFORM, worldTransform_)) { if (geometryType_ == GEOM_SKINNED) { 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) { if (numWorldTransforms_ > 1) graphics->SetShaderParameter(VSP_BILLBOARDROT, worldTransform_[1].RotationMatrix()); else 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 bool overrideFogColorToBlack = blend == BLEND_ADD || blend == BLEND_ADDALPHA; unsigned zoneHash = (unsigned)(size_t)zone_; if (overrideFogColorToBlack) zoneHash += 0x80000000; if (zone_ && graphics->NeedParameterUpdate(SP_ZONE, reinterpret_cast<void*>(zoneHash))) { graphics->SetShaderParameter(VSP_AMBIENTSTARTCOLOR, zone_->GetAmbientStartColor()); graphics->SetShaderParameter(VSP_AMBIENTENDCOLOR, zone_->GetAmbientEndColor().ToVector4() - zone_->GetAmbientStartColor().ToVector4()); const BoundingBox& box = zone_->GetBoundingBox(); Vector3 boxSize = box.Size(); Matrix3x4 adjust(Matrix3x4::IDENTITY); adjust.SetScale(Vector3(1.0f / boxSize.x_, 1.0f / boxSize.y_, 1.0f / boxSize.z_)); 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); if (fogStart >= fogEnd * (1.0f - M_LARGE_EPSILON)) 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) { Vector3 worldFogHeightVec = zoneNode->GetWorldTransform() * Vector3(0.0f, zone_->GetFogHeight(), 0.0f); 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_) { if (graphics->NeedParameterUpdate(SP_VERTEXLIGHTS, lightQueue_) && graphics->HasShaderParameter(VS, VSP_VERTEXLIGHTS)) { 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); } if (lights.Size()) graphics->SetShaderParameter(VSP_VERTEXLIGHTS, vertexLights[0].Data(), lights.Size() * 3 * 4); } } if (light && graphics->NeedParameterUpdate(SP_LIGHT, light)) { // 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(VS, VSP_LIGHTMATRICES)) { switch (light->GetLightType()) { case LIGHT_DIRECTIONAL: { Matrix4 shadowMatrices[MAX_CASCADE_SPLITS]; unsigned numSplits = 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; 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; } } 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(PS, PSP_LIGHTMATRICES)) { switch (light->GetLightType()) { case LIGHT_DIRECTIONAL: { Matrix4 shadowMatrices[MAX_CASCADE_SPLITS]; unsigned numSplits = 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); } 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); } 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; } } // Set shadow mapping shader parameters if (shadowMap) { { // Calculate point light shadow sampling offsets (unrolled cube map) unsigned faceWidth = shadowMap->GetWidth() / 2; 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 // If using 4 shadow samples, offset the position diagonally by half pixel if (renderer->GetShadowQuality() & SHADOWQUALITY_HIGH_16BIT) { addX -= 0.5f / width; addY -= 0.5f / height; } 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 Camera* shadowCamera = lightQueue_->shadowSplits_[0].shadowCamera_; float nearClip = shadowCamera->GetNearClip(); 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(); 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)); float pcfValues = (1.0f - intensity); float samples = renderer->GetShadowQuality() >= SHADOWQUALITY_HIGH_16BIT ? 4.0f : 1.0f; 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(); if (lightQueue_->shadowSplits_.Size() > 2) 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); } } // Set material-specific shader parameters and textures if (material_) { if (graphics->NeedParameterUpdate(SP_MATERIAL, material_)) { // Update shader parameter animations material_->UpdateShaderParameterAnimations(); const HashMap<StringHash, MaterialShaderParameter>& parameters = material_->GetShaderParameters(); for (HashMap<StringHash, MaterialShaderParameter>::ConstIterator i = parameters.Begin(); i != parameters.End(); ++i) graphics->SetShaderParameter(i->first_, i->second_.value_); } const SharedPtr<Texture>* textures = material_->GetTextures(); for (unsigned i = 0; i < MAX_MATERIAL_TEXTURE_UNITS; ++i) { TextureUnit unit = (TextureUnit)i; if (textures[i] && graphics->HasTextureUnit(unit)) graphics->SetTexture(i, textures[i]); } } // Set light-related textures if (light) { if (shadowMap && graphics->HasTextureUnit(TU_SHADOWMAP)) graphics->SetTexture(TU_SHADOWMAP, shadowMap); if (graphics->HasTextureUnit(TU_LIGHTRAMP)) { Texture* rampTexture = light->GetRampTexture(); if (!rampTexture) rampTexture = renderer->GetDefaultLightRamp(); graphics->SetTexture(TU_LIGHTRAMP, rampTexture); } if (graphics->HasTextureUnit(TU_LIGHTSHAPE)) { Texture* shapeTexture = light->GetShapeTexture(); if (!shapeTexture && light->GetLightType() == LIGHT_SPOT) shapeTexture = renderer->GetDefaultLightSpot(); graphics->SetTexture(TU_LIGHTSHAPE, shapeTexture); } } }
BoundingBox NavArea::GetWorldBoundingBox() const { Matrix3x4 mat; mat.SetTranslation(node_->GetWorldPosition()); return boundingBox_.Transformed(mat); }
void JSONValue::SetMatrix3x4(const String& name, const Matrix3x4& value) { SetString(name, value.ToString()); }
bool GLSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp) { const auto &HWAngles = di->Viewpoint.HWAngles; if (actor != nullptr && (actor->renderflags & RF_SPRITETYPEMASK) == RF_FLATSPRITE) { Matrix3x4 mat; mat.MakeIdentity(); // [MC] Rotate around the center or offsets given to the sprites. // Counteract any existing rotations, then rotate the angle. // Tilt the actor up or down based on pitch (increase 'somersaults' forward). // Then counteract the roll and DO A BARREL ROLL. FAngle pitch = (float)-Angles.Pitch.Degrees; pitch.Normalized180(); mat.Translate(x, z, y); mat.Rotate(0, 1, 0, 270. - Angles.Yaw.Degrees); mat.Rotate(1, 0, 0, pitch.Degrees); if (actor->renderflags & RF_ROLLCENTER) { float cx = (x1 + x2) * 0.5; float cy = (y1 + y2) * 0.5; mat.Translate(cx - x, 0, cy - y); mat.Rotate(0, 1, 0, - Angles.Roll.Degrees); mat.Translate(-cx, -z, -cy); } else { mat.Rotate(0, 1, 0, - Angles.Roll.Degrees); mat.Translate(-x, -z, -y); } v[0] = mat * FVector3(x2, z, y2); v[1] = mat * FVector3(x1, z, y2); v[2] = mat * FVector3(x2, z, y1); v[3] = mat * FVector3(x1, z, y1); return true; } // [BB] Billboard stuff const bool drawWithXYBillboard = ((particle && gl_billboard_particles) || (!(actor && actor->renderflags & RF_FORCEYBILLBOARD) //&& di->mViewActor != nullptr && (gl_billboard_mode == 1 || (actor && actor->renderflags & RF_FORCEXYBILLBOARD)))); const bool drawBillboardFacingCamera = gl_billboard_faces_camera; // [Nash] has +ROLLSPRITE const bool drawRollSpriteActor = (actor != nullptr && actor->renderflags & RF_ROLLSPRITE); // [fgsfds] check sprite type mask uint32_t spritetype = (uint32_t)-1; if (actor != nullptr) spritetype = actor->renderflags & RF_SPRITETYPEMASK; // [Nash] is a flat sprite const bool isFlatSprite = (actor != nullptr) && (spritetype == RF_WALLSPRITE || spritetype == RF_FLATSPRITE); const bool useOffsets = (actor != nullptr) && !(actor->renderflags & RF_ROLLCENTER); // [Nash] check for special sprite drawing modes if (drawWithXYBillboard || drawBillboardFacingCamera || drawRollSpriteActor || isFlatSprite) { // Compute center of sprite float xcenter = (x1 + x2)*0.5; float ycenter = (y1 + y2)*0.5; float zcenter = (z1 + z2)*0.5; float xx = -xcenter + x; float zz = -zcenter + z; float yy = -ycenter + y; Matrix3x4 mat; mat.MakeIdentity(); mat.Translate(xcenter, zcenter, ycenter); // move to sprite center // Order of rotations matters. Perform yaw rotation (Y, face camera) before pitch (X, tilt up/down). if (drawBillboardFacingCamera && !isFlatSprite) { // [CMB] Rotate relative to camera XY position, not just camera direction, // which is nicer in VR float xrel = xcenter - vp->X; float yrel = ycenter - vp->Y; float absAngleDeg = RAD2DEG(atan2(-yrel, xrel)); float counterRotationDeg = 270. - HWAngles.Yaw.Degrees; // counteracts existing sprite rotation float relAngleDeg = counterRotationDeg + absAngleDeg; mat.Rotate(0, 1, 0, relAngleDeg); } // [fgsfds] calculate yaw vectors float yawvecX = 0, yawvecY = 0, rollDegrees = 0; float angleRad = (270. - HWAngles.Yaw).Radians(); if (actor) rollDegrees = Angles.Roll.Degrees; if (isFlatSprite) { yawvecX = Angles.Yaw.Cos(); yawvecY = Angles.Yaw.Sin(); } // [fgsfds] Rotate the sprite about the sight vector (roll) if (spritetype == RF_WALLSPRITE) { mat.Rotate(0, 1, 0, 0); if (drawRollSpriteActor) { if (useOffsets) mat.Translate(xx, zz, yy); mat.Rotate(yawvecX, 0, yawvecY, rollDegrees); if (useOffsets) mat.Translate(-xx, -zz, -yy); } } else if (drawRollSpriteActor) { if (useOffsets) mat.Translate(xx, zz, yy); if (drawWithXYBillboard) { mat.Rotate(-sin(angleRad), 0, cos(angleRad), -HWAngles.Pitch.Degrees); } mat.Rotate(cos(angleRad), 0, sin(angleRad), rollDegrees); if (useOffsets) mat.Translate(-xx, -zz, -yy); } else if (drawWithXYBillboard) { // Rotate the sprite about the vector starting at the center of the sprite // triangle strip and with direction orthogonal to where the player is looking // in the x/y plane. mat.Rotate(-sin(angleRad), 0, cos(angleRad), -HWAngles.Pitch.Degrees); } mat.Translate(-xcenter, -zcenter, -ycenter); // retreat from sprite center v[0] = mat * FVector3(x1, z1, y1); v[1] = mat * FVector3(x2, z1, y2); v[2] = mat * FVector3(x1, z2, y1); v[3] = mat * FVector3(x2, z2, y2); } else // traditional "Y" billboard mode { v[0] = FVector3(x1, z1, y1); v[1] = FVector3(x2, z1, y2); v[2] = FVector3(x1, z2, y1); v[3] = FVector3(x2, z2, y2); } return false; }
bool XMLElement::SetMatrix3x4(const ea::string& name, const Matrix3x4& value) { return SetAttribute(name, value.ToString()); }
/** * @brief * Constructor */ JointUniversal::JointUniversal(PLPhysics::World &cWorld, PLPhysics::Body *pParentBody, PLPhysics::Body *pChildBody, const Vector3 &vPivotPoint, const Vector3 &vPinDir1, const Vector3 &vPinDir2) : PLPhysics::JointUniversal(cWorld, static_cast<World&>(cWorld).CreateJointImpl(), pParentBody, pChildBody, vPivotPoint, vPinDir1, vPinDir2) { // Deactivate the physics simulation if required const bool bSimulationActive = cWorld.IsSimulationActive(); if (bSimulationActive) cWorld.SetSimulationActive(false); // Get the Newton physics world Newton::NewtonWorld *pNewtonWorld = static_cast<World&>(cWorld).GetNewtonWorld(); // Flush assigned bodies (MUST be done before creating the joint!) if (pParentBody) static_cast<BodyImpl&>(pParentBody->GetBodyImpl()).Flush(); if (pChildBody) static_cast<BodyImpl&>(pChildBody ->GetBodyImpl()).Flush(); // Get the Newton physics parent and child bodies const Newton::NewtonBody *pNewtonParentBody = pParentBody ? static_cast<BodyImpl&>(pParentBody->GetBodyImpl()).GetNewtonBody() : nullptr; const Newton::NewtonBody *pNewtonChildBody = pChildBody ? static_cast<BodyImpl&>(pChildBody ->GetBodyImpl()).GetNewtonBody() : nullptr; // [TODO] ?? /* if (pNewtonParentBody) NewtonBodySetUserData(pNewtonParentBody, nullptr); if (pNewtonChildBody) NewtonBodySetUserData(pNewtonChildBody, nullptr); */ // Get body initial transform matrix if (pParentBody) { // Get transform matrix Quaternion qQ; pParentBody->GetRotation(qQ); Vector3 vPos; pParentBody->GetPosition(vPos); Matrix3x4 mTrans; mTrans.FromQuatTrans(qQ, vPos); // And transform the initial joint anchor into the body object space mTrans.Invert(); m_vLocalAnchor = mTrans*vPivotPoint; } // Create the Newton physics joint Newton::NewtonJoint *pNewtonJoint = NewtonConstraintCreateUniversal(pNewtonWorld, m_vPivotPoint, m_vPinDir1, m_vPinDir2, pNewtonChildBody, pNewtonParentBody); // Set Newton universal callback function NewtonUniversalSetUserCallback(pNewtonJoint, JointUserCallback); // Initialize the Newton physics joint static_cast<JointImpl&>(GetJointImpl()).InitializeNewtonJoint(*this, *pNewtonJoint); // Reactivate the physics simulation if required if (bSimulationActive) cWorld.SetSimulationActive(bSimulationActive); }