Browse Source

Removed assumptions of root node's identity transform.
Re-added the root node transform attributes so they can be edited, though this is not recommended.
Fixed needless creation of almost similar collision meshes caused by floating point inaccuracy.
Fixed bug where parenting a node back to the root node would not be replicated correctly on the network.

Lasse Öörni 14 years ago
parent
commit
0298cd3e00

+ 6 - 2
Docs/GettingStarted.dox

@@ -493,6 +493,8 @@ Now you should be ready to compile HelloWorld.cpp. The resulting executable will
 
 
 The Urho3D scene editor is a script application that can be run with the Urho3D main executable. To start, execute either of these commands: (in the Bin directory) Editor.bat or Urho3D.exe Scripts/Editor.as
 The Urho3D scene editor is a script application that can be run with the Urho3D main executable. To start, execute either of these commands: (in the Bin directory) Editor.bat or Urho3D.exe Scripts/Editor.as
 
 
+Hint: to get some content to look at, run the TestScene example, and press F5. This saves a scene file called Scene.xml into the Data subdirectory, which can be loaded in the editor.
+
 \section EditorInstructions_Controls Controls
 \section EditorInstructions_Controls Controls
 
 
 \verbatim
 \verbatim
@@ -541,12 +543,14 @@ New scene nodes and components are created with the buttons at the bottom of the
 
 
 To reparent scene nodes, drag and drop them onto the new parent scene node in the scene hierarchy window. Reparenting should retain the effective world transform, so check afterwards from the component window that the local transform is what you expect it to be. Components can not be dragged between nodes, but can be duplicated with cut/copy/paste operations.
 To reparent scene nodes, drag and drop them onto the new parent scene node in the scene hierarchy window. Reparenting should retain the effective world transform, so check afterwards from the component window that the local transform is what you expect it to be. Components can not be dragged between nodes, but can be duplicated with cut/copy/paste operations.
 
 
-Currently, when you edit for example a material or texture, you need to manually reload scene resources (Ctrl+R) to make the changes visible.
+Though Urho3D supports setting a non-identity transform on the root node (scene), it is still best to leave it at identity (position 0, 0, 0, rotation 0, 0, 0, scale 1, 1, 1.)
 
 
-To create a user variable into the current node, or delete it, type its name into the edit field below the node attributes, and press New or Del buttons. The New button will prompt to choose the variable type.
+To create a user variable into the current node, or delete it, type the variable name into the edit field below the node attributes, and press New or Del buttons next to it. The New button will prompt to choose the variable type.
 
 
 While editing, you can execute script files using the "Run script" item in the %File menu. These are AngelScript files that are executed in immediate mode ie. you do not need to define a function. The editor's scene will be accessible to the script as the global property "scene."
 While editing, you can execute script files using the "Run script" item in the %File menu. These are AngelScript files that are executed in immediate mode ie. you do not need to define a function. The editor's scene will be accessible to the script as the global property "scene."
 
 
+Currently, when you edit for example a material or texture, you need to manually reload scene resources (Ctrl+R) to make the changes visible.
+
 \section EditorInstructions_Importing Importing
 \section EditorInstructions_Importing Importing
 
 
 The editor can import models or scenes from all the formats that the Open Asset Import Library supports, see http://assimp.sourceforge.net/main_features_formats.html
 The editor can import models or scenes from all the formats that the Open Asset Import Library supports, see http://assimp.sourceforge.net/main_features_formats.html

+ 10 - 2
Engine/Physics/CollisionShape.cpp

@@ -865,8 +865,13 @@ void CollisionShape::CreateGeometry()
     case SHAPE_TRIANGLEMESH:
     case SHAPE_TRIANGLEMESH:
     case SHAPE_CONVEXHULL:
     case SHAPE_CONVEXHULL:
         {
         {
+            // For mesh cache lookup purposes, quantize size to 3 decimals only. Otherwise floating point inaccuracy from world
+            // matrix multiplications and rotation/scale decomposing causes several slightly differing meshes to be created
+            char sizeText[CONVERSION_BUFFER_LENGTH];
+            sprintf(sizeText, "%.3f%.3f%.3f", size.x_, size.y_, size.z_);
+            
             // Check the geometry cache
             // Check the geometry cache
-            String id = model_->GetName() + "_" + String(size) + "_" + String(lodLevel_);
+            String id = model_->GetName() + "_" + String(sizeText) + "_" + String(lodLevel_);
             if (shapeType_ == SHAPE_CONVEXHULL)
             if (shapeType_ == SHAPE_CONVEXHULL)
                 id += "_" + String(thickness_);
                 id += "_" + String(thickness_);
             
             
@@ -890,8 +895,11 @@ void CollisionShape::CreateGeometry()
         
         
     case SHAPE_HEIGHTFIELD:
     case SHAPE_HEIGHTFIELD:
         {
         {
+            char sizeText[CONVERSION_BUFFER_LENGTH];
+            sprintf(sizeText, "%.3f%.3f%.3f", size.x_, size.y_, size.z_);
+            
             // Check the geometry cache
             // Check the geometry cache
-            String id = model_->GetName() + "_" + String(size) + "_" + String(numPoints_) + "_" + String(thickness_) + "_" +
+            String id = model_->GetName() + "_" + String(sizeText) + "_" + String(numPoints_) + "_" + String(thickness_) + "_" +
                 String(lodLevel_);
                 String(lodLevel_);
             
             
             Map<String, SharedPtr<HeightfieldData> >& cache = physicsWorld_->GetHeightfieldCache();
             Map<String, SharedPtr<HeightfieldData> >& cache = physicsWorld_->GetHeightfieldCache();

+ 3 - 4
Engine/Physics/RigidBody.cpp

@@ -423,10 +423,9 @@ void RigidBody::PostStep(float t, HashSet<RigidBody*>& processedBodies)
     processedBodies.Insert(this);
     processedBodies.Insert(this);
     inPostStep_ = true;
     inPostStep_ = true;
     
     
-    // If the parent node has a rigid body, process it first. For now, treat node parented to the Scene as unparented
+    // If the parent node has a rigid body, process it first
     Node* parent = node_->GetParent();
     Node* parent = node_->GetParent();
-    bool hasParent = parent && parent != node_->GetScene();
-    if (hasParent)
+    if (parent)
     {
     {
         RigidBody* parentBody = parent->GetComponent<RigidBody>();
         RigidBody* parentBody = parent->GetComponent<RigidBody>();
         if (parentBody)
         if (parentBody)
@@ -439,7 +438,7 @@ void RigidBody::PostStep(float t, HashSet<RigidBody*>& processedBodies)
     // Apply the physics transform to rendering transform now
     // Apply the physics transform to rendering transform now
     const Vector3& currentPosition = *reinterpret_cast<const Vector3*>(dBodyGetPosition(body_));
     const Vector3& currentPosition = *reinterpret_cast<const Vector3*>(dBodyGetPosition(body_));
     const Quaternion& currentRotation = *reinterpret_cast<const Quaternion*>(dBodyGetQuaternion(body_));
     const Quaternion& currentRotation = *reinterpret_cast<const Quaternion*>(dBodyGetQuaternion(body_));
-    if (!hasParent)
+    if (!parent)
     {
     {
         // If node already has motion smoothing enabled, do not do substep interpolation
         // If node already has motion smoothing enabled, do not do substep interpolation
         if (!node_->IsSmoothed())
         if (!node_->IsSmoothed())

+ 9 - 8
Engine/Scene/Node.cpp

@@ -761,7 +761,10 @@ void Node::SetNetParentAttr(const PODVector<unsigned char>& value)
     MemoryBuffer buf(value);
     MemoryBuffer buf(value);
     // If nothing in the buffer, parent is the root node
     // If nothing in the buffer, parent is the root node
     if (buf.IsEof())
     if (buf.IsEof())
+    {
+        SetParent(scene);
         return;
         return;
+    }
     
     
     unsigned baseNodeID = buf.ReadNetID();
     unsigned baseNodeID = buf.ReadNetID();
     Node* baseNode = scene->GetNodeByID(baseNodeID);
     Node* baseNode = scene->GetNodeByID(baseNodeID);
@@ -771,18 +774,18 @@ void Node::SetNetParentAttr(const PODVector<unsigned char>& value)
         return;
         return;
     }
     }
     
     
-    // If buffer contains just an ID, the parent is replicated
+    // If buffer contains just an ID, the parent is replicated and we are done
     if (buf.IsEof())
     if (buf.IsEof())
-        baseNode->AddChild(this);
+        SetParent(baseNode);
     else
     else
     {
     {
         // Else the parent is local and we must find it recursively by name hash
         // Else the parent is local and we must find it recursively by name hash
         StringHash nameHash = buf.ReadStringHash();
         StringHash nameHash = buf.ReadStringHash();
-        Node* parent = baseNode->GetChild(nameHash, true);
-        if (!parent)
+        Node* parentNode = baseNode->GetChild(nameHash, true);
+        if (!parentNode)
             LOGWARNING("Failed to find parent node with name hash " + nameHash.ToString());
             LOGWARNING("Failed to find parent node with name hash " + nameHash.ToString());
         else
         else
-            parent->AddChild(this);
+            SetParent(parentNode);
     }
     }
 }
 }
 
 
@@ -974,9 +977,7 @@ Node* Node::CreateChild(unsigned id, CreateMode mode)
 
 
 void Node::UpdateWorldTransform() const
 void Node::UpdateWorldTransform() const
 {
 {
-    // For now, assume that the Scene has identity transform so that we skip one matrix multiply. However in the future
-    // we may want dynamic root nodes for large worlds
-    if (parent_ && parent_ != scene_)
+    if (parent_)
     {
     {
         if (parent_->dirty_)
         if (parent_->dirty_)
             parent_->UpdateWorldTransform();
             parent_->UpdateWorldTransform();

+ 8 - 4
Engine/Scene/Scene.cpp

@@ -75,14 +75,18 @@ void Scene::RegisterObject(Context* context)
     context->RegisterFactory<Scene>();
     context->RegisterFactory<Scene>();
     
     
     REF_ACCESSOR_ATTRIBUTE(Scene, VAR_STRING, "Name", GetName, SetName, String, String(), AM_DEFAULT);
     REF_ACCESSOR_ATTRIBUTE(Scene, VAR_STRING, "Name", GetName, SetName, String, String(), AM_DEFAULT);
-    ATTRIBUTE(Scene, VAR_FLOAT, "Smoothing Constant", smoothingConstant_, DEFAULT_SMOOTHING_CONSTANT, AM_DEFAULT);
-    ATTRIBUTE(Scene, VAR_FLOAT, "Snap Threshold", snapThreshold_, DEFAULT_SNAP_THRESHOLD, AM_DEFAULT);
-    ATTRIBUTE(Scene, VAR_VARIANTMAP, "Variables", vars_, VariantMap(), AM_FILE); // Network replication of vars uses custom data
+    REF_ACCESSOR_ATTRIBUTE(Scene, VAR_VECTOR3, "Position", GetPosition, SetPosition, Vector3, Vector3::ZERO, AM_DEFAULT | AM_LATESTDATA);
+    REF_ACCESSOR_ATTRIBUTE(Scene, VAR_QUATERNION, "Rotation", GetRotation, SetRotation, Quaternion, Quaternion::IDENTITY, AM_FILE);
+    REF_ACCESSOR_ATTRIBUTE(Scene, VAR_VECTOR3, "Scale", GetScale, SetScale, Vector3, Vector3::UNITY, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(Scene, VAR_FLOAT, "Smoothing Constant", GetSmoothingConstant, SetSmoothingConstant, float, DEFAULT_SMOOTHING_CONSTANT, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(Scene, VAR_FLOAT, "Snap Threshold", GetSnapThreshold, SetSnapThreshold, float, DEFAULT_SNAP_THRESHOLD, AM_DEFAULT);
     ATTRIBUTE(Scene, VAR_INT, "Next Replicated Node ID", replicatedNodeID_, FIRST_REPLICATED_ID, AM_FILE | AM_NOEDIT);
     ATTRIBUTE(Scene, VAR_INT, "Next Replicated Node ID", replicatedNodeID_, FIRST_REPLICATED_ID, AM_FILE | AM_NOEDIT);
     ATTRIBUTE(Scene, VAR_INT, "Next Replicated Component ID", replicatedComponentID_, FIRST_REPLICATED_ID, AM_FILE | AM_NOEDIT);
     ATTRIBUTE(Scene, VAR_INT, "Next Replicated Component ID", replicatedComponentID_, FIRST_REPLICATED_ID, AM_FILE | AM_NOEDIT);
     ATTRIBUTE(Scene, VAR_INT, "Next Local Node ID", localNodeID_, FIRST_LOCAL_ID, AM_FILE | AM_NOEDIT);
     ATTRIBUTE(Scene, VAR_INT, "Next Local Node ID", localNodeID_, FIRST_LOCAL_ID, AM_FILE | AM_NOEDIT);
     ATTRIBUTE(Scene, VAR_INT, "Next Local Component ID", localComponentID_, FIRST_LOCAL_ID, AM_FILE | AM_NOEDIT);
     ATTRIBUTE(Scene, VAR_INT, "Next Local Component ID", localComponentID_, FIRST_LOCAL_ID, AM_FILE | AM_NOEDIT);
-    ACCESSOR_ATTRIBUTE(Scene, VAR_STRING, "User Variable Names", GetVarNamesAttr, SetVarNamesAttr, String, String(), AM_FILE | AM_NOEDIT);
+    ATTRIBUTE(Scene, VAR_VARIANTMAP, "Variables", vars_, VariantMap(), AM_FILE); // Network replication of vars uses custom data
+    ACCESSOR_ATTRIBUTE(Scene, VAR_STRING, "Variable Names", GetVarNamesAttr, SetVarNamesAttr, String, String(), AM_FILE | AM_NOEDIT);
+    REF_ACCESSOR_ATTRIBUTE(Scene, VAR_BUFFER, "Network Rotation", GetNetRotationAttr, SetNetRotationAttr, PODVector<unsigned char>, PODVector<unsigned char>(), AM_NET | AM_LATESTDATA | AM_NOEDIT);
 }
 }
 
 
 bool Scene::Load(Deserializer& source)
 bool Scene::Load(Deserializer& source)