1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-03-03 14:09:39 +00:00

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

This commit is contained in:
scrawl 2014-02-16 18:48:35 +01:00
parent ab224f93c9
commit c9e349f60f
11 changed files with 147 additions and 57 deletions

View file

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

View file

@ -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 vertexBuffer,
Ogre::HardwareVertexBufferSharedPtr normalBuffer, Ogre::HardwareVertexBufferSharedPtr normalBuffer,
Ogre::HardwareVertexBufferSharedPtr colourBuffer) Ogre::HardwareVertexBufferSharedPtr colourBuffer)

View file

@ -36,7 +36,7 @@ namespace MWRender
/// @param vertexBuffer buffer to write vertices /// @param vertexBuffer buffer to write vertices
/// @param normalBuffer buffer to write vertex normals /// @param normalBuffer buffer to write vertex normals
/// @param colourBuffer buffer to write vertex colours /// @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 vertexBuffer,
Ogre::HardwareVertexBufferSharedPtr normalBuffer, Ogre::HardwareVertexBufferSharedPtr normalBuffer,
Ogre::HardwareVertexBufferSharedPtr colourBuffer); Ogre::HardwareVertexBufferSharedPtr colourBuffer);

View file

@ -52,7 +52,7 @@ namespace Terrain
mColourBuffer = mgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR), mColourBuffer = mgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR),
mVertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC); 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); mVertexBuffer, mNormalBuffer, mColourBuffer);
mVertexData->vertexBufferBinding->setBinding(0, mVertexBuffer); mVertexData->vertexBufferBinding->setBinding(0, mVertexBuffer);

View file

@ -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

View file

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

View file

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

View file

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

View file

@ -1,10 +1,10 @@
#ifndef COMPONENTS_TERRAIN_STORAGE_H #ifndef COMPONENTS_TERRAIN_STORAGE_H
#define COMPONENTS_TERRAIN_STORAGE_H #define COMPONENTS_TERRAIN_STORAGE_H
#include <OgreAxisAlignedBox.h>
#include <OgreHardwareVertexBuffer.h> #include <OgreHardwareVertexBuffer.h>
#include "defs.hpp"
namespace Terrain namespace Terrain
{ {
@ -43,7 +43,7 @@ namespace Terrain
/// @param vertexBuffer buffer to write vertices /// @param vertexBuffer buffer to write vertices
/// @param normalBuffer buffer to write vertex normals /// @param normalBuffer buffer to write vertex normals
/// @param colourBuffer buffer to write vertex colours /// @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 vertexBuffer,
Ogre::HardwareVertexBufferSharedPtr normalBuffer, Ogre::HardwareVertexBufferSharedPtr normalBuffer,
Ogre::HardwareVertexBufferSharedPtr colourBuffer) = 0; Ogre::HardwareVertexBufferSharedPtr colourBuffer) = 0;

View file

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

View file

@ -6,10 +6,7 @@
#include <OgreAxisAlignedBox.h> #include <OgreAxisAlignedBox.h>
#include <OgreTexture.h> #include <OgreTexture.h>
namespace Loading #include "defs.hpp"
{
class Listener;
}
namespace Ogre namespace Ogre
{ {
@ -33,7 +30,6 @@ namespace Terrain
{ {
public: public:
/// @note takes ownership of \a storage /// @note takes ownership of \a storage
/// @param loadingListener Listener to update with progress
/// @param sceneMgr scene manager to use /// @param sceneMgr scene manager to use
/// @param storage Storage instance to get terrain data from (heights, normals, colors, textures..) /// @param storage Storage instance to get terrain data from (heights, normals, colors, textures..)
/// @param visbilityFlags visibility flags for the created meshes /// @param visbilityFlags visibility flags for the created meshes
@ -41,12 +37,13 @@ namespace Terrain
/// This is a temporary option until it can be streamlined. /// 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 /// @param shaders Whether to use splatting shader, or multi-pass fixed function splatting. Shader is usually
/// faster so this is just here for compatibility. /// faster so this is just here for compatibility.
World(Loading::Listener* loadingListener, Ogre::SceneManager* sceneMgr, /// @param align The align of the terrain, see Alignment enum
Storage* storage, int visiblityFlags, bool distantLand, bool shaders); /// @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(); ~World();
void setLoadingListener(Loading::Listener* loadingListener) { mLoadingListener = loadingListener; }
bool getDistantLandEnabled() { return mDistantLand; } bool getDistantLandEnabled() { return mDistantLand; }
bool getShadersEnabled() { return mShaders; } bool getShadersEnabled() { return mShaders; }
bool getShadowsEnabled() { return mShadows; } bool getShadowsEnabled() { return mShadows; }
@ -86,14 +83,15 @@ namespace Terrain
void enableSplattingShader(bool enabled); void enableSplattingShader(bool enabled);
Alignment getAlign() { return mAlign; }
private: private:
bool mDistantLand; bool mDistantLand;
bool mShaders; bool mShaders;
bool mShadows; bool mShadows;
bool mSplitShadows; bool mSplitShadows;
bool mVisible; bool mVisible;
Alignment mAlign;
Loading::Listener* mLoadingListener;
QuadTreeNode* mRootNode; QuadTreeNode* mRootNode;
Ogre::SceneNode* mRootSceneNode; Ogre::SceneNode* mRootSceneNode;
@ -138,6 +136,11 @@ namespace Terrain
void clearCompositeMapSceneManager(); void clearCompositeMapSceneManager();
void renderCompositeMap (Ogre::TexturePtr target); 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: private:
// Index buffers are shared across terrain batches where possible. There is one index buffer for each // 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. // combination of LOD deltas and index buffer LOD we may need.