Переглянути джерело

Exposed StaticModelGroup to script. Ported HugeObjectCount example group mode switching to script versions.

Lasse Öörni 12 роки тому
батько
коміт
1cd73e46fd

+ 1 - 1
Bin/Data/LuaScripts/04_StaticScene.lua

@@ -95,7 +95,7 @@ function CreateInstructions()
 
     -- Position the text relative to the screen center
     instructionText.horizontalAlignment = HA_CENTER
-    instructionText.verticalAlignment= VA_CENTER
+    instructionText.verticalAlignment = VA_CENTER
     instructionText:SetPosition(0, ui.root.height / 4)
 end
 

+ 1 - 1
Bin/Data/LuaScripts/05_AnimatingScene.lua

@@ -94,7 +94,7 @@ function CreateInstructions()
 
     -- Position the text relative to the screen center
     instructionText.horizontalAlignment = HA_CENTER
-    instructionText.verticalAlignment= VA_CENTER
+    instructionText.verticalAlignment = VA_CENTER
     instructionText:SetPosition(0, ui.root.height / 4)
 end
 

+ 65 - 20
Bin/Data/LuaScripts/20_HugeObjectCount.lua

@@ -3,6 +3,7 @@
 --     - Creating a scene with 250 x 250 simple objects;
 --     - Competing with http://yosoygames.com.ar/wp/2013/07/ogre-2-0-is-up-to-3x-faster/ :);
 --     - Allowing examination of performance hotspots in the rendering code;
+--     - Optionally speeding up rendering by grouping the objects using StaticModelGroup component;
 
 require "LuaScripts/Utilities/Sample"
 
@@ -12,6 +13,7 @@ local boxNodes = {}
 local yaw = 0.0
 local pitch = 0.0
 local animate = false
+local useGroups = false
 
 local context = GetContext()
 
@@ -38,7 +40,12 @@ function Start()
 end
 
 function CreateScene()
-    scene_ = Scene(context)
+    if scene_ == nil then
+        scene_ = Scene(context)
+    else
+        scene_:Clear()
+        boxNodes = {}
+    end
 
     -- Create the Octree component to the scene so that drawable objects can be rendered. Use default volume
     -- (-1000, -1000, -1000) to (1000, 1000, 1000)
@@ -54,42 +61,74 @@ function CreateScene()
     
     -- Create a directional light
     local lightNode = scene_:CreateChild("DirectionalLight")
-    lightNode.direction = Vector3(0.5, -1.0, 0.5) -- The direction vector does not need to be normalized
+    lightNode.direction = Vector3(-0.6, -1.0, -0.8) -- The direction vector does not need to be normalized
     local light = lightNode:CreateComponent("Light")
     light.lightType = LIGHT_DIRECTIONAL
-    light.color = Color(0.7, 0.35, 0.0)
-
-    -- Create box StaticModels in the scene
-    for y = -125, 125 do
-        for x = -125, 125 do
-            local boxNode = scene_:CreateChild("Box")
-            boxNode.position = Vector3(x * 0.3, 0.0, y * 0.3)
-            boxNode:SetScale(0.25)
-            local boxObject = boxNode:CreateComponent("StaticModel")
-            boxObject.model = cache:GetResource("Model", "Models/Box.mdl")
-            table.insert(boxNodes, boxNode)
+
+
+    if not useGroups then
+        light.color = Color(0.7, 0.35, 0.0)
+
+        -- Create individual box StaticModels in the scene
+        for y = -125, 125 do
+            for x = -125, 125 do
+                local boxNode = scene_:CreateChild("Box")
+                boxNode.position = Vector3(x * 0.3, 0.0, y * 0.3)
+                boxNode:SetScale(0.25)
+                local boxObject = boxNode:CreateComponent("StaticModel")
+                boxObject.model = cache:GetResource("Model", "Models/Box.mdl")
+                table.insert(boxNodes, boxNode)
+            end
+        end
+    else
+        light.color = Color(0.6, 0.6, 0.6);
+        light.specularIntensity = 1.5;
+
+        -- Create StaticModelGroups in the scene
+        local lastGroup = nil
+
+        for y = -125, 125 do
+            for x = -125, 125 do
+                -- Create new group if no group yet, or the group has already "enough" objects. The tradeoff is between culling
+                -- accuracy and the amount of CPU processing needed for all the objects. Note that the group's own transform
+                -- does not matter, and it does not render anything if instance nodes are not added to it
+                if lastGroup == nil or lastGroup.numInstanceNodes >= 25 * 25 then
+                    local boxGroupNode = scene_:CreateChild("BoxGroup")
+                    lastGroup = boxGroupNode:CreateComponent("StaticModelGroup")
+                    lastGroup.model = cache:GetResource("Model", "Models/Box.mdl")
+                end
+
+                local boxNode = scene_:CreateChild("Box");
+                boxNode.position = Vector3(x * 0.3, 0.0, y * 0.3)
+                boxNode:SetScale(0.25)
+                table.insert(boxNodes, boxNode)
+                lastGroup:AddInstanceNode(boxNode);
+            end
         end
     end
 
-    -- Create the camera
-    cameraNode = scene_:CreateChild("Camera")
-    cameraNode.position = Vector3(0.0, 10.0, -100.0)
-    local camera = cameraNode:CreateComponent("Camera")
-    camera.farClip = 300.0
+    -- Create the camera. Create it outside the scene so that we can clear the whole scene without affecting it
+    if cameraNode == nil then
+        cameraNode = Node(context)
+        cameraNode.position = Vector3(0.0, 10.0, -100.0)
+        local camera = cameraNode:CreateComponent("Camera")
+        camera.farClip = 300.0
+    end
 end
 
 function CreateInstructions()
     -- Construct new Text object, set string to display and font to use
     local instructionText = ui.root:CreateChild("Text")
     instructionText:SetText("Use WASD keys and mouse to move\n"..
-        "Space to toggle animation")
+        "Space to toggle animation\n"..
+        "G to toggle object group optimization")
     instructionText:SetFont(cache:GetResource("Font", "Fonts/Anonymous Pro.ttf"), 15)
     -- The text has multiple rows. Center them in relation to each other
     instructionText.textAlignment = HA_CENTER
     
     -- Position the text relative to the screen center
     instructionText.horizontalAlignment = HA_CENTER
-    instructionText.verticalAlignment= VA_CENTER
+    instructionText.verticalAlignment = VA_CENTER
     instructionText:SetPosition(0, ui.root.height / 4)
 end
 
@@ -157,6 +196,12 @@ function HandleUpdate(eventType, eventData)
         animate = not animate
     end
 
+    -- Toggle grouped / ungrouped mode
+    if input:GetKeyPress(KEY_G) then
+        useGroups = not useGroups
+        CreateScene()
+    end
+
     -- Move the camera, scale movement with time step
     MoveCamera(timeStep)
     

+ 1 - 1
Bin/Data/Scripts/04_StaticScene.as

@@ -92,7 +92,7 @@ void CreateInstructions()
 
     // Position the text relative to the screen center
     instructionText.horizontalAlignment = HA_CENTER;
-    instructionText.verticalAlignment= VA_CENTER;
+    instructionText.verticalAlignment = VA_CENTER;
     instructionText.SetPosition(0, ui.root.height / 4);
 }
 

+ 1 - 1
Bin/Data/Scripts/05_AnimatingScene.as

@@ -94,7 +94,7 @@ void CreateInstructions()
 
     // Position the text relative to the screen center
     instructionText.horizontalAlignment = HA_CENTER;
-    instructionText.verticalAlignment= VA_CENTER;
+    instructionText.verticalAlignment = VA_CENTER;
     instructionText.SetPosition(0, ui.root.height / 4);
 }
 

+ 75 - 22
Bin/Data/Scripts/20_HugeObjectCount.as

@@ -3,6 +3,7 @@
 //     - Creating a scene with 250 x 250 simple objects;
 //     - Competing with http://yosoygames.com.ar/wp/2013/07/ogre-2-0-is-up-to-3x-faster/ :)
 //     - Allowing examination of performance hotspots in the rendering code;
+//     - Optionally speeding up rendering by grouping the objects using StaticModelGroup component;
 
 #include "Scripts/Utilities/Sample.as"
 
@@ -12,6 +13,7 @@ Array<Node@> boxNodes;
 float yaw = 0.0f;
 float pitch = 0.0f;
 bool animate = false;
+bool useGroups = false;
 
 void Start()
 {
@@ -33,7 +35,13 @@ void Start()
 
 void CreateScene()
 {
-    scene_ = Scene();
+    if (scene_ is null)
+        scene_ = Scene();
+    else
+    {
+        scene_.Clear();
+        boxNodes.Clear();
+    }
 
     // Create the Octree component to the scene so that drawable objects can be rendered. Use default volume
     // (-1000, -1000, -1000) to (1000, 1000, 1000)
@@ -46,49 +54,87 @@ void CreateScene()
     zone.fogColor = Color(0.2f, 0.2f, 0.2f);
     zone.fogStart = 200.0f;
     zone.fogEnd = 300.0f;
-    
+
     // Create a directional light
     Node@ lightNode = scene_.CreateChild("DirectionalLight");
-    lightNode.direction = Vector3(0.5f, -1.0f, 0.5f); // The direction vector does not need to be normalized
+    lightNode.direction = Vector3(-0.6f, -1.0f, -0.8f); // The direction vector does not need to be normalized
     Light@ light = lightNode.CreateComponent("Light");
     light.lightType = LIGHT_DIRECTIONAL;
-    light.color = Color(0.7f, 0.35f, 0.0f);
 
-    // Create box StaticModels in the scene
-    for (int y = -125; y < 125; ++y)
+    if (!useGroups)
+    {
+        light.color = Color(0.7f, 0.35f, 0.0f);
+
+        // Create individual box StaticModels in the scene
+        for (int y = -125; y < 125; ++y)
+        {
+            for (int x = -125; x < 125; ++x)
+            {
+                Node@ boxNode = scene_.CreateChild("Box");
+                boxNode.position = Vector3(x * 0.3f, 0.0f, y * 0.3f);
+                boxNode.SetScale(0.25f);
+                StaticModel@ boxObject = boxNode.CreateComponent("StaticModel");
+                boxObject.model = cache.GetResource("Model", "Models/Box.mdl");
+                boxNodes.Push(boxNode);
+            }
+        }
+    }
+    else
     {
-        for (int x = -125; x < 125; ++x)
+        light.color = Color(0.6f, 0.6f, 0.6f);
+        light.specularIntensity = 1.5f;
+
+        // Create StaticModelGroups in the scene
+        StaticModelGroup@ lastGroup;
+
+        for (int y = -125; y < 125; ++y)
         {
-            Node@ boxNode = scene_.CreateChild("Box");
-            boxNode.position = Vector3(x * 0.3f, 0.0f, y * 0.3f);
-            boxNode.SetScale(0.25f);
-            StaticModel@ boxObject = boxNode.CreateComponent("StaticModel");
-            boxObject.model = cache.GetResource("Model", "Models/Box.mdl");
-            boxNodes.Push(boxNode);
+            for (int x = -125; x < 125; ++x)
+            {
+                // Create new group if no group yet, or the group has already "enough" objects. The tradeoff is between culling
+                // accuracy and the amount of CPU processing needed for all the objects. Note that the group's own transform
+                // does not matter, and it does not render anything if instance nodes are not added to it
+                if (lastGroup is null || lastGroup.numInstanceNodes >= 25 * 25)
+                {
+                    Node@ boxGroupNode = scene_.CreateChild("BoxGroup");
+                    lastGroup = boxGroupNode.CreateComponent("StaticModelGroup");
+                    lastGroup.model = cache.GetResource("Model", "Models/Box.mdl");
+                }
+
+                Node@ boxNode = scene_.CreateChild("Box");
+                boxNode.position = Vector3(x * 0.3f, 0.0f, y * 0.3f);
+                boxNode.SetScale(0.25f);
+                boxNodes.Push(boxNode);
+                lastGroup.AddInstanceNode(boxNode);
+            }
         }
     }
 
-    // Create the camera
-    cameraNode = scene_.CreateChild("Camera");
-    cameraNode.position = Vector3(0.0f, 10.0f, -100.0f);
-    Camera@ camera = cameraNode.CreateComponent("Camera");
-    camera.farClip = 300.0f;
+    // Create the camera. Create it outside the scene so that we can clear the whole scene without affecting it
+    if (cameraNode is null)
+    {
+        cameraNode = Node("Camera");
+        cameraNode.position = Vector3(0.0f, 10.0f, -100.0f);
+        Camera@ camera = cameraNode.CreateComponent("Camera");
+        camera.farClip = 300.0f;
+    }
 }
 
 void CreateInstructions()
 {
     // Construct new Text object, set string to display and font to use
     Text@ instructionText = ui.root.CreateChild("Text");
-    instructionText.text = 
+    instructionText.text =
         "Use WASD keys and mouse to move\n"
-        "Space to toggle animation";
+        "Space to toggle animation\n"
+        "G to toggle object group optimization";
     instructionText.SetFont(cache.GetResource("Font", "Fonts/Anonymous Pro.ttf"), 15);
     // The text has multiple rows. Center them in relation to each other
     instructionText.textAlignment = HA_CENTER;
-    
+
     // Position the text relative to the screen center
     instructionText.horizontalAlignment = HA_CENTER;
-    instructionText.verticalAlignment= VA_CENTER;
+    instructionText.verticalAlignment = VA_CENTER;
     instructionText.SetPosition(0, ui.root.height / 4);
 }
 
@@ -155,6 +201,13 @@ void HandleUpdate(StringHash eventType, VariantMap& eventData)
     if (input.keyPress[KEY_SPACE])
         animate = !animate;
 
+    // Toggle grouped / ungrouped mode
+    if (input.keyPress['G'])
+    {
+        useGroups = !useGroups;
+        CreateScene();
+    }
+    
     // Move the camera, scale movement with time step
     MoveCamera(timeStep);
     

+ 12 - 0
Docs/LuaScriptAPI.dox

@@ -1982,6 +1982,18 @@ Properties:<br>
 - unsigned numGeometries (readonly)
 - unsigned occlusionLodLevel
 
+StaticModelGroup : StaticModel
+
+Methods:<br>
+- void AddInstanceNode(Node* node)
+- void RemoveInstanceNode(Node* node);
+- void RemoveAllInstanceNodes()
+- unsigned GetNumInstanceNodes() const
+- Node* GetInstanceNode(unsigned index) const
+
+Properties:<br>
+- unsigned numInstanceNodes (readonly)
+
 Pass : RefCounted
 
 Methods:<br>

+ 60 - 0
Docs/ScriptAPI.dox

@@ -2436,6 +2436,66 @@ Properties:<br>
 - uint occlusionLodLevel
 
 
+StaticModelGroup
+
+Methods:<br>
+- void SendEvent(const String&, VariantMap& arg1 = VariantMap ( ))
+- bool Load(File@, bool arg1 = false)
+- bool Save(File@) const
+- bool LoadXML(const XMLElement&, bool arg1 = false)
+- bool SaveXML(XMLElement&) const
+- void ApplyAttributes()
+- bool SetAttribute(const String&, const Variant&)
+- void ResetToDefault()
+- void RemoveInstanceDefault()
+- Variant GetAttribute(const String&) const
+- Variant GetAttributeDefault(const String&) const
+- void Remove()
+- void MarkNetworkUpdate() const
+- void DrawDebugGeometry(DebugRenderer@, bool)
+- void AddInstanceNode(Node@)
+- void RemoveInstanceNode(Node@)
+- void RemoveAllInstanceNodes()
+
+Properties:<br>
+- int refs (readonly)
+- int weakRefs (readonly)
+- ShortStringHash type (readonly)
+- String typeName (readonly)
+- String category (readonly)
+- uint numAttributes (readonly)
+- Variant[] attributes
+- Variant[] attributeDefaults (readonly)
+- AttributeInfo[] attributeInfos (readonly)
+- bool temporary
+- bool enabled
+- bool enabledEffective (readonly)
+- uint id (readonly)
+- Node@ node (readonly)
+- bool inView (readonly)
+- bool castShadows
+- bool occluder
+- bool occludee
+- float drawDistance
+- float shadowDistance
+- float lodBias
+- uint viewMask
+- uint lightMask
+- uint shadowMask
+- uint zoneMask
+- uint maxLights
+- BoundingBox boundingBox (readonly)
+- BoundingBox worldBoundingBox (readonly)
+- Model@ model
+- Material@ material (writeonly)
+- Material@[] materials
+- uint numGeometries (readonly)
+- Zone@ zone (readonly)
+- uint occlusionLodLevel
+- uint numInstanceNodes (readonly)
+- Node@[] instanceNodes (readonly)
+
+
 Skybox
 
 Methods:<br>

+ 14 - 0
Source/Engine/Script/GraphicsAPI.cpp

@@ -38,6 +38,7 @@
 #include "RenderPath.h"
 #include "Scene.h"
 #include "SmoothedTransform.h"
+#include "StaticModelGroup.h"
 #include "Technique.h"
 #include "Terrain.h"
 #include "TerrainPatch.h"
@@ -817,6 +818,18 @@ static void RegisterStaticModel(asIScriptEngine* engine)
     engine->RegisterObjectMethod("StaticModel", "uint get_occlusionLodLevel() const", asMETHOD(StaticModel, GetOcclusionLodLevel), asCALL_THISCALL);
 }
 
+static void RegisterStaticModelGroup(asIScriptEngine* engine)
+{
+    RegisterStaticModel<StaticModelGroup>(engine, "StaticModelGroup", true);
+    engine->RegisterObjectMethod("StaticModelGroup", "void set_occlusionLodLevel(uint) const", asMETHOD(StaticModelGroup, SetOcclusionLodLevel), asCALL_THISCALL);
+    engine->RegisterObjectMethod("StaticModelGroup", "uint get_occlusionLodLevel() const", asMETHOD(StaticModelGroup, GetOcclusionLodLevel), asCALL_THISCALL);
+    engine->RegisterObjectMethod("StaticModelGroup", "void AddInstanceNode(Node@+)", asMETHOD(StaticModelGroup, AddInstanceNode), asCALL_THISCALL);
+    engine->RegisterObjectMethod("StaticModelGroup", "void RemoveInstanceNode(Node@+)", asMETHOD(StaticModelGroup, RemoveInstanceNode), asCALL_THISCALL);
+    engine->RegisterObjectMethod("StaticModelGroup", "void RemoveAllInstanceNodes()", asMETHOD(StaticModelGroup, RemoveAllInstanceNodes), asCALL_THISCALL);
+    engine->RegisterObjectMethod("StaticModelGroup", "uint get_numInstanceNodes() const", asMETHOD(StaticModelGroup, GetNumInstanceNodes), asCALL_THISCALL);
+    engine->RegisterObjectMethod("StaticModelGroup", "Node@+ get_instanceNodes(uint) const", asMETHOD(StaticModelGroup, GetInstanceNode), asCALL_THISCALL);
+}
+
 static void RegisterSkybox(asIScriptEngine* engine)
 {
     RegisterStaticModel<Skybox>(engine, "Skybox", true);
@@ -1438,6 +1451,7 @@ void RegisterGraphicsAPI(asIScriptEngine* engine)
     RegisterLight(engine);
     RegisterZone(engine);
     RegisterStaticModel(engine);
+    RegisterStaticModelGroup(engine);
     RegisterSkybox(engine);
     RegisterAnimatedModel(engine);
     RegisterAnimationController(engine);

+ 13 - 0
Source/Extras/LuaScript/pkgs/Graphics/StaticModelGroup.pkg

@@ -0,0 +1,13 @@
+$#include "StaticModelGroup.h"
+
+class StaticModelGroup : public StaticModel
+{
+    void AddInstanceNode(Node* node);
+    void RemoveInstanceNode(Node* node);
+    void RemoveAllInstanceNodes();
+
+    unsigned GetNumInstanceNodes() const;
+    Node* GetInstanceNode(unsigned index) const;
+    
+    tolua_readonly tolua_property__get_set unsigned numInstanceNodes;
+};

+ 1 - 0
Source/Extras/LuaScript/pkgs/GraphicsLuaAPI.pkg

@@ -21,6 +21,7 @@ $pfile "Graphics/RenderSurface.pkg"
 $pfile "Graphics/Skeleton.pkg"
 $pfile "Graphics/Skybox.pkg"
 $pfile "Graphics/StaticModel.pkg"
+$pfile "Graphics/StaticModelGroup.pkg"
 $pfile "Graphics/Technique.pkg"
 $pfile "Graphics/Terrain.pkg"
 $pfile "Graphics/TerrainPatch.pkg"

+ 2 - 2
Source/Samples/20_HugeObjectCount/HugeObjectCount.cpp

@@ -134,7 +134,7 @@ void HugeObjectCount::CreateScene()
                 // Create new group if no group yet, or the group has already "enough" objects. The tradeoff is between culling
                 // accuracy and the amount of CPU processing needed for all the objects. Note that the group's own transform
                 // does not matter, and it does not render anything if instance nodes are not added to it
-                if (!lastGroup || lastGroup->GetNumInstanceNodes() >= 25* 25)
+                if (!lastGroup || lastGroup->GetNumInstanceNodes() >= 25 * 25)
                 {
                     Node* boxGroupNode = scene_->CreateChild("BoxGroup");
                     lastGroup = boxGroupNode->CreateComponent<StaticModelGroup>();
@@ -170,7 +170,7 @@ void HugeObjectCount::CreateInstructions()
     instructionText->SetText(
         "Use WASD keys and mouse to move\n"
         "Space to toggle animation\n"
-        "G to toggle object group optimization\n"
+        "G to toggle object group optimization"
     );
     instructionText->SetFont(cache->GetResource<Font>("Fonts/Anonymous Pro.ttf"), 15);
     // The text has multiple rows. Center them in relation to each other

+ 1 - 0
Source/Samples/20_HugeObjectCount/HugeObjectCount.h

@@ -38,6 +38,7 @@ class Scene;
 ///     - Competing with http://yosoygames.com.ar/wp/2013/07/ogre-2-0-is-up-to-3x-faster/ :)
 ///     - Allowing examination of performance hotspots in the rendering code;
 ///     - Using the profiler to measure the time taken to animate the scene;
+///     - Optionally speeding up rendering by grouping the objects using StaticModelGroup component;
 class HugeObjectCount : public Sample
 {
     OBJECT(HugeObjectCount);