Explorar el Código

Gizmo improvements.
Reduced node transform edit related code duplication in the editor.
Exposed Plane class to script.

Lasse Öörni hace 14 años
padre
commit
0e6b9508b9

+ 175 - 48
Bin/Data/Scripts/Editor/EditorGizmo.as

@@ -27,17 +27,29 @@ class GizmoAxis
 
     void Update(Ray cameraRay, float scale, bool drag)
     {
-        lastT = t;
-        lastD = d;
-
         Vector3 closest = cameraRay.ClosestPoint(axisRay);
         Vector3 projected = axisRay.Project(closest);
         d = axisRay.Distance(closest);
         t = (projected - axisRay.origin).DotProduct(axisRay.direction);
 
+        // Determine the sign of d from a plane that goes through the camera position to the axis
+        Plane axisPlane(cameraNode.position, axisRay.origin, axisRay.origin + axisRay.direction);
+        if (axisPlane.Distance(closest) < 0.0)
+            d = -d;
+
         // Update selected status only when not dragging
         if (!drag)
-            selected = d < axisMaxD * scale && t >= -axisMaxD * scale && t <= axisMaxT * scale;
+        {
+            selected = Abs(d) < axisMaxD * scale && t >= -axisMaxD * scale && t <= axisMaxT * scale;
+            lastT = t;
+            lastD = d;
+        }
+    }
+    
+    void Moved()
+    {
+        lastT = t;
+        lastD = d;
     }
 }
 
@@ -124,6 +136,13 @@ void CalculateGizmoAxes()
     gizmoAxisZ.axisRay = Ray(gizmoNode.position, gizmoNode.rotation * Vector3(0, 0, 1));
 }
 
+void GizmoMoved()
+{
+    gizmoAxisX.Moved();
+    gizmoAxisY.Moved();
+    gizmoAxisZ.Moved();
+}
+
 void UseGizmo()
 {
     if (gizmo is null || !gizmo.visible)
@@ -150,7 +169,8 @@ void UseGizmo()
 
     if (drag)
     {
-        /// \todo Implement snapping
+        bool moved = false;
+
         if (moveMode == OBJ_MOVE)
         {
             Vector3 adjust(0, 0, 0);
@@ -161,19 +181,7 @@ void UseGizmo()
             if (gizmoAxisZ.selected)
                 adjust += gizmoAxisZ.axisRay.direction * (gizmoAxisZ.t - gizmoAxisZ.lastT);
 
-            if (adjust.length > M_EPSILON)
-            {
-                for (uint i = 0; i < editNodes.length; ++i)
-                {
-                    Node@ node = editNodes[i];
-                    Vector3 nodeAdjust = adjust;
-                    if (node.parent !is null)
-                        nodeAdjust = node.parent.WorldToLocal(Vector4(nodeAdjust, 0.0));
-                    node.position = node.position + nodeAdjust;
-                }
-
-                UpdateNodeAttributes();
-            }
+            moved = MoveNodes(adjust);
         }
         else if (moveMode == OBJ_ROTATE)
         {
@@ -181,31 +189,11 @@ void UseGizmo()
             if (gizmoAxisX.selected)
                 adjust.x = (gizmoAxisX.d - gizmoAxisX.lastD) * rotSensitivity / scale;
             if (gizmoAxisY.selected)
-                adjust.y = (gizmoAxisY.d - gizmoAxisY.lastD) * rotSensitivity / scale;
+                adjust.y = -(gizmoAxisY.d - gizmoAxisY.lastD) * rotSensitivity / scale;
             if (gizmoAxisZ.selected)
                 adjust.z = (gizmoAxisZ.d - gizmoAxisZ.lastD) * rotSensitivity / scale;
 
-            if (adjust.length > M_EPSILON)
-            {
-                for (uint i = 0; i < editNodes.length; ++i)
-                {
-                    Node@ node = editNodes[i];
-                    Quaternion rotQuat(adjust);
-                    if (axisMode == AXIS_WORLD || editNodes.length > 1)
-                    {
-                        Vector3 offset = node.worldPosition - gizmoAxisX.axisRay.origin;
-                        node.rotation = rotQuat * node.rotation;
-                        Vector3 newPosition = gizmoAxisX.axisRay.origin + rotQuat * offset;
-                        if (node.parent !is null)
-                            newPosition = node.parent.WorldToLocal(newPosition);
-                        node.position = newPosition;
-                    }
-                    else
-                        node.rotation = node.rotation * rotQuat;
-                }
-
-                UpdateNodeAttributes();
-            }
+            moved = RotateNodes(adjust);
         }
         else if (moveMode == OBJ_SCALE)
         {
@@ -217,28 +205,167 @@ void UseGizmo()
             if (gizmoAxisZ.selected)
                 adjust += Vector3(0, 0, 1) * (gizmoAxisZ.t - gizmoAxisZ.lastT);
 
-            // Special handling for uniform scale: use the X-axis movement only
+            // Special handling for uniform scale: use the unmodified X-axis movement only
             if (moveMode == OBJ_SCALE && gizmoAxisX.selected && gizmoAxisY.selected && gizmoAxisZ.selected)
             {
                 float x = gizmoAxisX.t - gizmoAxisX.lastT;
                 adjust = Vector3(x, x, x);
             }
 
-            if (adjust.length > M_EPSILON)
+            moved = ScaleNodes(adjust);
+        }
+        
+        if (moved)
+        {
+            GizmoMoved();
+            UpdateNodeAttributes();
+        }
+    }
+}
+
+bool IsGizmoSelected()
+{
+    return gizmoAxisX.selected || gizmoAxisY.selected || gizmoAxisZ.selected;
+}
+
+bool MoveNodes(Vector3 adjust)
+{
+    bool moved = false;
+
+    if (adjust.length > M_EPSILON)
+    {
+        for (uint i = 0; i < editNodes.length; ++i)
+        {
+            Node@ node = editNodes[i];
+            Vector3 nodeAdjust = adjust;
+            if (axisMode == AXIS_LOCAL)
+                nodeAdjust = node.worldRotation * nodeAdjust;
+
+            Vector3 worldPos = node.worldPosition;
+            Vector3 oldPos = node.position;
+
+            if (!moveSnap)
+                worldPos += nodeAdjust;
+            else
             {
-                for (uint i = 0; i < editNodes.length; ++i)
+                if (nodeAdjust.x != 0)
                 {
-                    Node@ node = editNodes[i];
-                    node.scale = node.scale + adjust;
+                    worldPos.x += nodeAdjust.x * moveStep;
+                    worldPos.x = Floor(worldPos.x / moveStep + 0.5) * moveStep;
                 }
+                if (nodeAdjust.y != 0)
+                {
+                    worldPos.y += nodeAdjust.y * moveStep;
+                    worldPos.y = Floor(worldPos.y / moveStep + 0.5) * moveStep;
+                }
+                if (nodeAdjust.z != 0)
+                {
+                    worldPos.z += nodeAdjust.z * moveStep;
+                    worldPos.z = Floor(worldPos.z / moveStep + 0.5) * moveStep;
+                }
+            }
+
+            if (node.parent is null)
+                node.position = worldPos;
+            else
+                node.position = node.parent.WorldToLocal(worldPos);
+
+            if (node.position != oldPos)
+                moved = true;
+        }
+    }
+    
+    return moved;
+}
 
-                UpdateNodeAttributes();
+bool RotateNodes(Vector3 adjust)
+{
+    bool moved = false;
+
+    if (rotateSnap)
+    {
+        adjust.x = Floor(adjust.x / rotateStep + 0.5) * rotateStep;
+        adjust.y = Floor(adjust.y / rotateStep + 0.5) * rotateStep;
+        adjust.z = Floor(adjust.z / rotateStep + 0.5) * rotateStep;
+    }
+
+    if (adjust.length > M_EPSILON)
+    {
+        moved = true;
+
+        for (uint i = 0; i < editNodes.length; ++i)
+        {
+            Node@ node = editNodes[i];
+            Quaternion rotQuat(adjust);
+            if (axisMode == AXIS_WORLD || editNodes.length > 1)
+            {
+                Vector3 offset = node.worldPosition - gizmoAxisX.axisRay.origin;
+                if (node.parent !is null && node.parent.worldRotation != Quaternion(1, 0, 0, 0))
+                    rotQuat = node.parent.worldRotation.Inverse() * rotQuat * node.parent.worldRotation;
+                node.rotation = rotQuat * node.rotation;
+                Vector3 newPosition = gizmoAxisX.axisRay.origin + rotQuat * offset;
+                if (node.parent !is null)
+                    newPosition = node.parent.WorldToLocal(newPosition);
+                node.position = newPosition;
+            }
+            else
+                node.rotation = node.rotation * rotQuat;
+                
+            // If snapping is on, perform a final snap on the euler angles to ensure we do not drift
+            if (rotateSnap)
+            {
+                Vector3 euler = node.rotation.eulerAngles;
+                euler.x = Floor(euler.x / rotateStep + 0.5) * rotateStep;
+                euler.y = Floor(euler.y / rotateStep + 0.5) * rotateStep;
+                euler.z = Floor(euler.z / rotateStep + 0.5) * rotateStep;
+                node.rotation = Quaternion(euler);
             }
         }
     }
+    
+    return moved;
 }
 
-bool IsGizmoSelected()
+bool ScaleNodes(Vector3 adjust)
 {
-    return gizmoAxisX.selected || gizmoAxisY.selected || gizmoAxisZ.selected;
+    bool moved = false;
+
+    if (adjust.length > M_EPSILON)
+    {
+        for (uint i = 0; i < editNodes.length; ++i)
+        {
+            Node@ node = editNodes[i];
+
+            Vector3 scale = node.scale;
+            Vector3 oldScale = scale;
+            
+            if (!scaleSnap)
+                scale += adjust;
+            else
+            {
+                if (adjust.x != 0)
+                {
+                    scale.x += adjust.x * scaleStep;
+                    scale.x = Floor(scale.x / scaleStep + 0.5) * scaleStep;
+                }
+                if (adjust.y != 0)
+                {
+                    scale.y += adjust.y * scaleStep;
+                    scale.y = Floor(scale.y / scaleStep + 0.5) * scaleStep;
+                }
+                if (adjust.z != 0)
+                {
+                    scale.z += adjust.z * scaleStep;
+                    scale.z = Floor(scale.z / scaleStep + 0.5) * scaleStep;
+                }
+            }
+
+            if (scale != oldScale)
+                moved = true;
+
+            node.scale = scale;
+        }
+    }
+    
+    return moved;
 }

+ 38 - 122
Bin/Data/Scripts/Editor/EditorView.as

@@ -189,7 +189,6 @@ void MoveCamera(float timeStep)
     // Move/rotate/scale object
     if (!editNodes.empty && ui.focusElement is null && input.keyDown[KEY_LCTRL])
     {
-        bool changed = false;
         Vector3 adjust(0, 0, 0);
         if (input.keyDown[KEY_UP])
             adjust.z = 1;
@@ -211,64 +210,38 @@ void MoveCamera(float timeStep)
                 adjust = Vector3(-1, -1, -1);
         }
 
-        if (adjust != Vector3(0, 0, 0))
-        {
-            adjust *= timeStep * 10;
-
-            if (input.keyDown[KEY_LSHIFT])
-                adjust *= cameraShiftSpeedMultiplier;
+        if (adjust == Vector3(0, 0, 0))
+            return;
+        
+        bool moved = false;
+        adjust *= timeStep * 10;
 
-            switch (moveMode)
+        switch (moveMode)
+        {
+        case OBJ_MOVE:
+            if (!moveSnap)
+                moved = MoveNodes(adjust * moveStep);
+            break;
+            
+        case OBJ_ROTATE:
+            if (!rotateSnap)
             {
-            case OBJ_MOVE:
-                if (!moveSnap)
-                {
-                    for (uint i = 0; i < editNodes.length; ++i)
-                    {
-                        Node@ node = editNodes[i];
-                        Vector3 nodeAdjust = adjust;
-                        if (axisMode == AXIS_LOCAL)
-                            nodeAdjust = node.worldRotation * nodeAdjust;
-                        if (node.parent !is null)
-                            nodeAdjust = node.parent.WorldToLocal(Vector4(nodeAdjust, 0.0));
-                        node.position = node.position + nodeAdjust * moveStep;
-                    }
-                    changed = true;
-                }
-                break;
-
-            case OBJ_ROTATE:
-                if (!rotateSnap)
-                {
-                    for (uint i = 0; i < editNodes.length; ++i)
-                    {
-                        Node@ node = editNodes[i];
-                        Vector3 euler = node.rotation.eulerAngles;
-                        euler.x += adjust.z * rotateStep;
-                        euler.y += adjust.x * rotateStep;
-                        euler.z += adjust.y * rotateStep;
-                        node.rotation = Quaternion(euler);
-                    }
-                    changed = true;
-                }
-                break;
-
-            case OBJ_SCALE:
-                if (!scaleSnap)
-                {
-                    for (uint i = 0; i < editNodes.length; ++i)
-                    {
-                        Node@ node = editNodes[i];
-                        node.scale = node.scale + adjust * scaleStep;
-                    }
-                    changed = true;
-                }
-                break;
+                Vector3 rotAdjust;
+                rotAdjust.x = adjust.z * rotateStep;
+                rotAdjust.y = adjust.x * rotateStep;
+                rotAdjust.z = adjust.y * rotateStep;
+                moved = RotateNodes(rotAdjust);
             }
+            break;
+
+        case OBJ_SCALE:
+            if (!scaleSnap)
+                moved = ScaleNodes(adjust * scaleStep);
+            break;
         }
 
-        if (changed)
-            UpdateAttributes(false);
+        if (moved)
+            UpdateNodeAttributes();
     }
 }
 
@@ -309,88 +282,31 @@ void SteppedObjectManipulation(int key)
     if (adjust == Vector3(0, 0, 0))
         return;
 
+    bool moved = false;
+
     switch (moveMode)
     {
     case OBJ_MOVE:
-        for (uint i = 0; i < editNodes.length; ++i)
-        {
-            Node@ node = editNodes[i];
-            Vector3 nodeAdjust = adjust;
-            if (axisMode == AXIS_LOCAL)
-                nodeAdjust = node.worldRotation * nodeAdjust;
-            if (node.parent !is null)
-                nodeAdjust = node.parent.WorldToLocal(Vector4(nodeAdjust, 0.0));
-
-            Vector3 pos = node.position;
-            if (adjust.x != 0)
-            {
-                pos.x += adjust.x * moveStep;
-                pos.x = Floor(pos.x / moveStep + 0.5) * moveStep;
-            }
-            if (adjust.y != 0)
-            {
-                pos.y += adjust.y * moveStep;
-                pos.y = Floor(pos.y / moveStep + 0.5) * moveStep;
-            }
-            if (adjust.z != 0)
-            {
-                pos.z += adjust.z * moveStep;
-                pos.z = Floor(pos.z / moveStep + 0.5) * moveStep;
-            }
-            node.position = pos;
-        }
+        moved = MoveNodes(adjust);
         break;
 
     case OBJ_ROTATE:
-        for (uint i = 0; i < editNodes.length; ++i)
         {
-            Node@ node = editNodes[i];
-            Vector3 rot = node.rotation.eulerAngles;
-            if (adjust.z != 0)
-            {
-                rot.x += adjust.z * rotateStep;
-                rot.x = Floor(rot.x / rotateStep + 0.5) * rotateStep;
-            }
-            if (adjust.x != 0)
-            {
-                rot.y += adjust.x * rotateStep;
-                rot.y = Floor(rot.y / rotateStep + 0.5) * rotateStep;
-            }
-            if (adjust.y != 0)
-            {
-                rot.z += adjust.y * rotateStep;
-                rot.z = Floor(rot.z / rotateStep + 0.5) * rotateStep;
-            }
-            node.rotation = Quaternion(rot);
+            Vector3 rotAdjust;
+            rotAdjust.x = adjust.z * rotateStep;
+            rotAdjust.y = adjust.x * rotateStep;
+            rotAdjust.z = adjust.y * rotateStep;
+            moved = RotateNodes(rotAdjust);
         }
         break;
 
     case OBJ_SCALE:
-        for (uint i = 0; i < editNodes.length; ++i)
-        {
-            Node@ node = editNodes[i];
-            Vector3 scale = node.scale;
-            if (adjust.x != 0)
-            {
-                scale.x += adjust.x * scaleStep;
-                scale.x = Floor(scale.x / scaleStep + 0.5) * scaleStep;
-            }
-            if (adjust.y != 0)
-            {
-                scale.y += adjust.y * scaleStep;
-                scale.y = Floor(scale.y / scaleStep + 0.5) * scaleStep;
-            }
-            if (adjust.z != 0)
-            {
-                scale.z += adjust.z * scaleStep;
-                scale.z = Floor(scale.z / scaleStep + 0.5) * scaleStep;
-            }
-            node.scale = scale;
-        }
+        moved = ScaleNodes(adjust * scaleStep);
         break;
     }
 
-    UpdateAttributes(false);
+    if (moved)
+        UpdateNodeAttributes();
 }
 
 

+ 15 - 3
Docs/ScriptAPI.dox

@@ -456,6 +456,19 @@ Properties:<br>
 - bool defined
 
 
+Plane
+
+Methods:<br>
+- void Define(const Vector3&, const Vector3&, const Vector3&)
+- void Define(const Vector3&, const Vector3&)
+- float Distance(const Vector3&) const
+
+Properties:<br>
+- Vector3 normal
+- Vector3 absNormal
+- float intercept
+
+
 Ray
 
 Methods:<br>
@@ -1993,9 +2006,8 @@ Methods:<br>
 - void Remove()
 - void Resize(const BoundingBox&, uint)
 - void DrawDebugGeometry(bool) const
-- void AddDrawable(Drawable@)
-- void AddUnculledDrawable(Drawable@)
-- void RemoveUnculledDrawable(Drawable@)
+- void AddManualDrawable(Drawable@, bool)
+- void RemoveManualDrawable(Drawable@)
 - RayQueryResult[]@ Raycast(const Ray&, RayQueryLevel arg1 = RAY_TRIANGLE, float arg2 = M_INFINITY, uint8 arg3 = DRAWABLE_ANY, uint arg4 = DEFAULT_VIEWMASK)
 - Node@[]@ GetDrawables(const Vector3&, uint8 arg1 = DRAWABLE_ANY, uint arg2 = DEFAULT_VIEWMASK)
 - Node@[]@ GetDrawables(const BoundingBox&, uint8 arg1 = DRAWABLE_ANY, uint arg2 = DEFAULT_VIEWMASK)

+ 36 - 0
Engine/Engine/MathAPI.cpp

@@ -390,6 +390,41 @@ static void RegisterQuaternion(asIScriptEngine* engine)
     engine->RegisterObjectProperty("Quaternion", "float z", offsetof(Quaternion, z_));
 }
 
+static void ConstructPlane(Plane* ptr)
+{
+    new(ptr) Plane();
+}
+
+static void ConstructPlaneCopy(const Plane& plane, Plane* ptr)
+{
+    new(ptr) Plane(plane);
+}
+
+static void ConstructPlaneInitVertices(const Vector3& v0, const Vector3& v1, const Vector3& v2, Ray* ptr)
+{
+    new(ptr) Plane(v0, v1, v2);
+}
+
+static void ConstructPlaneInitNormalPoint(const Vector3& normal, const Vector3& point, Ray* ptr)
+{
+    new(ptr) Plane(normal, point);
+}
+
+static void RegisterPlane(asIScriptEngine* engine)
+{
+    engine->RegisterObjectType("Plane", sizeof(Plane), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CAK);
+    engine->RegisterObjectBehaviour("Plane", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructPlane), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectBehaviour("Plane", asBEHAVE_CONSTRUCT, "void f(const Plane&in)", asFUNCTION(ConstructPlaneCopy), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectBehaviour("Plane", asBEHAVE_CONSTRUCT, "void f(const Vector3&in, const Vector3&in, const Vector3&in)", asFUNCTION(ConstructPlaneInitVertices), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectBehaviour("Plane", asBEHAVE_CONSTRUCT, "void f(const Vector3&in, const Vector3&in)", asFUNCTION(ConstructPlaneInitNormalPoint), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("Plane", "void Define(const Vector3&in, const Vector3&in, const Vector3&in)", asMETHODPR(Plane, Define, (const Vector3&, const Vector3&, const Vector3&), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Plane", "void Define(const Vector3&in, const Vector3&in)", asMETHODPR(Plane, Define, (const Vector3&, const Vector3&), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Plane", "float Distance(const Vector3&in) const", asMETHOD(Plane, Distance), asCALL_THISCALL);
+    engine->RegisterObjectProperty("Plane", "Vector3 normal", offsetof(Plane, normal_));
+    engine->RegisterObjectProperty("Plane", "Vector3 absNormal", offsetof(Plane, absNormal_));
+    engine->RegisterObjectProperty("Plane", "float intercept", offsetof(Plane, intercept_));
+}
+
 static void ConstructRay(Ray* ptr)
 {
     // Initialize to zero because performance is not critical
@@ -753,6 +788,7 @@ void RegisterMathAPI(asIScriptEngine* engine)
     RegisterQuaternion(engine);
     RegisterRect(engine);
     RegisterVolumes(engine);
+    RegisterPlane(engine);
     RegisterRay(engine);
     RegisterColor(engine);
     

+ 1 - 1
Engine/Math/Plane.h

@@ -72,7 +72,7 @@ public:
         intercept_ = normal_.DotProduct(point);
     }
     
-    /// Return distance to a point.
+    /// Return signed distance to a point.
     float Distance(const Vector3& point) const { return normal_.DotProduct(point) - intercept_; }
     
     /// Plane normal.