Преглед изворни кода

Merged the face camera boolean and axes parameters used by BillboardSet & Text3D into a FaceCameraMode enum. Implement none, rotate XYZ, rotate Y, lookat XYZ & lookat Y modes. More can be added as necessary.

Lasse Öörni пре 11 година
родитељ
комит
84d06d2e61

+ 1 - 1
Bin/Data/Scripts/NinjaSnowWar.as

@@ -399,7 +399,7 @@ void SpawnPlayer(Connection@ connection)
         text3D.text = players[playerIndex].name;
         text3D.horizontalAlignment = HA_CENTER;
         text3D.verticalAlignment = VA_CENTER;
-        text3D.faceCamera = true;
+        text3D.faceCameraMode = FC_ROTATE_XYZ;
     }
 }
 

+ 16 - 14
Source/Engine/Graphics/BillboardSet.cpp

@@ -46,6 +46,16 @@ extern const char* GEOMETRY_CATEGORY;
 
 static const float INV_SQRT_TWO = 1.0f / sqrtf(2.0f);
 
+const char* faceCameraModeNames[] =
+{
+    "None",
+    "Rotate XYZ",
+    "Rotate Y",
+    "LookAt XYZ",
+    "LookAt Y",
+    0
+};
+
 inline bool CompareBillboards(Billboard* lhs, Billboard* rhs)
 {
     return lhs->sortDistance_ > rhs->sortDistance_;
@@ -53,13 +63,12 @@ inline bool CompareBillboards(Billboard* lhs, Billboard* rhs)
 
 BillboardSet::BillboardSet(Context* context) :
     Drawable(context, DRAWABLE_GEOMETRY),
-    faceCameraAxes_(Vector3::ONE),
     animationLodBias_(1.0f),
     animationLodTimer_(0.0f),
     relative_(true),
     scaled_(true),
     sorted_(false),
-    faceCamera_(true),
+    faceCameraMode_(FC_ROTATE_XYZ),
     geometry_(new Geometry(context)),
     vertexBuffer_(new VertexBuffer(context_)),
     indexBuffer_(new IndexBuffer(context_)),
@@ -93,8 +102,7 @@ void BillboardSet::RegisterObject(Context* context)
     ACCESSOR_ATTRIBUTE(BillboardSet, VAR_BOOL, "Sort By Distance", IsSorted, SetSorted, bool, false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(BillboardSet, VAR_BOOL, "Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
     ATTRIBUTE(BillboardSet, VAR_BOOL, "Cast Shadows", castShadows_, false, AM_DEFAULT);
-    ATTRIBUTE(BillboardSet, VAR_BOOL, "Face Camera", faceCamera_, true, AM_DEFAULT);
-    ATTRIBUTE(BillboardSet, VAR_VECTOR3, "Face Camera Axes", faceCameraAxes_, Vector3::ONE, AM_DEFAULT);
+    ENUM_ATTRIBUTE(BillboardSet, "Face Camera Mode", faceCameraMode_, faceCameraModeNames, FC_ROTATE_XYZ, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(BillboardSet, VAR_FLOAT, "Draw Distance", GetDrawDistance, SetDrawDistance, float, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(BillboardSet, VAR_FLOAT, "Shadow Distance", GetShadowDistance, SetShadowDistance, float, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(BillboardSet, VAR_FLOAT, "Animation LOD Bias", GetAnimationLodBias, SetAnimationLodBias, float, 1.0f, AM_DEFAULT);
@@ -181,8 +189,8 @@ void BillboardSet::UpdateBatches(const FrameInfo& frame)
     // Billboard positioning
     transforms_[0] = relative_ ? node_->GetWorldTransform() : Matrix3x4::IDENTITY;
     // Billboard rotation
-    transforms_[1] = Matrix3x4(Vector3::ZERO, faceCamera_ ? frame.camera_->GetFaceCameraRotation(
-        node_->GetWorldRotation(), faceCameraAxes_) : node_->GetWorldRotation(), Vector3::ONE);
+    transforms_[1] = Matrix3x4(Vector3::ZERO, faceCameraMode_ != FC_NONE ? frame.camera_->GetFaceCameraRotation(
+        node_->GetWorldPosition(), node_->GetWorldRotation(), faceCameraMode_) : node_->GetWorldRotation(), Vector3::ONE);
 }
 
 void BillboardSet::UpdateGeometry(const FrameInfo& frame)
@@ -253,15 +261,9 @@ void BillboardSet::SetSorted(bool enable)
     Commit();
 }
 
-void BillboardSet::SetFaceCamera(bool enable)
-{
-    faceCamera_ = enable;
-    MarkNetworkUpdate();
-}
-
-void BillboardSet::SetFaceCameraAxes(const Vector3& axes)
+void BillboardSet::SetFaceCameraMode(FaceCameraMode mode)
 {
-    faceCameraAxes_ = axes;
+    faceCameraMode_ = mode;
     MarkNetworkUpdate();
 }
 

+ 6 - 10
Source/Engine/Graphics/BillboardSet.h

@@ -87,10 +87,8 @@ public:
     void SetScaled(bool enable);
     /// Set whether billboards are sorted by distance. Default false.
     void SetSorted(bool enable);
-    /// Set whether billboards face the camera automatically. Default true.
-    void SetFaceCamera(bool enable);
-    /// Set on which coordinate axes the billboards face the camera. Default all axes (1,1,1). Negative axes imply facing away.
-    void SetFaceCameraAxes(const Vector3& axes);
+    /// Set how the billboards should rotate in relation to the camera. Default is to follow camera rotation on all axes (FC_ROTATE_XYZ.)
+    void SetFaceCameraMode(FaceCameraMode mode);
     /// Set animation LOD bias.
     void SetAnimationLodBias(float bias);
     /// Mark for bounding box and vertex buffer update. Call after modifying the billboards.
@@ -110,10 +108,8 @@ public:
     bool IsScaled() const { return scaled_; }
     /// Return whether billboards are sorted.
     bool IsSorted() const { return sorted_; }
-    /// Return whether faces the camera automatically.
-    bool GetFaceCamera() const { return faceCamera_; }
-    /// Return on which coordinate axes camera facing is done.
-    const Vector3& GetFaceCameraAxes() const { return faceCameraAxes_; }
+    /// Return how the billboards rotate in relation to the camera.
+    FaceCameraMode GetFaceCameraMode() const { return faceCameraMode_; }
     /// Return animation LOD bias.
     float GetAnimationLodBias() const { return animationLodBias_; }
     
@@ -150,8 +146,8 @@ protected:
     bool scaled_;
     /// Billboards sorted flag.
     bool sorted_;
-    /// Face camera flag.
-    bool faceCamera_;
+    /// Billboard rotation mode in relation to the camera.
+    FaceCameraMode faceCameraMode_;
     
 private:
     /// Resize billboard vertex and index buffers.

+ 32 - 24
Source/Engine/Graphics/Camera.cpp

@@ -527,39 +527,47 @@ float Camera::GetLodDistance(float distance, float scale, float bias) const
         return orthoSize_ / d;
 }
 
-Quaternion Camera::GetFaceCameraRotation(const Quaternion& rotation, const Vector3& faceCameraAxes)
+Quaternion Camera::GetFaceCameraRotation(const Vector3& position, const Quaternion& rotation, FaceCameraMode mode)
 {
     if (!node_)
         return rotation;
     
-    // No facing
-    if (faceCameraAxes == Vector3::ZERO)
+    switch (mode)
+    {
+    default:
         return rotation;
-    // Facing on all axes
-    else if (faceCameraAxes.x_ > 0.0f && faceCameraAxes.y_ > 0.0f && faceCameraAxes.z_ > 0.0f)
+        
+    case FC_ROTATE_XYZ:
         return node_->GetWorldRotation();
-    // Selective facing based on Euler angle rewriting
-    else
-    {
-        Vector3 euler = rotation.EulerAngles();
-        Vector3 cameraEuler = node_->GetWorldRotation().EulerAngles();
         
-        if (faceCameraAxes.x_ > 0.0f)
-            euler.x_ = cameraEuler.x_;
-        else if (faceCameraAxes.x_ < 0.0f)
-            euler.x_ = cameraEuler.x_ + 180.0f;
+    case FC_ROTATE_Y:
+        {
+            Vector3 euler = rotation.EulerAngles();
+            euler.y_ = node_->GetWorldRotation().EulerAngles().y_;
+            return Quaternion(euler.x_, euler.y_, euler.z_);
+        }
         
-        if (faceCameraAxes.y_ > 0.0f)
-            euler.y_ = cameraEuler.y_;
-        else if (faceCameraAxes.y_ < 0.0f)
-            euler.y_ = -cameraEuler.y_ + 180.0f;
+    case FC_LOOKAT_XYZ:
+        {
+            Quaternion lookAt;
+            lookAt.FromLookRotation(position - node_->GetWorldPosition());
+            return lookAt;
+        }
         
-        if (faceCameraAxes.z_ > 0.0f)
-            euler.z_ = cameraEuler.z_;
-        else if (faceCameraAxes.z_ < 0.0f)
-            euler.z_ = -cameraEuler.z_ + 180.0f;
-
-        return Quaternion(euler.x_, euler.y_, euler.z_);
+    case FC_LOOKAT_Y:
+        {
+            // Make the Y-only lookat happen on an XZ plane to make sure there are no unwanted transitions
+            // or singularities
+            Vector3 lookAtVec(position - node_->GetWorldPosition());
+            lookAtVec.y_ = 0.0f;
+            
+            Quaternion lookAt;
+            lookAt.FromLookRotation(lookAtVec);
+            
+            Vector3 euler = rotation.EulerAngles();
+            euler.y_ = lookAt.EulerAngles().y_;
+            return Quaternion(euler.x_, euler.y_, euler.z_);
+        }
     }
 }
 

+ 1 - 1
Source/Engine/Graphics/Camera.h

@@ -164,7 +164,7 @@ public:
     /// Return a scene node's LOD scaled distance.
     float GetLodDistance(float distance, float scale, float bias) const;
     /// Return a world rotation for facing a camera on certain axes based on the existing world rotation.
-    Quaternion GetFaceCameraRotation(const Quaternion& rotation, const Vector3& faceCameraAxes);
+    Quaternion GetFaceCameraRotation(const Vector3& position, const Quaternion& rotation, FaceCameraMode mode);
     /// Get effective world transform for matrix and frustum calculations including reflection but excluding node scaling.
     Matrix3x4 GetEffectiveWorldTransform() const;
     /// Return if projection parameters are valid for rendering and raycasting.

+ 46 - 36
Source/Engine/Graphics/GraphicsDefs.h

@@ -197,6 +197,52 @@ enum ShaderType
     PS,
 };
 
+/// Shader parameter groups for determining need to update.
+enum ShaderParameterGroup
+{
+    SP_FRAME = 0,
+    SP_CAMERA,
+    SP_VIEWPORT,
+    SP_ZONE,
+    SP_LIGHT,
+    SP_VERTEXLIGHTS,
+    SP_MATERIAL,
+    SP_OBJECTTRANSFORM,
+    MAX_SHADER_PARAMETER_GROUPS
+};
+
+/// Texture units.
+enum TextureUnit
+{
+    TU_DIFFUSE = 0,
+    TU_ALBEDOBUFFER = 0,
+    TU_NORMAL = 1,
+    TU_NORMALBUFFER = 1,
+    TU_SPECULAR = 2,
+    TU_EMISSIVE = 3,
+    TU_ENVIRONMENT = 4,
+    MAX_MATERIAL_TEXTURE_UNITS = 5,
+    TU_LIGHTRAMP = 5,
+    TU_LIGHTSHAPE = 6,
+    TU_SHADOWMAP = 7,
+    TU_FACESELECT = 8,
+    TU_INDIRECTION = 9,
+    TU_DEPTHBUFFER = 10,
+    TU_LIGHTBUFFER = 11,
+    TU_VOLUMEMAP = 12,
+    MAX_TEXTURE_UNITS = 13
+};
+
+/// Billboard camera facing modes.
+enum FaceCameraMode
+{
+    FC_NONE = 0,
+    FC_ROTATE_XYZ,
+    FC_ROTATE_Y,
+    FC_LOOKAT_XYZ,
+    FC_LOOKAT_Y
+};
+
 // Inbuilt shader parameters.
 extern StringHash VSP_AMBIENTSTARTCOLOR;
 extern StringHash VSP_AMBIENTENDCOLOR;
@@ -260,42 +306,6 @@ extern StringHash PASS_POSTALPHA;
 // Scale calculation from bounding box diagonal.
 extern Vector3 DOT_SCALE;
 
-/// Texture units.
-enum TextureUnit
-{
-    TU_DIFFUSE = 0,
-    TU_ALBEDOBUFFER = 0,
-    TU_NORMAL = 1,
-    TU_NORMALBUFFER = 1,
-    TU_SPECULAR = 2,
-    TU_EMISSIVE = 3,
-    TU_ENVIRONMENT = 4,
-    MAX_MATERIAL_TEXTURE_UNITS = 5,
-    TU_LIGHTRAMP = 5,
-    TU_LIGHTSHAPE = 6,
-    TU_SHADOWMAP = 7,
-    TU_FACESELECT = 8,
-    TU_INDIRECTION = 9,
-    TU_DEPTHBUFFER = 10,
-    TU_LIGHTBUFFER = 11,
-    TU_VOLUMEMAP = 12,
-    MAX_TEXTURE_UNITS = 13
-};
-
-/// Shader parameter groups for determining need to update.
-enum ShaderParameterGroup
-{
-    SP_FRAME = 0,
-    SP_CAMERA,
-    SP_VIEWPORT,
-    SP_ZONE,
-    SP_LIGHT,
-    SP_VERTEXLIGHTS,
-    SP_MATERIAL,
-    SP_OBJECTTRANSFORM,
-    MAX_SHADER_PARAMETER_GROUPS
-};
-
 static const int QUALITY_LOW = 0;
 static const int QUALITY_MEDIUM = 1;
 static const int QUALITY_HIGH = 2;

+ 2 - 2
Source/Engine/Graphics/ParticleEmitter.cpp

@@ -38,6 +38,7 @@ namespace Urho3D
 {
 
 extern const char* GEOMETRY_CATEGORY;
+extern const char* faceCameraModeNames[];
 
 static const char* emitterTypeNames[] =
 {
@@ -118,8 +119,7 @@ void ParticleEmitter::RegisterObject(Context* context)
     ACCESSOR_ATTRIBUTE(ParticleEmitter, VAR_BOOL, "Relative Position", IsRelative, SetRelative, bool, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(ParticleEmitter, VAR_BOOL, "Relative Scale", IsScaled, SetScaled, bool, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(ParticleEmitter, VAR_BOOL, "Sort By Distance", IsSorted, SetSorted, bool, false, AM_DEFAULT);
-    ATTRIBUTE(ParticleEmitter, VAR_BOOL, "Face Camera", faceCamera_, true, AM_DEFAULT);
-    ATTRIBUTE(ParticleEmitter, VAR_VECTOR3, "Face Camera Axes", faceCameraAxes_, Vector3::ONE, AM_DEFAULT);
+    ENUM_ATTRIBUTE(ParticleEmitter, "Face Camera Mode", faceCameraMode_, faceCameraModeNames, FC_ROTATE_XYZ, AM_DEFAULT);
     ATTRIBUTE(ParticleEmitter, VAR_FLOAT, "Time To Live Min", timeToLiveMin_, DEFAULT_TIME_TO_LIVE, AM_DEFAULT);
     ATTRIBUTE(ParticleEmitter, VAR_FLOAT, "Time To Live Max", timeToLiveMax_, DEFAULT_TIME_TO_LIVE, AM_DEFAULT);
     ATTRIBUTE(ParticleEmitter, VAR_VECTOR2, "Particle Size Min", sizeMin_, DEFAULT_PARTICLE_SIZE, AM_DEFAULT);

+ 3 - 6
Source/Engine/LuaScript/pkgs/Graphics/BillboardSet.pkg

@@ -18,8 +18,7 @@ class BillboardSet : public Drawable
     void SetRelative(bool enable);
     void SetScaled(bool enable);
     void SetSorted(bool enable);
-    void SetFaceCamera(bool enable);
-    void SetFaceCameraAxes(const Vector3& axes);
+    void SetFaceCameraMode(FaceCameraMode mode);
     void SetAnimationLodBias(float bias);
 
     void Commit();
@@ -30,8 +29,7 @@ class BillboardSet : public Drawable
     bool IsRelative() const;
     bool IsScaled() const;
     bool IsSorted() const;
-    bool GetFaceCamera() const;
-    const Vector3& GetFaceCameraAxes() const;
+    FaceCameraMode GetFaceCameraMode() const;
     float GetAnimationLodBias() const;
     
     tolua_property__get_set Material* material;
@@ -39,7 +37,6 @@ class BillboardSet : public Drawable
     tolua_property__is_set bool relative;
     tolua_property__is_set bool scaled;
     tolua_property__is_set bool sorted;
-    tolua_property__get_set bool faceCamera;
-    tolua_property__get_set Vector3& faceCameraAxes;
+    tolua_property__get_set FaceCameraMode faceCameraMode;
     tolua_property__get_set float animationLodBias;
 };

+ 19 - 10
Source/Engine/LuaScript/pkgs/Graphics/GraphicsDefs.pkg

@@ -151,6 +151,19 @@ enum ShaderType
     PS,
 };
 
+enum ShaderParameterGroup
+{
+    SP_FRAME = 0,
+    SP_CAMERA,
+    SP_VIEWPORT,
+    SP_ZONE,
+    SP_LIGHT,
+    SP_VERTEXLIGHTS,
+    SP_MATERIAL,
+    SP_OBJECTTRANSFORM,
+    MAX_SHADER_PARAMETER_GROUPS
+};
+
 enum TextureUnit
 {
     TU_DIFFUSE = 0,
@@ -172,17 +185,13 @@ enum TextureUnit
     MAX_TEXTURE_UNITS = 13
 };
 
-enum ShaderParameterGroup
+enum FaceCameraMode
 {
-    SP_FRAME = 0,
-    SP_CAMERA,
-    SP_VIEWPORT,
-    SP_ZONE,
-    SP_LIGHT,
-    SP_VERTEXLIGHTS,
-    SP_MATERIAL,
-    SP_OBJECTTRANSFORM,
-    MAX_SHADER_PARAMETER_GROUPS
+    FC_NONE = 0,
+    FC_ROTATE_XYZ,
+    FC_ROTATE_Y,
+    FC_LOOKAT_XYZ,
+    FC_LOOKAT_Y
 };
 
 static const int QUALITY_LOW;

+ 3 - 6
Source/Engine/LuaScript/pkgs/UI/Text3D.pkg

@@ -25,8 +25,7 @@ class Text3D : public Drawable
     void SetColor(const Color& color);
     void SetColor(Corner corner, const Color& color);
     void SetOpacity(float opacity);
-    void SetFaceCamera(bool enable);
-    void SetFaceCameraAxes(const Vector3& axes);
+    void SetFaceCameraMode(FaceCameraMode mode);
     
     Font* GetFont() const;
     Material* GetMaterial() const;
@@ -49,8 +48,7 @@ class Text3D : public Drawable
     IntVector2 GetCharSize(unsigned index);
     const Color& GetColor(Corner corner) const;
     float GetOpacity() const;
-    bool GetFaceCamera() const;
-    const Vector3& GetFaceCameraAxes() const;
+    FaceCameraMode GetFaceCameraMode() const;
     
     tolua_property__get_set Font* font;
     tolua_property__get_set Material* material;
@@ -70,8 +68,7 @@ class Text3D : public Drawable
     tolua_readonly tolua_property__get_set unsigned numRows;
     tolua_readonly tolua_property__get_set unsigned numChars;
     tolua_property__get_set float opacity;
-    tolua_property__get_set bool faceCamera;
-    tolua_property__get_set Vector3& faceCameraAxes;
+    tolua_property__get_set FaceCameraMode faceCameraMode;
 };
 
 ${

+ 11 - 8
Source/Engine/Script/GraphicsAPI.cpp

@@ -988,6 +988,13 @@ static void RegisterAnimationController(asIScriptEngine* engine)
 
 static void RegisterBillboardSet(asIScriptEngine* engine)
 {
+    engine->RegisterEnum("FaceCameraMode");
+    engine->RegisterEnumValue("FaceCameraMode", "FC_NONE", FC_NONE);
+    engine->RegisterEnumValue("FaceCameraMode", "FC_ROTATE_XYZ", FC_ROTATE_XYZ);
+    engine->RegisterEnumValue("FaceCameraMode", "FC_ROTATE_Y", FC_ROTATE_Y);
+    engine->RegisterEnumValue("FaceCameraMode", "FC_LOOKAT_XYZ", FC_LOOKAT_XYZ);
+    engine->RegisterEnumValue("FaceCameraMode", "FC_LOOKAT_Y", FC_LOOKAT_Y);
+    
     engine->RegisterObjectType("Billboard", 0, asOBJ_REF);
     engine->RegisterObjectBehaviour("Billboard", asBEHAVE_ADDREF, "void f()", asFUNCTION(FakeAddRef), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectBehaviour("Billboard", asBEHAVE_RELEASE, "void f()", asFUNCTION(FakeReleaseRef), asCALL_CDECL_OBJLAST);
@@ -1010,10 +1017,8 @@ static void RegisterBillboardSet(asIScriptEngine* engine)
     engine->RegisterObjectMethod("BillboardSet", "bool get_sorted() const", asMETHOD(BillboardSet, IsSorted), asCALL_THISCALL);
     engine->RegisterObjectMethod("BillboardSet", "void set_scaled(bool)", asMETHOD(BillboardSet, SetScaled), asCALL_THISCALL);
     engine->RegisterObjectMethod("BillboardSet", "bool get_scaled() const", asMETHOD(BillboardSet, IsScaled), asCALL_THISCALL);
-    engine->RegisterObjectMethod("BillboardSet", "void set_faceCamera(bool)", asMETHOD(BillboardSet, SetFaceCamera), asCALL_THISCALL);
-    engine->RegisterObjectMethod("BillboardSet", "bool get_faceCamera() const", asMETHOD(BillboardSet, GetFaceCamera), asCALL_THISCALL);
-    engine->RegisterObjectMethod("BillboardSet", "void set_faceCameraAxes(const Vector3&)", asMETHOD(BillboardSet, SetFaceCameraAxes), asCALL_THISCALL);
-    engine->RegisterObjectMethod("BillboardSet", "const Vector3& get_faceCameraAxes() const", asMETHOD(BillboardSet, GetFaceCameraAxes), asCALL_THISCALL);
+    engine->RegisterObjectMethod("BillboardSet", "void set_faceCameraMode(FaceCameraMode)", asMETHOD(BillboardSet, SetFaceCameraMode), asCALL_THISCALL);
+    engine->RegisterObjectMethod("BillboardSet", "FaceCameraMode get_faceCameraMode() const", asMETHOD(BillboardSet, GetFaceCameraMode), asCALL_THISCALL);
     engine->RegisterObjectMethod("BillboardSet", "void set_animationLodBias(float)", asMETHOD(BillboardSet, SetAnimationLodBias), asCALL_THISCALL);
     engine->RegisterObjectMethod("BillboardSet", "float get_animationLodBias() const", asMETHOD(BillboardSet, GetAnimationLodBias), asCALL_THISCALL);
     engine->RegisterObjectMethod("BillboardSet", "Billboard@+ get_billboards(uint)", asMETHOD(BillboardSet, GetBillboard), asCALL_THISCALL);
@@ -1056,10 +1061,8 @@ static void RegisterParticleEmitter(asIScriptEngine* engine)
     engine->RegisterObjectMethod("ParticleEmitter", "bool get_sorted() const", asMETHOD(ParticleEmitter, IsSorted), asCALL_THISCALL);
     engine->RegisterObjectMethod("ParticleEmitter", "void set_scaled(bool)", asMETHOD(ParticleEmitter, SetScaled), asCALL_THISCALL);
     engine->RegisterObjectMethod("ParticleEmitter", "bool get_scaled() const", asMETHOD(ParticleEmitter, IsScaled), asCALL_THISCALL);
-    engine->RegisterObjectMethod("ParticleEmitter", "void set_faceCamera(bool)", asMETHOD(ParticleEmitter, SetFaceCamera), asCALL_THISCALL);
-    engine->RegisterObjectMethod("ParticleEmitter", "bool get_faceCamera() const", asMETHOD(ParticleEmitter, GetFaceCamera), asCALL_THISCALL);
-    engine->RegisterObjectMethod("ParticleEmitter", "void set_faceCameraAxes(const Vector3&)", asMETHOD(ParticleEmitter, SetFaceCameraAxes), asCALL_THISCALL);
-    engine->RegisterObjectMethod("ParticleEmitter", "const Vector3& get_faceCameraAxes() const", asMETHOD(ParticleEmitter, GetFaceCameraAxes), asCALL_THISCALL);
+    engine->RegisterObjectMethod("ParticleEmitter", "void set_faceCameraMode(FaceCameraMode)", asMETHOD(ParticleEmitter, SetFaceCameraMode), asCALL_THISCALL);
+    engine->RegisterObjectMethod("ParticleEmitter", "FaceCameraMode get_faceCameraMode() const", asMETHOD(ParticleEmitter, GetFaceCameraMode), asCALL_THISCALL);
     engine->RegisterObjectMethod("ParticleEmitter", "void set_updateInvisible(bool)", asMETHOD(ParticleEmitter, SetUpdateInvisible), asCALL_THISCALL);
     engine->RegisterObjectMethod("ParticleEmitter", "bool get_updateInvisible() const", asMETHOD(ParticleEmitter, GetUpdateInvisible), asCALL_THISCALL);
     engine->RegisterObjectMethod("ParticleEmitter", "void set_animationLodBias(float)", asMETHOD(ParticleEmitter, SetAnimationLodBias), asCALL_THISCALL);

+ 2 - 4
Source/Engine/Script/UIAPI.cpp

@@ -396,10 +396,8 @@ static void RegisterText3D(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Text3D", "const Color& get_colors(Corner) const", asMETHOD(Text3D, GetColor), asCALL_THISCALL);
     engine->RegisterObjectMethod("Text3D", "void set_opacity(float)", asMETHOD(Text3D, SetOpacity), asCALL_THISCALL);
     engine->RegisterObjectMethod("Text3D", "float get_opacity() const", asMETHOD(Text3D, GetOpacity), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Text3D", "void set_faceCamera(bool)", asMETHOD(Text3D, SetFaceCamera), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Text3D", "bool get_faceCamera() const", asMETHOD(Text3D, GetFaceCamera), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Text3D", "void set_faceCameraAxes(const Vector3&)", asMETHOD(Text3D, SetFaceCameraAxes), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Text3D", "const Vector3& get_faceCameraAxes() const", asMETHOD(Text3D, GetFaceCameraAxes), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Text3D", "void set_faceCameraMode(FaceCameraMode)", asMETHOD(Text3D, SetFaceCameraMode), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Text3D", "FaceCameraMode get_faceCameraMode() const", asMETHOD(Text3D, GetFaceCameraMode), asCALL_THISCALL);
     engine->RegisterObjectMethod("Text3D", "uint get_numRows() const", asMETHOD(Text3D, GetNumRows), asCALL_THISCALL);
     engine->RegisterObjectMethod("Text3D", "uint get_numChars() const", asMETHOD(Text3D, GetNumChars), asCALL_THISCALL);
     engine->RegisterObjectMethod("Text3D", "int get_rowWidths(uint) const", asMETHOD(Text3D, GetRowWidth), asCALL_THISCALL);

+ 12 - 18
Source/Engine/UI/Text3D.cpp

@@ -40,6 +40,7 @@ namespace Urho3D
 extern const char* horizontalAlignments[];
 extern const char* verticalAlignments[];
 extern const char* textEffects[];
+extern const char* faceCameraModeNames[];
 extern const char* GEOMETRY_CATEGORY;
 
 static const float TEXT_SCALING = 1.0f / 128.0f;
@@ -50,8 +51,7 @@ Text3D::Text3D(Context* context) :
     text_(context),
     vertexBuffer_(new VertexBuffer(context_)),
     customWorldTransform_(Matrix3x4::IDENTITY),
-    faceCameraAxes_(Vector3::ONE),
-    faceCamera_(false),
+    faceCameraMode_(FC_NONE),
     textDirty_(true),
     geometryDirty_(true)
 {
@@ -75,8 +75,7 @@ void Text3D::RegisterObject(Context* context)
     ATTRIBUTE(Text3D, VAR_FLOAT, "Row Spacing", text_.rowSpacing_, 1.0f, AM_DEFAULT);
     ATTRIBUTE(Text3D, VAR_BOOL, "Word Wrap", text_.wordWrap_, false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Text3D, VAR_BOOL, "Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
-    ACCESSOR_ATTRIBUTE(Text3D, VAR_BOOL, "Face Camera", GetFaceCamera, SetFaceCamera, bool, false, AM_DEFAULT);
-    ATTRIBUTE(Text3D, VAR_VECTOR3, "Face Camera Axes", faceCameraAxes_, Vector3::ONE, AM_DEFAULT);
+    ENUM_ATTRIBUTE(Text3D, "Face Camera Mode", faceCameraMode_, faceCameraModeNames, FC_NONE, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Text3D, VAR_FLOAT, "Draw Distance", GetDrawDistance, SetDrawDistance, float, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Text3D, VAR_INT, "Width", GetWidth, SetWidth, int, 0, AM_DEFAULT);
     ENUM_ACCESSOR_ATTRIBUTE(Text3D, "Horiz Alignment", GetHorizontalAlignment, SetHorizontalAlignment, HorizontalAlignment, horizontalAlignments, HA_LEFT, AM_DEFAULT);
@@ -102,20 +101,20 @@ void Text3D::ApplyAttributes()
 
 void Text3D::UpdateBatches(const FrameInfo& frame)
 {
-    const Matrix3x4& worldTransform = node_->GetWorldTransform();
     distance_ = frame.camera_->GetDistance(GetWorldBoundingBox().Center());
     
-    if (faceCamera_)
+    if (faceCameraMode_ != FC_NONE)
     {
-        customWorldTransform_ = Matrix3x4(node_->GetWorldPosition(), frame.camera_->GetFaceCameraRotation(
-            node_->GetWorldRotation(), faceCameraAxes_), node_->GetWorldScale());
+        Vector3 worldPosition = node_->GetWorldPosition();
+        customWorldTransform_ = Matrix3x4(worldPosition, frame.camera_->GetFaceCameraRotation(
+            worldPosition, node_->GetWorldRotation(), faceCameraMode_), node_->GetWorldScale());
         worldBoundingBoxDirty_ = true;
     }
     
     for (unsigned i = 0; i < batches_.Size(); ++i)
     {
         batches_[i].distance_ = distance_;
-        batches_[i].worldTransform_ = faceCamera_ ? &customWorldTransform_ : &worldTransform;
+        batches_[i].worldTransform_ = faceCameraMode_ != FC_NONE ? &customWorldTransform_ : &node_->GetWorldTransform();
     }
 }
 
@@ -283,22 +282,17 @@ void Text3D::SetOpacity(float opacity)
     MarkTextDirty();
 }
 
-void Text3D::SetFaceCamera(bool enable)
+void Text3D::SetFaceCameraMode(FaceCameraMode mode)
 {
-    if (enable != faceCamera_)
+    if (mode != faceCameraMode_)
     {
-        faceCamera_ = enable;
+        faceCameraMode_ = mode;
         
         // Bounding box must be recalculated
         OnMarkedDirty(node_);
     }
 }
 
-void Text3D::SetFaceCameraAxes(const Vector3& axes)
-{
-    faceCameraAxes_ = axes;
-}
-
 Material* Text3D::GetMaterial() const
 {
     return material_;
@@ -418,7 +412,7 @@ void Text3D::OnWorldBoundingBoxUpdate()
         UpdateTextBatches();
     
     // In face camera mode, use the last camera rotation to build the world bounding box
-    worldBoundingBox_ = boundingBox_.Transformed(faceCamera_ ? Matrix3x4(node_->GetWorldPosition(),
+    worldBoundingBox_ = boundingBox_.Transformed(faceCameraMode_ != FC_NONE ? Matrix3x4(node_->GetWorldPosition(),
         customWorldTransform_.Rotation(), node_->GetWorldScale()) : node_->GetWorldTransform());
 }
 

+ 6 - 12
Source/Engine/UI/Text3D.h

@@ -88,10 +88,8 @@ public:
     void SetColor(Corner corner, const Color& color);
     /// Set opacity.
     void SetOpacity(float opacity);
-    /// Set whether to face the camera automatically.
-    void SetFaceCamera(bool enable);
-    /// Set on which axes the text faces the camera. Default all axes (1,1,1). Negative axes imply facing away.
-    void SetFaceCameraAxes(const Vector3& axes);
+    /// Set how the text should rotate in relation to the camera. Default is to not rotate (FC_NONE.)
+    void SetFaceCameraMode(FaceCameraMode mode);
     
     /// Return font.
     Font* GetFont() const;
@@ -135,10 +133,8 @@ public:
     const Color& GetColor(Corner corner) const;
     /// Return opacity.
     float GetOpacity() const;
-    /// Return whether faces the camera automatically.
-    bool GetFaceCamera() const { return faceCamera_; }
-    /// Return on which coordinate axes camera facing is done.
-    const Vector3& GetFaceCameraAxes() const { return faceCameraAxes_; }
+    /// Return how the text rotates in relation to the camera.
+    FaceCameraMode GetFaceCameraMode() const { return faceCameraMode_; }
     
     /// Set font attribute.
     void SetFontAttr(ResourceRef value);
@@ -181,10 +177,8 @@ private:
     PODVector<float> uiVertexData_;
     /// Custom world transform for facing the camera automatically.
     Matrix3x4 customWorldTransform_;
-    /// Coordinate axes on which camera facing is done.
-    Vector3 faceCameraAxes_;
-    /// Face camera flag.
-    bool faceCamera_;
+    /// Text rotation mode in relation to the camera.
+    FaceCameraMode faceCameraMode_;
     /// Text needs update flag.
     bool textDirty_;
     /// Geometry dirty flag.