Terrain: support alternate coordinate systems. Get rid of LoadingListener for now

actorid
scrawl 11 years ago
parent ab224f93c9
commit c9e349f60f

@ -1043,15 +1043,12 @@ void RenderingManager::enableTerrain(bool enable)
{
if (!mTerrain)
{
Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
Loading::ScopedLoad load(listener);
mTerrain = new Terrain::World(listener, mRendering.getScene(), new MWRender::TerrainStorage(), RV_Terrain,
mTerrain = new Terrain::World(mRendering.getScene(), new MWRender::TerrainStorage(), RV_Terrain,
Settings::Manager::getBool("distant land", "Terrain"),
Settings::Manager::getBool("shader", "Terrain"));
Settings::Manager::getBool("shader", "Terrain"), Terrain::Align_XY, 1, 64);
mTerrain->applyMaterials(Settings::Manager::getBool("enabled", "Shadows"),
Settings::Manager::getBool("split", "Shadows"));
mTerrain->update(mRendering.getCamera()->getRealPosition());
mTerrain->setLoadingListener(NULL);
}
mTerrain->setVisible(true);
}

@ -167,7 +167,7 @@ namespace MWRender
}
void TerrainStorage::fillVertexBuffers (int lodLevel, float size, const Ogre::Vector2& center,
void TerrainStorage::fillVertexBuffers (int lodLevel, float size, const Ogre::Vector2& center, Terrain::Alignment align,
Ogre::HardwareVertexBufferSharedPtr vertexBuffer,
Ogre::HardwareVertexBufferSharedPtr normalBuffer,
Ogre::HardwareVertexBufferSharedPtr colourBuffer)

@ -36,7 +36,7 @@ namespace MWRender
/// @param vertexBuffer buffer to write vertices
/// @param normalBuffer buffer to write vertex normals
/// @param colourBuffer buffer to write vertex colours
virtual void fillVertexBuffers (int lodLevel, float size, const Ogre::Vector2& center,
virtual void fillVertexBuffers (int lodLevel, float size, const Ogre::Vector2& center, Terrain::Alignment align,
Ogre::HardwareVertexBufferSharedPtr vertexBuffer,
Ogre::HardwareVertexBufferSharedPtr normalBuffer,
Ogre::HardwareVertexBufferSharedPtr colourBuffer);

@ -52,7 +52,7 @@ namespace Terrain
mColourBuffer = mgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR),
mVertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC);
mNode->getTerrain()->getStorage()->fillVertexBuffers(lodLevel, mNode->getSize(), mNode->getCenter(),
mNode->getTerrain()->getStorage()->fillVertexBuffers(lodLevel, mNode->getSize(), mNode->getCenter(), mNode->getTerrain()->getAlign(),
mVertexBuffer, mNormalBuffer, mColourBuffer);
mVertexData->vertexBufferBinding->setBinding(0, mVertexBuffer);

@ -0,0 +1,41 @@
#ifndef COMPONENTS_TERRAIN_DEFS_HPP
#define COMPONENTS_TERRAIN_DEFS_HPP
namespace Terrain
{
/// The alignment of the terrain
enum Alignment
{
/// Terrain is in the X/Z plane
Align_XZ = 0,
/// Terrain is in the X/Y plane
Align_XY = 1,
/// Terrain is in the Y/Z plane.
/// UNTESTED - use at own risk.
/// Besides, X as up axis? What is wrong with you? ;)
Align_YZ = 2
};
inline void convertPosition(Alignment align, float &x, float &y, float &z)
{
switch (align)
{
case Align_XY:
return;
case Align_XZ:
std::swap(y, z);
// This is since -Z should be going *into* the screen
// If not doing this, we'd get wrong vertex winding
z *= -1;
return;
case Align_YZ:
std::swap(x, y);
std::swap(y, z);
return;
}
}
}
#endif

@ -235,7 +235,6 @@ namespace Terrain
sh::MaterialInstancePass* p = material->createPass ();
p->setProperty ("vertex_program", sh::makeProperty<sh::StringValue>(new sh::StringValue("terrain_vertex")));
p->setProperty ("fragment_program", sh::makeProperty<sh::StringValue>(new sh::StringValue("terrain_fragment")));
if (layerOffset != 0)

@ -169,7 +169,11 @@ QuadTreeNode::QuadTreeNode(World* terrain, ChildDirection dir, float size, const
pos = mParent->getCenter();
pos = mCenter - pos;
float cellWorldSize = mTerrain->getStorage()->getCellWorldSize();
mSceneNode->setPosition(Ogre::Vector3(pos.x*cellWorldSize, pos.y*cellWorldSize, 0));
Ogre::Vector3 sceneNodePos (pos.x*cellWorldSize, pos.y*cellWorldSize, 0);
mTerrain->convertPosition(sceneNodePos.x, sceneNodePos.y, sceneNodePos.z);
mSceneNode->setPosition(sceneNodePos);
mMaterialGenerator = new MaterialGenerator(mTerrain->getShadersEnabled());
}
@ -212,11 +216,31 @@ void QuadTreeNode::initAabb()
mChildren[i]->initAabb();
mBounds.merge(mChildren[i]->getBoundingBox());
}
mBounds = Ogre::AxisAlignedBox (Ogre::Vector3(-mSize/2*cellWorldSize, -mSize/2*cellWorldSize, mBounds.getMinimum().z),
Ogre::Vector3(mSize/2*cellWorldSize, mSize/2*cellWorldSize, mBounds.getMaximum().z));
float minH, maxH;
switch (mTerrain->getAlign())
{
case Terrain::Align_XY:
minH = mBounds.getMinimum().z;
maxH = mBounds.getMaximum().z;
break;
case Terrain::Align_XZ:
minH = mBounds.getMinimum().y;
maxH = mBounds.getMinimum().y;
break;
case Terrain::Align_YZ:
minH = mBounds.getMinimum().x;
maxH = mBounds.getMaximum().x;
break;
}
Ogre::Vector3 min(-mSize/2*cellWorldSize, -mSize/2*cellWorldSize, minH);
Ogre::Vector3 max(Ogre::Vector3(mSize/2*cellWorldSize, mSize/2*cellWorldSize, maxH));
mBounds = Ogre::AxisAlignedBox (min, max);
mTerrain->convertBounds(mBounds);
}
mWorldBounds = Ogre::AxisAlignedBox(mBounds.getMinimum() + Ogre::Vector3(mCenter.x*cellWorldSize, mCenter.y*cellWorldSize, 0),
mBounds.getMaximum() + Ogre::Vector3(mCenter.x*cellWorldSize, mCenter.y*cellWorldSize, 0));
Ogre::Vector3 offset(mCenter.x*cellWorldSize, mCenter.y*cellWorldSize, 0);
mTerrain->convertPosition(offset);
mWorldBounds = Ogre::AxisAlignedBox(mBounds.getMinimum() + offset,
mBounds.getMaximum() + offset);
}
void QuadTreeNode::setBoundingBox(const Ogre::AxisAlignedBox &box)
@ -229,7 +253,12 @@ const Ogre::AxisAlignedBox& QuadTreeNode::getBoundingBox()
return mBounds;
}
void QuadTreeNode::update(const Ogre::Vector3 &cameraPos, Loading::Listener* loadingListener)
const Ogre::AxisAlignedBox& QuadTreeNode::getWorldBoundingBox()
{
return mWorldBounds;
}
void QuadTreeNode::update(const Ogre::Vector3 &cameraPos)
{
const Ogre::AxisAlignedBox& bounds = getBoundingBox();
if (bounds.isNull())
@ -263,9 +292,6 @@ void QuadTreeNode::update(const Ogre::Vector3 &cameraPos, Loading::Listener* loa
bool hadChunk = hasChunk();
if (loadingListener)
loadingListener->indicateProgress();
if (!distantLand && dist > 8192*2)
{
if (mIsActive)
@ -353,7 +379,7 @@ void QuadTreeNode::update(const Ogre::Vector3 &cameraPos, Loading::Listener* loa
}
assert(hasChildren() && "Leaf node's LOD needs to be 0");
for (int i=0; i<4; ++i)
mChildren[i]->update(cameraPos, loadingListener);
mChildren[i]->update(cameraPos);
}
}

@ -5,8 +5,6 @@
#include <OgreVector2.h>
#include <OgreTexture.h>
#include <components/loadinglistener/loadinglistener.hpp>
namespace Ogre
{
class Rectangle2D;
@ -95,10 +93,12 @@ namespace Terrain
/// Get bounding box in local coordinates
const Ogre::AxisAlignedBox& getBoundingBox();
const Ogre::AxisAlignedBox& getWorldBoundingBox();
World* getTerrain() { return mTerrain; }
/// Adjust LODs for the given camera position, possibly splitting up chunks or merging them.
void update (const Ogre::Vector3& cameraPos, Loading::Listener* loadingListener);
void update (const Ogre::Vector3& cameraPos);
/// Adjust index buffers of chunks to stitch together chunks of different LOD, so that cracks are avoided.
/// Call after QuadTreeNode::update!

@ -1,10 +1,10 @@
#ifndef COMPONENTS_TERRAIN_STORAGE_H
#define COMPONENTS_TERRAIN_STORAGE_H
#include <OgreAxisAlignedBox.h>
#include <OgreHardwareVertexBuffer.h>
#include "defs.hpp"
namespace Terrain
{
@ -43,7 +43,7 @@ namespace Terrain
/// @param vertexBuffer buffer to write vertices
/// @param normalBuffer buffer to write vertex normals
/// @param colourBuffer buffer to write vertex colours
virtual void fillVertexBuffers (int lodLevel, float size, const Ogre::Vector2& center,
virtual void fillVertexBuffers (int lodLevel, float size, const Ogre::Vector2& center, Terrain::Alignment align,
Ogre::HardwareVertexBufferSharedPtr vertexBuffer,
Ogre::HardwareVertexBufferSharedPtr normalBuffer,
Ogre::HardwareVertexBufferSharedPtr colourBuffer) = 0;

@ -6,8 +6,6 @@
#include <OgreHardwarePixelBuffer.h>
#include <OgreRoot.h>
#include <components/loadinglistener/loadinglistener.hpp>
#include "storage.hpp"
#include "quadtreenode.hpp"
@ -51,27 +49,25 @@ namespace
namespace Terrain
{
World::World(Loading::Listener* loadingListener, Ogre::SceneManager* sceneMgr,
Storage* storage, int visibilityFlags, bool distantLand, bool shaders)
World::World(Ogre::SceneManager* sceneMgr,
Storage* storage, int visibilityFlags, bool distantLand, bool shaders, Alignment align, float minBatchSize, float maxBatchSize)
: mStorage(storage)
, mMinBatchSize(1)
, mMaxBatchSize(64)
, mMinBatchSize(minBatchSize)
, mMaxBatchSize(maxBatchSize)
, mSceneMgr(sceneMgr)
, mVisibilityFlags(visibilityFlags)
, mDistantLand(distantLand)
, mShaders(shaders)
, mVisible(true)
, mLoadingListener(loadingListener)
, mAlign(align)
, mMaxX(0)
, mMinX(0)
, mMaxY(0)
, mMinY(0)
{
loadingListener->setLabel("Creating terrain");
loadingListener->indicateProgress();
mCompositeMapSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC);
/// \todo make composite map size configurable
Ogre::Camera* compositeMapCam = mCompositeMapSceneMgr->createCamera("a");
mCompositeMapRenderTexture = Ogre::TextureManager::getSingleton().createManual(
"terrain/comp/rt", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
@ -96,11 +92,11 @@ namespace Terrain
mRootNode = new QuadTreeNode(this, Root, size, Ogre::Vector2(centerX, centerY), NULL);
buildQuadTree(mRootNode);
loadingListener->indicateProgress();
//loadingListener->indicateProgress();
mRootNode->initAabb();
loadingListener->indicateProgress();
//loadingListener->indicateProgress();
mRootNode->initNeighbours();
loadingListener->indicateProgress();
//loadingListener->indicateProgress();
}
World::~World()
@ -120,8 +116,12 @@ namespace Terrain
Ogre::Vector2 center = node->getCenter();
float cellWorldSize = getStorage()->getCellWorldSize();
if (mStorage->getMinMaxHeights(node->getSize(), center, minZ, maxZ))
node->setBoundingBox(Ogre::AxisAlignedBox(Ogre::Vector3(-halfSize*cellWorldSize, -halfSize*cellWorldSize, minZ),
Ogre::Vector3(halfSize*cellWorldSize, halfSize*cellWorldSize, maxZ)));
{
Ogre::AxisAlignedBox bounds(Ogre::Vector3(-halfSize*cellWorldSize, -halfSize*cellWorldSize, minZ),
Ogre::Vector3(halfSize*cellWorldSize, halfSize*cellWorldSize, maxZ));
convertBounds(bounds);
node->setBoundingBox(bounds);
}
else
node->markAsDummy(); // no data available for this node, skip it
return;
@ -161,7 +161,7 @@ namespace Terrain
{
if (!mVisible)
return;
mRootNode->update(cameraPos, mLoadingListener);
mRootNode->update(cameraPos);
mRootNode->updateIndexBuffers();
}
@ -173,11 +173,7 @@ namespace Terrain
|| center.y < mMinY)
return Ogre::AxisAlignedBox::BOX_NULL;
QuadTreeNode* node = findNode(center, mRootNode);
Ogre::AxisAlignedBox box = node->getBoundingBox();
float cellWorldSize = getStorage()->getCellWorldSize();
box.setExtents(box.getMinimum() + Ogre::Vector3(center.x, center.y, 0) * cellWorldSize,
box.getMaximum() + Ogre::Vector3(center.x, center.y, 0) * cellWorldSize);
return box;
return node->getWorldBoundingBox();
}
Ogre::HardwareVertexBufferSharedPtr World::getVertexBuffer(int numVertsOneSide)
@ -414,5 +410,33 @@ namespace Terrain
return mVisible;
}
void World::convertPosition(float &x, float &y, float &z)
{
Terrain::convertPosition(mAlign, x, y, z);
}
void World::convertPosition(Ogre::Vector3 &pos)
{
convertPosition(pos.x, pos.y, pos.z);
}
void World::convertBounds(Ogre::AxisAlignedBox& bounds)
{
switch (mAlign)
{
case Align_XY:
return;
case Align_XZ:
convertPosition(bounds.getMinimum());
convertPosition(bounds.getMaximum());
// Because we changed sign of Z
std::swap(bounds.getMinimum().z, bounds.getMaximum().z);
return;
case Align_YZ:
convertPosition(bounds.getMinimum());
convertPosition(bounds.getMaximum());
return;
}
}
}

@ -6,10 +6,7 @@
#include <OgreAxisAlignedBox.h>
#include <OgreTexture.h>
namespace Loading
{
class Listener;
}
#include "defs.hpp"
namespace Ogre
{
@ -33,7 +30,6 @@ namespace Terrain
{
public:
/// @note takes ownership of \a storage
/// @param loadingListener Listener to update with progress
/// @param sceneMgr scene manager to use
/// @param storage Storage instance to get terrain data from (heights, normals, colors, textures..)
/// @param visbilityFlags visibility flags for the created meshes
@ -41,12 +37,13 @@ namespace Terrain
/// This is a temporary option until it can be streamlined.
/// @param shaders Whether to use splatting shader, or multi-pass fixed function splatting. Shader is usually
/// faster so this is just here for compatibility.
World(Loading::Listener* loadingListener, Ogre::SceneManager* sceneMgr,
Storage* storage, int visiblityFlags, bool distantLand, bool shaders);
/// @param align The align of the terrain, see Alignment enum
/// @param minBatchSize Minimum size of a terrain batch along one side (in cell units). Used for building the quad tree.
/// @param maxBatchSize Maximum size of a terrain batch along one side (in cell units). Used when traversing the quad tree.
World(Ogre::SceneManager* sceneMgr,
Storage* storage, int visiblityFlags, bool distantLand, bool shaders, Alignment align, float minBatchSize, float maxBatchSize);
~World();
void setLoadingListener(Loading::Listener* loadingListener) { mLoadingListener = loadingListener; }
bool getDistantLandEnabled() { return mDistantLand; }
bool getShadersEnabled() { return mShaders; }
bool getShadowsEnabled() { return mShadows; }
@ -86,14 +83,15 @@ namespace Terrain
void enableSplattingShader(bool enabled);
Alignment getAlign() { return mAlign; }
private:
bool mDistantLand;
bool mShaders;
bool mShadows;
bool mSplitShadows;
bool mVisible;
Loading::Listener* mLoadingListener;
Alignment mAlign;
QuadTreeNode* mRootNode;
Ogre::SceneNode* mRootSceneNode;
@ -138,6 +136,11 @@ namespace Terrain
void clearCompositeMapSceneManager();
void renderCompositeMap (Ogre::TexturePtr target);
// Convert the given position from Z-up align, i.e. Align_XY to the wanted align set in mAlign
void convertPosition (float& x, float& y, float& z);
void convertPosition (Ogre::Vector3& pos);
void convertBounds (Ogre::AxisAlignedBox& bounds);
private:
// Index buffers are shared across terrain batches where possible. There is one index buffer for each
// combination of LOD deltas and index buffer LOD we may need.

Loading…
Cancel
Save