Browse Source

Fix terrain occlusion leaving holes in the occlusion geometry, and being over-aggressive with height reduction, which would result in poor occlusion. Allow to configure terrain number of LOD levels to be less than 4. Allow to configure the LOD level used for terrain occlusion (not recommended to be changed.) Closes #825.

Lasse Öörni 10 years ago
parent
commit
a737bbb671

+ 70 - 17
Source/Urho3D/Graphics/Terrain.cpp

@@ -89,6 +89,8 @@ Terrain::Terrain(Context* context) :
     patchSize_(DEFAULT_PATCH_SIZE),
     patchSize_(DEFAULT_PATCH_SIZE),
     lastPatchSize_(0),
     lastPatchSize_(0),
     numLodLevels_(1),
     numLodLevels_(1),
+    maxLodLevels_(MAX_LOD_LEVELS),
+    occlusionLodLevel_(M_MAX_UNSIGNED),
     smoothing_(false),
     smoothing_(false),
     visible_(true),
     visible_(true),
     castShadows_(false),
     castShadows_(false),
@@ -122,6 +124,7 @@ void Terrain::RegisterObject(Context* context)
         AM_DEFAULT);
         AM_DEFAULT);
     ATTRIBUTE("Vertex Spacing", Vector3, spacing_, DEFAULT_SPACING, AM_DEFAULT);
     ATTRIBUTE("Vertex Spacing", Vector3, spacing_, DEFAULT_SPACING, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE("Patch Size", GetPatchSize, SetPatchSizeAttr, int, DEFAULT_PATCH_SIZE, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE("Patch Size", GetPatchSize, SetPatchSizeAttr, int, DEFAULT_PATCH_SIZE, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE("Max LOD Levels", GetMaxLodLevels, SetMaxLodLevelsAttr, unsigned, MAX_LOD_LEVELS, AM_DEFAULT);
     ATTRIBUTE("Smooth Height Map", bool, smoothing_, false, AM_DEFAULT);
     ATTRIBUTE("Smooth Height Map", bool, smoothing_, false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE("Is Occluder", IsOccluder, SetOccluder, bool, false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE("Is Occluder", IsOccluder, SetOccluder, bool, false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE("Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE("Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
@@ -134,6 +137,7 @@ void Terrain::RegisterObject(Context* context)
     ACCESSOR_ATTRIBUTE("Light Mask", GetLightMask, SetLightMask, unsigned, DEFAULT_LIGHTMASK, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE("Light Mask", GetLightMask, SetLightMask, unsigned, DEFAULT_LIGHTMASK, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE("Shadow Mask", GetShadowMask, SetShadowMask, unsigned, DEFAULT_SHADOWMASK, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE("Shadow Mask", GetShadowMask, SetShadowMask, unsigned, DEFAULT_SHADOWMASK, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE("Zone Mask", GetZoneMask, SetZoneMask, unsigned, DEFAULT_ZONEMASK, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE("Zone Mask", GetZoneMask, SetZoneMask, unsigned, DEFAULT_ZONEMASK, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE("Occlusion LOD level", GetOcclusionLodLevel, SetOcclusionLodLevelAttr, unsigned, M_MAX_UNSIGNED, AM_DEFAULT);
 }
 }
 
 
 void Terrain::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
 void Terrain::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
@@ -187,6 +191,31 @@ void Terrain::SetSpacing(const Vector3& spacing)
     }
     }
 }
 }
 
 
+void Terrain::SetMaxLodLevels(unsigned levels)
+{
+    levels = Clamp((int)levels, 1, MAX_LOD_LEVELS);
+    if (levels != maxLodLevels_)
+    {
+        maxLodLevels_ = levels;
+        lastPatchSize_ = 0; // Force full recreate
+        
+        CreateGeometry();
+        MarkNetworkUpdate();
+    }
+}
+
+void Terrain::SetOcclusionLodLevel(unsigned level)
+{
+    if (level != occlusionLodLevel_)
+    {
+        occlusionLodLevel_ = level;
+        lastPatchSize_ = 0; // Force full recreate
+        
+        CreateGeometry();
+        MarkNetworkUpdate();
+    }
+}
+
 void Terrain::SetSmoothing(bool enable)
 void Terrain::SetSmoothing(bool enable)
 {
 {
     if (enable != smoothing_)
     if (enable != smoothing_)
@@ -468,7 +497,7 @@ void Terrain::CreatePatchGeometry(TerrainPatch* patch)
     VertexBuffer* vertexBuffer = patch->GetVertexBuffer();
     VertexBuffer* vertexBuffer = patch->GetVertexBuffer();
     Geometry* geometry = patch->GetGeometry();
     Geometry* geometry = patch->GetGeometry();
     Geometry* maxLodGeometry = patch->GetMaxLodGeometry();
     Geometry* maxLodGeometry = patch->GetMaxLodGeometry();
-    Geometry* minLodGeometry = patch->GetMinLodGeometry();
+    Geometry* occlusionGeometry = patch->GetOcclusionGeometry();
 
 
     if (vertexBuffer->GetVertexCount() != row * row)
     if (vertexBuffer->GetVertexCount() != row * row)
         vertexBuffer->SetSize(row * row, MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1 | MASK_TANGENT);
         vertexBuffer->SetSize(row * row, MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1 | MASK_TANGENT);
@@ -481,14 +510,15 @@ void Terrain::CreatePatchGeometry(TerrainPatch* patch)
     float* occlusionData = (float*)occlusionCpuVertexData.Get();
     float* occlusionData = (float*)occlusionCpuVertexData.Get();
     BoundingBox box;
     BoundingBox box;
 
 
+    unsigned occlusionLevel = occlusionLodLevel_;
+    if (occlusionLevel > numLodLevels_ - 1)
+        occlusionLevel = numLodLevels_ - 1;
+
     if (vertexData)
     if (vertexData)
     {
     {
         const IntVector2& coords = patch->GetCoordinates();
         const IntVector2& coords = patch->GetCoordinates();
-        int patchMinX = coords.x_ * patchSize_;
-        int patchMaxX = (coords.x_ + 1) * patchSize_;
-        int patchMinZ = coords.y_ * patchSize_;
-        int patchMaxZ = (coords.y_ + 1) * patchSize_;
-        int lodExpand = (1 << (numLodLevels_ - 1)) - 1;
+        int lodExpand = (1 << (occlusionLevel)) - 1;
+        int halfLodExpand = (1 << (occlusionLevel)) / 2;
         
         
         for (int z = 0; z <= patchSize_; ++z)
         for (int z = 0; z <= patchSize_; ++z)
         {
         {
@@ -508,14 +538,15 @@ void Terrain::CreatePatchGeometry(TerrainPatch* patch)
 
 
                 box.Merge(position);
                 box.Merge(position);
                 
                 
-                // For vertices that are part of the lowest LOD, calculate the minimum height in the neighborhood for occlusion
+                // For vertices that are part of the occlusion LOD, calculate the minimum height in the neighborhood
+                // to prevent false positive occlusion due to inaccuracy between occlusion LOD & visible LOD
                 float minHeight = position.y_;
                 float minHeight = position.y_;
-                if (lodExpand > 0 && (x & lodExpand) == 0 && (z & lodExpand) == 0)
+                if (halfLodExpand > 0 && (x & lodExpand) == 0 && (z & lodExpand) == 0)
                 {
                 {
-                    int minX = Max(xPos - lodExpand, patchMinX);
-                    int maxX = Min(xPos + lodExpand, patchMaxX);
-                    int minZ = Max(zPos - lodExpand, patchMinZ);
-                    int maxZ = Min(zPos + lodExpand, patchMaxZ);
+                    int minX = Max(xPos - halfLodExpand, 0);
+                    int maxX = Min(xPos + halfLodExpand, numVertices_.x_ - 1);
+                    int minZ = Max(zPos - halfLodExpand, 0);
+                    int maxZ = Min(zPos + halfLodExpand, numVertices_.y_ - 1);
                     for (int nZ = minZ; nZ <= maxZ; ++nZ)
                     for (int nZ = minZ; nZ <= maxZ; ++nZ)
                     {
                     {
                         for (int nX = minX; nX <= maxX; ++nX)
                         for (int nX = minX; nX <= maxX; ++nX)
@@ -554,7 +585,7 @@ void Terrain::CreatePatchGeometry(TerrainPatch* patch)
 
 
     if (drawRanges_.Size())
     if (drawRanges_.Size())
     {
     {
-        unsigned lastDrawRange = drawRanges_.Size() - 1;
+        unsigned occlusionDrawRange = occlusionLevel << 4;
 
 
         geometry->SetIndexBuffer(indexBuffer_);
         geometry->SetIndexBuffer(indexBuffer_);
         geometry->SetDrawRange(TRIANGLE_LIST, drawRanges_[0].first_, drawRanges_[0].second_, false);
         geometry->SetDrawRange(TRIANGLE_LIST, drawRanges_[0].first_, drawRanges_[0].second_, false);
@@ -562,9 +593,9 @@ void Terrain::CreatePatchGeometry(TerrainPatch* patch)
         maxLodGeometry->SetIndexBuffer(indexBuffer_);
         maxLodGeometry->SetIndexBuffer(indexBuffer_);
         maxLodGeometry->SetDrawRange(TRIANGLE_LIST, drawRanges_[0].first_, drawRanges_[0].second_, false);
         maxLodGeometry->SetDrawRange(TRIANGLE_LIST, drawRanges_[0].first_, drawRanges_[0].second_, false);
         maxLodGeometry->SetRawVertexData(cpuVertexData, sizeof(Vector3), MASK_POSITION);
         maxLodGeometry->SetRawVertexData(cpuVertexData, sizeof(Vector3), MASK_POSITION);
-        minLodGeometry->SetIndexBuffer(indexBuffer_);
-        minLodGeometry->SetDrawRange(TRIANGLE_LIST, drawRanges_[lastDrawRange].first_, drawRanges_[lastDrawRange].second_, false);
-        minLodGeometry->SetRawVertexData(occlusionCpuVertexData, sizeof(Vector3), MASK_POSITION);
+        occlusionGeometry->SetIndexBuffer(indexBuffer_);
+        occlusionGeometry->SetDrawRange(TRIANGLE_LIST, drawRanges_[occlusionDrawRange].first_, drawRanges_[occlusionDrawRange].second_, false);
+        occlusionGeometry->SetRawVertexData(occlusionCpuVertexData, sizeof(Vector3), MASK_POSITION);
     }
     }
 
 
     patch->ResetLod();
     patch->ResetLod();
@@ -623,6 +654,28 @@ void Terrain::SetPatchSizeAttr(int value)
     }
     }
 }
 }
 
 
+void Terrain::SetMaxLodLevelsAttr(unsigned value)
+{
+    value = Clamp((int)value, 1, MAX_LOD_LEVELS);
+    
+    if (value != maxLodLevels_)
+    {
+        maxLodLevels_ = value;
+        lastPatchSize_ = 0; // Force full recreate
+        recreateTerrain_ = true;
+    }
+}
+
+void Terrain::SetOcclusionLodLevelAttr(unsigned value)
+{
+    if (value != occlusionLodLevel_)
+    {
+        occlusionLodLevel_ = value;
+        lastPatchSize_ = 0; // Force full recreate
+        recreateTerrain_ = true;
+    }
+}
+
 ResourceRef Terrain::GetMaterialAttr() const
 ResourceRef Terrain::GetMaterialAttr() const
 {
 {
     return GetResourceRef(material_, Material::GetTypeStatic());
     return GetResourceRef(material_, Material::GetTypeStatic());
@@ -647,7 +700,7 @@ void Terrain::CreateGeometry()
     // Determine number of LOD levels
     // Determine number of LOD levels
     unsigned lodSize = (unsigned)patchSize_;
     unsigned lodSize = (unsigned)patchSize_;
     numLodLevels_ = 1;
     numLodLevels_ = 1;
-    while (lodSize > MIN_PATCH_SIZE && numLodLevels_ < MAX_LOD_LEVELS)
+    while (lodSize > MIN_PATCH_SIZE && numLodLevels_ < maxLodLevels_)
     {
     {
         lodSize >>= 1;
         lodSize >>= 1;
         ++numLodLevels_;
         ++numLodLevels_;

+ 19 - 1
Source/Urho3D/Graphics/Terrain.h

@@ -57,6 +57,10 @@ public:
     void SetPatchSize(int size);
     void SetPatchSize(int size);
     /// Set vertex (XZ) and height (Y) spacing.
     /// Set vertex (XZ) and height (Y) spacing.
     void SetSpacing(const Vector3& spacing);
     void SetSpacing(const Vector3& spacing);
+    /// Set maximum number of LOD levels for terrain patches. This can be between 1-4.
+    void SetMaxLodLevels(unsigned levels);
+    /// Set LOD level used for terrain patch occlusion. By default (M_MAX_UNSIGNED) the coarsest. Since the LOD level used needs to be fixed, using finer LOD levels may result in false positive occlusion in cases where the actual rendered geometry is coarser, so use with caution.
+    void SetOcclusionLodLevel(unsigned level);
     /// Set smoothing of heightmap.
     /// Set smoothing of heightmap.
     void SetSmoothing(bool enable);
     void SetSmoothing(bool enable);
     /// Set heightmap image. Dimensions should be a power of two + 1. Uses 8-bit grayscale, or optionally red as MSB and green as LSB for 16-bit accuracy. Return true if successful.
     /// Set heightmap image. Dimensions should be a power of two + 1. Uses 8-bit grayscale, or optionally red as MSB and green as LSB for 16-bit accuracy. Return true if successful.
@@ -81,7 +85,7 @@ public:
     void SetMaxLights(unsigned num);
     void SetMaxLights(unsigned num);
     /// Set shadowcaster flag for patches.
     /// Set shadowcaster flag for patches.
     void SetCastShadows(bool enable);
     void SetCastShadows(bool enable);
-    /// Set occlusion flag for patches. Occlusion uses the coarsest LOD and may potentially be too aggressive, so use with caution.
+    /// Set occlusion flag for patches. Occlusion uses the coarsest LOD by default.
     void SetOccluder(bool enable);
     void SetOccluder(bool enable);
     /// Set occludee flag for patches.
     /// Set occludee flag for patches.
     void SetOccludee(bool enable);
     void SetOccludee(bool enable);
@@ -100,6 +104,12 @@ public:
     /// Return heightmap size in patches.
     /// Return heightmap size in patches.
     const IntVector2& GetNumPatches() const { return numPatches_; }
     const IntVector2& GetNumPatches() const { return numPatches_; }
 
 
+    /// Return maximum number of LOD levels for terrain patches. This can be between 1-4.
+    unsigned GetMaxLodLevels() const { return maxLodLevels_; }
+    
+    /// Return LOD level used for occlusion.
+    unsigned GetOcclusionLodLevel() const { return occlusionLodLevel_; }
+    
     /// Return whether smoothing is in use.
     /// Return whether smoothing is in use.
     bool GetSmoothing() const { return smoothing_; }
     bool GetSmoothing() const { return smoothing_; }
 
 
@@ -167,6 +177,10 @@ public:
     void SetMaterialAttr(const ResourceRef& value);
     void SetMaterialAttr(const ResourceRef& value);
     /// Set patch size attribute.
     /// Set patch size attribute.
     void SetPatchSizeAttr(int value);
     void SetPatchSizeAttr(int value);
+    /// Set max LOD levels attribute.
+    void SetMaxLodLevelsAttr(unsigned value);
+    /// Set occlusion LOD level attribute.
+    void SetOcclusionLodLevelAttr(unsigned value);
     /// Return heightmap attribute.
     /// Return heightmap attribute.
     ResourceRef GetHeightMapAttr() const;
     ResourceRef GetHeightMapAttr() const;
     /// Return material attribute.
     /// Return material attribute.
@@ -228,6 +242,10 @@ private:
     int lastPatchSize_;
     int lastPatchSize_;
     /// Number of terrain LOD levels.
     /// Number of terrain LOD levels.
     unsigned numLodLevels_;
     unsigned numLodLevels_;
+    /// Maximum number of LOD levels.
+    unsigned maxLodLevels_;
+    /// LOD level used for occlusion.
+    unsigned occlusionLodLevel_;
     /// Smoothing enable flag.
     /// Smoothing enable flag.
     bool smoothing_;
     bool smoothing_;
     /// Visible flag.
     /// Visible flag.

+ 10 - 10
Source/Urho3D/Graphics/TerrainPatch.cpp

@@ -24,6 +24,7 @@
 
 
 #include "../Core/Context.h"
 #include "../Core/Context.h"
 #include "../Graphics/Camera.h"
 #include "../Graphics/Camera.h"
+#include "../Graphics/DebugRenderer.h"
 #include "../Graphics/Geometry.h"
 #include "../Graphics/Geometry.h"
 #include "../Graphics/IndexBuffer.h"
 #include "../Graphics/IndexBuffer.h"
 #include "../Graphics/Material.h"
 #include "../Graphics/Material.h"
@@ -48,14 +49,14 @@ TerrainPatch::TerrainPatch(Context* context) :
     Drawable(context, DRAWABLE_GEOMETRY),
     Drawable(context, DRAWABLE_GEOMETRY),
     geometry_(new Geometry(context)),
     geometry_(new Geometry(context)),
     maxLodGeometry_(new Geometry(context)),
     maxLodGeometry_(new Geometry(context)),
-    minLodGeometry_(new Geometry(context)),
+    occlusionGeometry_(new Geometry(context)),
     vertexBuffer_(new VertexBuffer(context)),
     vertexBuffer_(new VertexBuffer(context)),
     coordinates_(IntVector2::ZERO),
     coordinates_(IntVector2::ZERO),
     lodLevel_(0)
     lodLevel_(0)
 {
 {
     geometry_->SetVertexBuffer(0, vertexBuffer_, MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1 | MASK_TANGENT);
     geometry_->SetVertexBuffer(0, vertexBuffer_, MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1 | MASK_TANGENT);
     maxLodGeometry_->SetVertexBuffer(0, vertexBuffer_, MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1 | MASK_TANGENT);
     maxLodGeometry_->SetVertexBuffer(0, vertexBuffer_, MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1 | MASK_TANGENT);
-    minLodGeometry_->SetVertexBuffer(0, vertexBuffer_, MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1 | MASK_TANGENT);
+    occlusionGeometry_->SetVertexBuffer(0, vertexBuffer_, MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1 | MASK_TANGENT);
 
 
     batches_.Resize(1);
     batches_.Resize(1);
     batches_[0].geometry_ = geometry_;
     batches_[0].geometry_ = geometry_;
@@ -175,7 +176,7 @@ unsigned TerrainPatch::GetNumOccluderTriangles()
     if (mat && !mat->GetOcclusion())
     if (mat && !mat->GetOcclusion())
         return 0;
         return 0;
     else
     else
-        return minLodGeometry_->GetIndexCount() / 3;
+        return occlusionGeometry_->GetIndexCount() / 3;
 }
 }
 
 
 bool TerrainPatch::DrawOcclusion(OcclusionBuffer* buffer)
 bool TerrainPatch::DrawOcclusion(OcclusionBuffer* buffer)
@@ -197,22 +198,21 @@ bool TerrainPatch::DrawOcclusion(OcclusionBuffer* buffer)
     unsigned indexSize;
     unsigned indexSize;
     unsigned elementMask;
     unsigned elementMask;
 
 
-    minLodGeometry_->GetRawData(vertexData, vertexSize, indexData, indexSize, elementMask);
+    occlusionGeometry_->GetRawData(vertexData, vertexSize, indexData, indexSize, elementMask);
     // Check for valid geometry data
     // Check for valid geometry data
     if (!vertexData || !indexData)
     if (!vertexData || !indexData)
         return true;
         return true;
 
 
     // Draw and check for running out of triangles
     // Draw and check for running out of triangles
-    return buffer->Draw(node_->GetWorldTransform(), vertexData, vertexSize, indexData, indexSize, minLodGeometry_->GetIndexStart(),
-        minLodGeometry_->GetIndexCount());
+    return buffer->Draw(node_->GetWorldTransform(), vertexData, vertexSize, indexData, indexSize, occlusionGeometry_->GetIndexStart(),
+        occlusionGeometry_->GetIndexCount());
 }
 }
 
 
 void TerrainPatch::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
 void TerrainPatch::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
 {
 {
-    // Intentionally no action
+    // Intentionally no operation
 }
 }
 
 
-
 void TerrainPatch::SetOwner(Terrain* terrain)
 void TerrainPatch::SetOwner(Terrain* terrain)
 {
 {
     owner_ = terrain;
     owner_ = terrain;
@@ -257,9 +257,9 @@ Geometry* TerrainPatch::GetMaxLodGeometry() const
     return maxLodGeometry_;
     return maxLodGeometry_;
 }
 }
 
 
-Geometry* TerrainPatch::GetMinLodGeometry() const
+Geometry* TerrainPatch::GetOcclusionGeometry() const
 {
 {
-    return minLodGeometry_;
+    return occlusionGeometry_;
 }
 }
 
 
 VertexBuffer* TerrainPatch::GetVertexBuffer() const
 VertexBuffer* TerrainPatch::GetVertexBuffer() const

+ 5 - 5
Source/Urho3D/Graphics/TerrainPatch.h

@@ -76,10 +76,10 @@ public:
 
 
     /// Return visible geometry.
     /// Return visible geometry.
     Geometry* GetGeometry() const;
     Geometry* GetGeometry() const;
-    /// Return max LOD geometry.
+    /// Return max LOD geometry. Used for decals.
     Geometry* GetMaxLodGeometry() const;
     Geometry* GetMaxLodGeometry() const;
-    /// Return min LOD geometry.
-    Geometry* GetMinLodGeometry() const;
+    /// Return geometry used for occlusion.
+    Geometry* GetOcclusionGeometry() const;
     /// Return vertex buffer.
     /// Return vertex buffer.
     VertexBuffer* GetVertexBuffer() const;
     VertexBuffer* GetVertexBuffer() const;
     /// Return owner terrain.
     /// Return owner terrain.
@@ -118,8 +118,8 @@ private:
     SharedPtr<Geometry> geometry_;
     SharedPtr<Geometry> geometry_;
     /// Geometry that is locked to the max LOD level. Used for decals.
     /// Geometry that is locked to the max LOD level. Used for decals.
     SharedPtr<Geometry> maxLodGeometry_;
     SharedPtr<Geometry> maxLodGeometry_;
-    /// Geometry that is locked to the minimum LOD level. Used for occlusion.
-    SharedPtr<Geometry> minLodGeometry_;
+    /// Geometry that is used for occlusion.
+    SharedPtr<Geometry> occlusionGeometry_;
     /// Vertex buffer.
     /// Vertex buffer.
     SharedPtr<VertexBuffer> vertexBuffer_;
     SharedPtr<VertexBuffer> vertexBuffer_;
     /// Parent terrain.
     /// Parent terrain.

+ 6 - 0
Source/Urho3D/LuaScript/pkgs/Graphics/Terrain.pkg

@@ -4,6 +4,8 @@ class Terrain : public Component
 {
 {
     void SetPatchSize(int size);
     void SetPatchSize(int size);
     void SetSpacing(const Vector3& spacing);
     void SetSpacing(const Vector3& spacing);
+    void SetMaxLodLevels(unsigned levels);
+    void SetOcclusionLodLevel(unsigned level);
     void SetSmoothing(bool enable);
     void SetSmoothing(bool enable);
     bool SetHeightMap(Image* image);
     bool SetHeightMap(Image* image);
     void SetMaterial(Material* material);
     void SetMaterial(Material* material);
@@ -24,6 +26,8 @@ class Terrain : public Component
     const Vector3& GetSpacing() const;
     const Vector3& GetSpacing() const;
     const IntVector2& GetNumVertices() const;
     const IntVector2& GetNumVertices() const;
     const IntVector2& GetNumPatches() const;
     const IntVector2& GetNumPatches() const;
+    unsigned GetMaxLodLevels() const;
+    unsigned GetOcclusionLodLevel() const;
     bool GetSmoothing() const;
     bool GetSmoothing() const;
     Image* GetHeightMap() const;
     Image* GetHeightMap() const;
     Material* GetMaterial() const;
     Material* GetMaterial() const;
@@ -50,6 +54,8 @@ class Terrain : public Component
     tolua_property__get_set Vector3& spacing;
     tolua_property__get_set Vector3& spacing;
     tolua_readonly tolua_property__get_set IntVector2& numVertices;
     tolua_readonly tolua_property__get_set IntVector2& numVertices;
     tolua_readonly tolua_property__get_set IntVector2& numPatches;
     tolua_readonly tolua_property__get_set IntVector2& numPatches;
+    tolua_property__get_set unsigned maxLodLevels;
+    tolua_property__get_set unsigned occlusionLodLevel;
     tolua_property__get_set bool smoothing;
     tolua_property__get_set bool smoothing;
     tolua_property__get_set Image* heightMap;
     tolua_property__get_set Image* heightMap;
     tolua_property__get_set Material* material;
     tolua_property__get_set Material* material;

+ 2 - 2
Source/Urho3D/LuaScript/pkgs/Graphics/TerrainPatch.pkg

@@ -11,7 +11,7 @@ class TerrainPatch : public Drawable
     
     
     Geometry* GetGeometry() const;
     Geometry* GetGeometry() const;
     Geometry* GetMaxLodGeometry() const;
     Geometry* GetMaxLodGeometry() const;
-    Geometry* GetMinLodGeometry() const;
+    Geometry* GetOcclusionGeometry() const;
     VertexBuffer* GetVertexBuffer() const;
     VertexBuffer* GetVertexBuffer() const;
     Terrain* GetOwner() const;
     Terrain* GetOwner() const;
     TerrainPatch* GetNorthPatch() const;
     TerrainPatch* GetNorthPatch() const;
@@ -23,7 +23,7 @@ class TerrainPatch : public Drawable
 
 
     tolua_readonly tolua_property__get_set Geometry* geometry;
     tolua_readonly tolua_property__get_set Geometry* geometry;
     tolua_readonly tolua_property__get_set Geometry* maxLodGeometry;
     tolua_readonly tolua_property__get_set Geometry* maxLodGeometry;
-    tolua_readonly tolua_property__get_set Geometry* minLodGeometry;
+    tolua_readonly tolua_property__get_set Geometry* occlusionGeometry;
     tolua_readonly tolua_property__get_set VertexBuffer* vertexBuffer;
     tolua_readonly tolua_property__get_set VertexBuffer* vertexBuffer;
     tolua_property__get_set Terrain* owner;
     tolua_property__get_set Terrain* owner;
     tolua_readonly tolua_property__get_set TerrainPatch* northPatch;
     tolua_readonly tolua_property__get_set TerrainPatch* northPatch;

+ 4 - 0
Source/Urho3D/Script/GraphicsAPI.cpp

@@ -1431,6 +1431,10 @@ static void RegisterTerrain(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Terrain", "IntVector2 WorldToHeightMap(const Vector3&in) const", asMETHOD(Terrain, WorldToHeightMap), asCALL_THISCALL);
     engine->RegisterObjectMethod("Terrain", "IntVector2 WorldToHeightMap(const Vector3&in) const", asMETHOD(Terrain, WorldToHeightMap), asCALL_THISCALL);
     engine->RegisterObjectMethod("Terrain", "void set_material(Material@+)", asMETHOD(Terrain, SetMaterial), asCALL_THISCALL);
     engine->RegisterObjectMethod("Terrain", "void set_material(Material@+)", asMETHOD(Terrain, SetMaterial), asCALL_THISCALL);
     engine->RegisterObjectMethod("Terrain", "Material@+ get_material() const", asMETHOD(Terrain, GetMaterial), asCALL_THISCALL);
     engine->RegisterObjectMethod("Terrain", "Material@+ get_material() const", asMETHOD(Terrain, GetMaterial), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Terrain", "void set_maxLodLevels(uint)", asMETHOD(Terrain, SetMaxLodLevels), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Terrain", "uint get_maxLodLevels() const", asMETHOD(Terrain, GetMaxLodLevels), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Terrain", "void set_occlusionLodLevel(uint)", asMETHOD(Terrain, SetOcclusionLodLevel), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Terrain", "uint get_occlusionLodLevel() const", asMETHOD(Terrain, GetOcclusionLodLevel), asCALL_THISCALL);
     engine->RegisterObjectMethod("Terrain", "void set_smoothing(bool)", asMETHOD(Terrain, SetSmoothing), asCALL_THISCALL);
     engine->RegisterObjectMethod("Terrain", "void set_smoothing(bool)", asMETHOD(Terrain, SetSmoothing), asCALL_THISCALL);
     engine->RegisterObjectMethod("Terrain", "bool get_smoothing() const", asMETHOD(Terrain, GetSmoothing), asCALL_THISCALL);
     engine->RegisterObjectMethod("Terrain", "bool get_smoothing() const", asMETHOD(Terrain, GetSmoothing), asCALL_THISCALL);
     engine->RegisterObjectMethod("Terrain", "void set_heightMap(Image@+)", asMETHOD(Terrain, SetHeightMap), asCALL_THISCALL);
     engine->RegisterObjectMethod("Terrain", "void set_heightMap(Image@+)", asMETHOD(Terrain, SetHeightMap), asCALL_THISCALL);