|
|
@@ -69,6 +69,7 @@ BillboardSet::BillboardSet(Context* context) :
|
|
|
relative_(true),
|
|
|
scaled_(true),
|
|
|
sorted_(false),
|
|
|
+ fixedScreenSize_(false),
|
|
|
faceCameraMode_(FC_ROTATE_XYZ),
|
|
|
geometry_(new Geometry(context)),
|
|
|
vertexBuffer_(new VertexBuffer(context_)),
|
|
|
@@ -104,6 +105,7 @@ void BillboardSet::RegisterObject(Context* context)
|
|
|
URHO3D_ACCESSOR_ATTRIBUTE("Relative Position", IsRelative, SetRelative, bool, true, AM_DEFAULT);
|
|
|
URHO3D_ACCESSOR_ATTRIBUTE("Relative Scale", IsScaled, SetScaled, bool, true, AM_DEFAULT);
|
|
|
URHO3D_ACCESSOR_ATTRIBUTE("Sort By Distance", IsSorted, SetSorted, bool, false, AM_DEFAULT);
|
|
|
+ URHO3D_ACCESSOR_ATTRIBUTE("Fixed Screen Size", IsFixedScreenSize, SetFixedScreenSize, bool, false, AM_DEFAULT);
|
|
|
URHO3D_ACCESSOR_ATTRIBUTE("Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
|
|
|
URHO3D_ATTRIBUTE("Cast Shadows", bool, castShadows_, false, AM_DEFAULT);
|
|
|
URHO3D_ENUM_ACCESSOR_ATTRIBUTE("Face Camera Mode", GetFaceCameraMode, SetFaceCameraMode, FaceCameraMode, faceCameraModeNames, FC_ROTATE_XYZ, AM_DEFAULT);
|
|
|
@@ -141,6 +143,8 @@ void BillboardSet::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQue
|
|
|
|
|
|
// Approximate the billboards as spheres for raycasting
|
|
|
float size = INV_SQRT_TWO * (billboards_[i].size_.x_ * billboardScale.x_ + billboards_[i].size_.y_ * billboardScale.y_);
|
|
|
+ if (fixedScreenSize_)
|
|
|
+ size *= billboards_[i].screenScaleFactor_;
|
|
|
Vector3 center = billboardTransform * billboards_[i].position_;
|
|
|
Sphere billboardSphere(center, size);
|
|
|
|
|
|
@@ -174,10 +178,38 @@ void BillboardSet::UpdateBatches(const FrameInfo& frame)
|
|
|
// Sort if position relative to camera has changed
|
|
|
if (offset != previousOffset_)
|
|
|
{
|
|
|
- if(sorted_)
|
|
|
+ if (sorted_)
|
|
|
sortThisFrame_ = true;
|
|
|
- if(faceCameraMode_ == FC_DIRECTION)
|
|
|
+ if (faceCameraMode_ == FC_DIRECTION)
|
|
|
bufferDirty_ = true;
|
|
|
+
|
|
|
+ // Calculate fixed screen size scale factor for billboards if needed
|
|
|
+ if (fixedScreenSize_)
|
|
|
+ {
|
|
|
+ bufferDirty_ = true;
|
|
|
+ worldBoundingBoxDirty_ = true;
|
|
|
+ float invViewHeight = 1.0f / frame.viewSize_.y_;
|
|
|
+ float halfViewWorldSize = frame.camera_->GetHalfViewSize();
|
|
|
+
|
|
|
+ if (!frame.camera_->IsOrthographic())
|
|
|
+ {
|
|
|
+ Matrix4 viewProj(frame.camera_->GetProjection(false) * frame.camera_->GetView());
|
|
|
+ const Matrix3x4& worldTransform = node_->GetWorldTransform();
|
|
|
+ Matrix3x4 billboardTransform = relative_ ? worldTransform : Matrix3x4::IDENTITY;
|
|
|
+ Vector3 billboardScale = scaled_ ? worldTransform.Scale() : Vector3::ONE;
|
|
|
+
|
|
|
+ for (unsigned i = 0; i < billboards_.Size(); ++i)
|
|
|
+ {
|
|
|
+ Vector4 projPos(viewProj * Vector4(billboardTransform * billboards_[i].position_, 1.0f));
|
|
|
+ billboards_[i].screenScaleFactor_ = invViewHeight * halfViewWorldSize * projPos.w_;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ for (unsigned i = 0; i < billboards_.Size(); ++i)
|
|
|
+ billboards_[i].screenScaleFactor_ = invViewHeight * halfViewWorldSize;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
distance_ = frame.camera_->GetDistance(GetWorldBoundingBox().Center());
|
|
|
@@ -254,6 +286,7 @@ void BillboardSet::SetNumBillboards(unsigned num)
|
|
|
billboards_[i].rotation_ = 0.0f;
|
|
|
billboards_[i].direction_ = Vector3::UP;
|
|
|
billboards_[i].enabled_ = false;
|
|
|
+ billboards_[i].screenScaleFactor_ = 1.0f;
|
|
|
}
|
|
|
|
|
|
bufferSizeDirty_ = true;
|
|
|
@@ -278,6 +311,12 @@ void BillboardSet::SetSorted(bool enable)
|
|
|
Commit();
|
|
|
}
|
|
|
|
|
|
+void BillboardSet::SetFixedScreenSize(bool enable)
|
|
|
+{
|
|
|
+ fixedScreenSize_ = enable;
|
|
|
+ Commit();
|
|
|
+}
|
|
|
+
|
|
|
void BillboardSet::SetFaceCameraMode(FaceCameraMode mode)
|
|
|
{
|
|
|
if ((faceCameraMode_ != FC_DIRECTION && mode == FC_DIRECTION) || (faceCameraMode_ == FC_DIRECTION && mode != FC_DIRECTION))
|
|
|
@@ -443,6 +482,9 @@ void BillboardSet::OnWorldBoundingBoxUpdate()
|
|
|
continue;
|
|
|
|
|
|
float size = INV_SQRT_TWO * (billboards_[i].size_.x_ * billboardScale.x_ + billboards_[i].size_.y_ * billboardScale.y_);
|
|
|
+ if (fixedScreenSize_)
|
|
|
+ size *= billboards_[i].screenScaleFactor_;
|
|
|
+
|
|
|
Vector3 center = billboardTransform * billboards_[i].position_;
|
|
|
Vector3 edge = Vector3::ONE * size;
|
|
|
worldBox.Merge(BoundingBox(center - edge, center + edge));
|
|
|
@@ -579,6 +621,8 @@ void BillboardSet::UpdateVertexBuffer(const FrameInfo& frame)
|
|
|
|
|
|
Vector2 size(billboard.size_.x_ * billboardScale.x_, billboard.size_.y_ * billboardScale.y_);
|
|
|
unsigned color = billboard.color_.ToUInt();
|
|
|
+ if (fixedScreenSize_)
|
|
|
+ size *= billboard.screenScaleFactor_;
|
|
|
|
|
|
float rotationMatrix[2][2];
|
|
|
SinCos(billboard.rotation_, rotationMatrix[0][1], rotationMatrix[0][0]);
|
|
|
@@ -634,6 +678,8 @@ void BillboardSet::UpdateVertexBuffer(const FrameInfo& frame)
|
|
|
|
|
|
Vector2 size(billboard.size_.x_ * billboardScale.x_, billboard.size_.y_ * billboardScale.y_);
|
|
|
unsigned color = billboard.color_.ToUInt();
|
|
|
+ if (fixedScreenSize_)
|
|
|
+ size *= billboard.screenScaleFactor_;
|
|
|
|
|
|
float rot2D[2][2];
|
|
|
SinCos(billboard.rotation_, rot2D[0][1], rot2D[0][0]);
|