Projective Decals

snipexv

18-02-2006 04:19:58

I've been trying to use the recent projective decal tutorial to add a decal to my plsm terrain and I had a question. Which material do I need to add the pass to in order for my projective decal to appear on the terrain.

Thanks.

tuan kuranes

18-02-2006 08:18:09

you have to get page x and Y using "scenemanager::getOption()" and then compose the name of the Material for that Page. You can do that knowing the texture mode you're using (check paginglandcsapeTexture.....cpp for name composition.)

But I can add a mechanism using scenemanager::getOption() that would give material name for a page X,Y. so that It would work everytime, without "hard coding" the material composition name.

snipexv

18-02-2006 20:17:10

That would probably be useful.

Thanks for your help!

Falagard

18-02-2006 22:09:13

If you get decals working let me know, I'm interested in them too.

tuan kuranes

20-02-2006 07:55:44

Added on todo list.
Will post when available in CVS.

tuan kuranes

21-02-2006 09:33:59

Ok, added it as "getMaterialPageName" scene manager Option in CVS.

Example code is :

Vector3 myspos(x,y,z);
void *myOptionPtr = &myspos;
getOption ("getMaterialPageName", myOptionPtr);
String myPageMaterialName = *myOptionPtr;


Keep us informed of how it goes.

snipexv

21-02-2006 14:59:55

I will try it out tonight. Thanks!

Cutter

23-05-2006 17:48:43

Hi, I also want to use projective Decals on my terrain. So I tried to adapt the code above, but it doesn`t work for me. I use a current (2 days old) cvs version of plsm2.
This is my code:

Ogre::Vector3 p (mPos);
void* myOptionPtr = &p;

app->mSceneMgr->getOption ("getMaterialPageName", myOptionPtr);
std::string terr_mat = *( (std::string*)myOptionPtr);
makeMaterialReceiveDecal(terr_mat);

I double-checked that all variables (mPos, app->mSceneMgr) are valid.

This compiles fine, but produces a runtime error in the getMaterialPageName function:

if (strKey == "getMaterialPageName")
{
if (mPageManager)
{
Vector3 *pos = static_cast < Vector3 * > (pDestValue);
mPageManager->getGlobalToPage (pos->x, pos->z);
>> * static_cast < String * > (pDestValue) = mTextureManager->getTexture(pos->x, pos->z, false)->getMaterialName();
}
return true;
}

The error occurs in line 1410. Everything works until this line is executed: the correct page coordinates and the material name are found, but then the name string is written to the adress of the position vector, which results in an unhandled exception.

I am not that familiar with the internals of c++, so it would be very kind if someone could tell me how to resolve this issue.

tuan kuranes

24-05-2006 09:35:42

Can you try replacing the faulty line by this one :


pDestValue = static_cast <void *> (const_cast <String *>
(&(mTextureManager->getTexture(pos->x, pos->z, false)->getMaterialName())));

Cutter

24-05-2006 20:49:05

OK, I finally managed to retrieve the terrain material by using a string**. This is the code in my application:

Ogre::Vector3 p (mPos);
void* myOptionPtr = &p;

app->mSceneMgr->getOption ("getMaterialPageName", myOptionPtr);
std::string terr_mat = **static_cast<std::string**>(myOptionPtr);
makeMaterialReceiveDecal(terr_mat);

And in PLSM2:

if (strKey == "getMaterialPageName")
{
if (mPageManager)
{
// convert position
Vector3 *pos = static_cast < Vector3 * > (pDestValue);
mPageManager->getGlobalToPage (pos->x, pos->z);

// get the texture
Ogre::PagingLandScapeTexture* texture_ptr =
mTextureManager->getTexture(pos->x, pos->z, false);

// check for valid texture
if( texture_ptr )
{
// get texture name
String* name_ptr = const_cast<String*>(&texture_ptr->getMaterialName());

// convert void pointer to a string**
String** target_ptr = static_cast<String**>(pDestValue);

// save name at target position
*target_ptr = name_ptr;
}
}
return true;
}

It is a bit bloated because of debugging, but it works!

tuan kuranes

25-05-2006 09:27:13

thanks, added to code base.

Cutter

27-05-2006 20:30:56

just wanted to let you know that terrain decals are working properly now. I made a class TerrainDecal that takes a texture, a size and a position. Then it dynamically adds a pass to the underlaying terrain pages (up to 4) and shows the decal. The Position and size can be altered every frame, if needed.

This works pretty good as long as there are not too many TerrainDecals at the same time. With one decal, the fps drop from 120 to 110, which is acceptable, but with 24 decals it drops to 30.

So I guess I will have to take a different approach to show things like selection circles (my game is a RTS) of hundreds of units. Nevertheless I wonder if this class is worth a wiki entry: its very simple, but I didn`t find any link on the wiki or forums to a PLSM2 decal.

Here are some screenshots:

tuan kuranes

30-05-2006 08:56:38

So I guess I will have to take a different approach to show things like selection circles (my game is a RTS) of hundreds of units.

Other ways

- if not already the case applying the decal only on tile concerned, not on all the page that handle the material.(not sure how to do that, after reading your wiki entry, perhaps it would be clearer.)

- Extract Tiles Verteices at this lod of the area covered by the "decals", make a mesh of it, apply your material on it, not forgetting to specifiying a depth bias. (getOption("getAreaSize"), getOption("PageGetTileVertexData_2")) should help

- Extract only vertices at this lod of the area covered by the "decals", make a mesh from them, apply your material on it, not forgetting to specifiying a depth bias. (getOption(getAreaSize), getOption("PageGetTileVertexData_2") to be modified to your needs.).
At first it could be done using Height Ray queries. (terrain editor use this for "selection circle", Check "RTS" on ogre wiki, and its selection scheme.)
if you have a pool of decals mesh, they would just receive their new coordinates at each move.

- Group decals on a single material, dynamically modifying the texture each time a new decal is added/deleted/moved. (using shaders or splatting technique, you can have texture resolution as small as 1 pixel on texture is the smallest decal possible

Nevertheless I wonder if this class is worth a wiki entry: its very simple, but I didn`t find any link on the wiki or forums to a PLSM2 decal.
yes, please, that would help a lot.

neocryptek

31-05-2006 04:36:49

This works pretty good as long as there are not too many TerrainDecals at the same time. With one decal, the fps drop from 120 to 110, which is acceptable, but with 24 decals it drops to 30.

With decals that big, do you think you may be hitting fillrate bottlenecks? If you make them much smaller [like diameter of a unit] does the fps increase?

Also I'm sure many people would enjoy a wiki on it, I know I would.

Falagard

31-05-2006 04:57:55


- Extract Tiles Verteices at this lod of the area covered by the "decals", make a mesh of it, apply your material on it, not forgetting to specifiying a depth bias. (getOption("getAreaSize"), getOption("PageGetTileVertexData_2")) should help


Hrm, I wondering about using decals in combination with GOOF to add extra details to terrain in certain small areas. With GOOF's LOD system I could have the decal only appear when you're close to it, and have it fade in.

I wonder if it would be better to extract the verts into a mesh like you suggest here, or better to simply render additional passes on the existing tile renderable like he's already doing. As you know, the mesh will possibly have z-fighting issues.

I definitely have to look into this!

Falagard

31-05-2006 05:16:35


if not already the case applying the decal only on tile concerned, not on all the page that handle the material.(not sure how to do that, after reading your wiki entry, perhaps it would be clearer.)


That'd only be possible if each tile had its own material since the decal code basically adds a new pass to an existing material and sets it up with custom projection.

It might actually be a good idea to add an option to have a material per tile in some cases. I know it's less batching, but I can think of a few reasons. For example, eventually I might want to fade between full splatting and a base texture by adding another material LOD between the high and low material lods which renders both splatting and base texture at the same time with alpha that gets more translucent further from the camera.

Clay

tuan kuranes

31-05-2006 08:01:49

That'd only be possible if each tile had its own material since the decal code basically adds a new pass to an existing material and sets it up with custom projection.
ok. so have to clone it per tile, then.

It might actually be a good idea to add an option to have a material per tile in some cases.
might be an idea. Have to think about how to do that. (add this to the todo list.)

Cutter

31-05-2006 17:57:26

OK, I added it to the wiki (I hope the style is right, this is the first time for me to edit a wiki page): http://www.ogre3d.org/wiki/index.php/Decals_on_PLSM2_Terrain

Feel free to critizise, I develop my game for the purpose of learning, so I will gladly accept every improvement!

@neocryptek
With decals that big, do you think you may be hitting fillrate bottlenecks? If you make them much smaller [like diameter of a unit] does the fps increase?

I tried to use a smaller texture (100x100 instead of 1000x1000), but the performance difference was minimal (3 fps increasement for 4 decals at the same time). Not sure if I understand you correctly, though. Reducing the decal area does not cause any performance difference, only if the decal is placed in a page border area (in this case the bigger decal needs to affect more than one page, the smaller one can possibly stick to one).

@tuan, falagard

The idea of creating a mesh and dynamically altering the vertices to match the terrain surface looks great to me since this approach would also work with different LODs. In this case a small decal would also perform much better because only the vertices that are affected would be rendered twice.

I think the way to go depends on what you want to do. If you plan to do lots of decals (for Terrain details, for example, as Falagard suggested), a second pass could be faster, I think, because you don`t have to mess with the second mesh.

But if you just want to render some small decals (selection decals in RPGs, for example), the mesh way seems superior to me.

Now I wonder what would be the solution if you want to render hundreds of small decals (object selection in RTS, as seen in Rome). Perhaps one could think about combining all the decal textures in one big texture and then adding a new pass with this big texture to the terrain`s material. I think this was what tuan suggested in this point:
Group decals on a single material, dynamically modifying the texture each time a new decal is added/deleted/moved. (using shaders or splatting technique, you can have texture resolution as small as 1 pixel on texture is the smallest decal possible
In this case you would have to alter the texture very often: every time the selection changes you have to modify the texture. You also have to keep track of all intersecting parts, because if a texture should be removed, you have to clear the texture`s area and remake all other texture areas that intersect the removed one.
I`m not sure how to do that, though: use the cpu and change the texture values in code or use GPU power and render all those small decals as a seperate Render queue? My knowledge of these things is quite limited, so feel free to give more comments!

tuan kuranes

01-06-2006 15:28:26

if you want to render hundreds of small decals
It could be grouped in one or several mesh updated on selection moves. If you group mesh into a single vertex buffer, that should give the fastest and lower cost solution.
You can even use Ogre::Billboards there, as each selection is a Quad, and each Quad has same texture.

I think this was what tuan suggested
Yes, Was the Idea.
I`m not sure how to do that, though:
Have a look in plsm2 paginglandscapeTexture.cpp about how it updates texture dynamically. Not that Hard, and not that slow, specially if using updaterec as I did there.

Falagard

01-06-2006 16:38:45

The only problem with generating a mesh is terrain lods, and it's a big problem. Might also be a problem with compressed terrain? At least with projective decals you can use the same shader as the terrain is using to get decals that always match the terrain.

Speaking of which, tuan, are you lod morphing terrain on the CPU? I thought you'd be passing a parameter to the shader but that doesn't seem to be the case.

tuan kuranes

01-06-2006 16:53:02

generating a mesh is terrain lods
yes have to catch lod change, and sometimes lodmorph ca lead to problem (but on a distant terrain)
Might also be a problem with compressed terrain
getHeight is independant of compression. (not morphing)
Speaking of which, tuan, are you lod morphing terrain on the CPU? I thought eyou'd be passing a parameter to the shader but that doesn't seem to be the cas.
no morphing on CPU... but now that you raised that, it perhaps should have for getheight and so.
Morph is in GPU, a special VB hold morph info and parameter is updated per paginlandscape renderable using a special parameter hook.

sklug

17-09-2006 01:05:11

This seemed like a reasonable thread to post this in. I have done a first implementation of a decal using a mesh as mentioned might be possible above. It has some issues with parts being drawn behind the landscape still. Any suggestions would be appreciated. For now though, you can give it a height offset, which causes it to draw the decal above the terrain, to try to offset some of those problems. Also, increasing the resolution of the mesh will help, at the cost of dramatically increasing the number of ray scene queries required. In any case, this appears to be good enough for my purposes (a targetting circle). Let me know if there's any interest in posting it on the wiki, etc.:


#pragma once
#include "Ogre.h"

#include <vector>

class TerrainMeshDecal : public Ogre::MovableObject, public Ogre::Renderable
{
private:
Ogre::AxisAlignedBox AABB_;
Ogre::Real radius_;

Ogre::MaterialPtr material_;
Ogre::LightList lightList_;

Ogre::Vector3 position_;
Ogre::Vector2 size_;
Ogre::RenderOperation renderOp_;
Ogre::RaySceneQuery* rayQuery_;

std::vector<Ogre::Vector3> vertices_;

public:
TerrainMeshDecal( const Ogre::String& materialName,
const Ogre::Vector2& size,
Ogre::SceneManager& sceneMgr );
virtual ~TerrainMeshDecal();

// Main public interface
void SetSize( const Ogre::Vector2& size );

private:
void CreateGeometry();

// From MovableObject
const Ogre::String& getMovableType() const
{
static Ogre::String movType( "TerrainMeshDecal" );
return movType;
}
const Ogre::AxisAlignedBox& getBoundingBox() const
{
return AABB_;
}
Ogre::Real getBoundingRadius() const
{
return radius_;
}
void _updateRenderQueue( Ogre::RenderQueue* queue );

// From Renderable
const Ogre::MaterialPtr& getMaterial() const
{
return material_;
}
void getRenderOperation( Ogre::RenderOperation& op );
void getWorldTransforms( Ogre::Matrix4* xform ) const;
const Ogre::Quaternion& getWorldOrientation() const;
const Ogre::Vector3& getWorldPosition() const;
Ogre::Real getSquaredViewDepth( const Ogre::Camera* cam ) const;
const Ogre::LightList& getLights() const
{
return lightList_;
}
};



#include "StdAfx.h"
#include "TerrainMeshDecal.h"

using namespace Ogre;

namespace
{
const int SAMPLES_PER_AXIS = 4; // Will generate n^2 ray scene queries.
const int NUM_VERTICES = SAMPLES_PER_AXIS * SAMPLES_PER_AXIS;
const int NUM_INDICES = ( SAMPLES_PER_AXIS - 1 ) * ( SAMPLES_PER_AXIS - 1 ) * 6;
const float HEIGHT_OFFSET = 3.0;
}

TerrainMeshDecal::TerrainMeshDecal( const String& materialName, const Vector2& size, SceneManager& sceneMgr )
: position_( Vector3::ZERO )
, size_( size )
, vertices_( NUM_VERTICES )
{
material_ = MaterialManager::getSingleton().getByName( materialName );
ENFORCE( !material_.isNull() );

// Create a dummy rayQuery to avoid heap allocation every frame.
rayQuery_ = sceneMgr.createRayQuery( Ray( Vector3::ZERO, Vector3::NEGATIVE_UNIT_Y ) );
rayQuery_->setQueryTypeMask( SceneManager::WORLD_GEOMETRY_TYPE_MASK );
rayQuery_->setWorldFragmentType( SceneQuery::WFT_SINGLE_INTERSECTION );

// Allocate objects for render op.
renderOp_.vertexData = new VertexData();
renderOp_.indexData = new IndexData();

// Setup static buffers, etc.
//---------------------------

// Set some fixed values.
renderOp_.vertexData->vertexCount = NUM_VERTICES;

// Create declaration (memory format) of vertex data
VertexDeclaration* decl = renderOp_.vertexData->vertexDeclaration;
decl->addElement( 0, 0, VET_FLOAT3, VES_POSITION );
decl->addElement( 1, 0, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);

// Crate texture coords.
HardwareVertexBufferSharedPtr texbuf = HardwareBufferManager::getSingleton().
createVertexBuffer( 2 * sizeof( float ),
NUM_VERTICES,
HardwareBuffer::HBU_STATIC_WRITE_ONLY );
// Bind it.
renderOp_.vertexData->vertexBufferBinding->setBinding( 1, texbuf );

// Stuff it with our texture coords.
float* texCoords = (float*)texbuf->lock( HardwareBuffer::HBL_DISCARD );
for( int i = 0; i < SAMPLES_PER_AXIS; ++i )
{
for( int j = 0; j < SAMPLES_PER_AXIS; ++j )
{
*texCoords++ = Real( i ) / Real( SAMPLES_PER_AXIS - 1 );
*texCoords++ = 1.0 - Real( j ) / Real( SAMPLES_PER_AXIS - 1 );
}
}
texbuf->unlock();

// Create index data.
IndexData* indexData = renderOp_.indexData;
indexData->indexStart = 0;
indexData->indexCount = NUM_INDICES;

// Allocate index buffer of the requested number of vertices (ibufCount)
HardwareIndexBufferSharedPtr ibuf = HardwareBufferManager::getSingleton().
createIndexBuffer( HardwareIndexBuffer::IT_16BIT,
NUM_INDICES,
HardwareBuffer::HBU_STATIC_WRITE_ONLY );
unsigned short* indices = (unsigned short*)ibuf->lock( HardwareBuffer::HBL_DISCARD );
for( int i = 0; i < SAMPLES_PER_AXIS - 1; ++i )
{
for( int j = 0; j < SAMPLES_PER_AXIS - 1; ++j )
{
*indices++ = i * SAMPLES_PER_AXIS + j;
*indices++ = i * SAMPLES_PER_AXIS + j + 1;
*indices++ = ( i + 1 ) * SAMPLES_PER_AXIS + j;

*indices++ = ( i + 1 ) * SAMPLES_PER_AXIS + j;
*indices++ = i * SAMPLES_PER_AXIS + j + 1;
*indices++ = ( i + 1 ) * SAMPLES_PER_AXIS + j + 1;
}
}

ibuf->unlock();

// Put the hardware index buffer into our render operation object.
indexData->indexBuffer = ibuf;

CreateGeometry();
}

TerrainMeshDecal::~TerrainMeshDecal()
{
delete renderOp_.vertexData;
delete renderOp_.indexData;
}

void TerrainMeshDecal::CreateGeometry()
{
// Create translation matrix for our mesh in order to sample landscape
// heights.
Matrix4 xlate;
if( mParentNode )
getWorldTransforms( &xlate );
else
xlate = Matrix4::IDENTITY;
Matrix4 invXlate = xlate.inverse();

// Create our vertices, based on position. Use ray scene queries for
// the height component.
float dx = size_.x / ( SAMPLES_PER_AXIS - 1 );
float xOffset = -size_.x / 2;
float dz = size_.y / ( SAMPLES_PER_AXIS - 1 );
float zOffset = -size_.y / 2;
float minY = 0;
float maxY = 0;
std::vector<Vector3>::iterator it = vertices_.begin();
for( int i = 0; i < SAMPLES_PER_AXIS; ++i )
{
for( int j = 0; j < SAMPLES_PER_AXIS; ++j, ++it )
{
it->x = i * dz + zOffset;
it->y = 0;
it->z = j * dx + xOffset;

Vector3 worldVert = xlate * *it;
// Create our ray.
rayQuery_->setRay( Ray( worldVert, Vector3::NEGATIVE_UNIT_Y ) );
RaySceneQueryResult& qryResult = rayQuery_->execute();
RaySceneQueryResult::iterator queryIt = qryResult.begin();
if( queryIt != qryResult.end() && queryIt->worldFragment )
{
worldVert.y = queryIt->worldFragment->singleIntersection.y + HEIGHT_OFFSET;
}
*it = invXlate * worldVert;
// Keep track of height bounds for AABB.
if( it->y < minY )
minY = it->y;
if( it->x > maxY )
maxY = it->y;
}
}

// Create vertex data structure for 4 vertices shared between submeshes
VertexData* vertexData = renderOp_.vertexData;

// Allocate vertex buffer of the requested number of vertices (vertexCount)
// and bytes per vertex (offset)
HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton().
createVertexBuffer( 3 * sizeof( float ),
NUM_VERTICES,
// HardwareBuffer::HBU_STATIC_WRITE_ONLY );
HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE );

// Set vertex buffer binding so buffer 0 is bound to our vertex buffer
vertexData->vertexBufferBinding->setBinding( 0, vbuf );

vbuf->writeData( 0, vbuf->getSizeInBytes(), &vertices_[0], true );

// Set bounding information (for culling)
AABB_.setMinimum( Vector3( -size_.x, minY, -size_.y ) );
AABB_.setMaximum( Vector3( size_.x, maxY, size_.y ) );
radius_ = std::max( size_.x, size_.y );
}

// From Ogre::MovableObject
void TerrainMeshDecal::_updateRenderQueue( RenderQueue* queue )
{
queue->addRenderable( this, mRenderQueueID, OGRE_RENDERABLE_DEFAULT_PRIORITY );
}

// From Ogre::Renderable
void TerrainMeshDecal::getRenderOperation( Ogre::RenderOperation& op )
{
// Update our RenderOperation if necessary.
const Vector3& position = mParentNode->getWorldPosition();
if( position != position_ )
{
position_ = position;
CreateGeometry();
}
op = renderOp_;
}

void TerrainMeshDecal::getWorldTransforms( Ogre::Matrix4* xform ) const
{
*xform = mParentNode->_getFullTransform();
}

const Quaternion& TerrainMeshDecal::getWorldOrientation() const
{
return mParentNode->_getDerivedOrientation();
}

const Vector3& TerrainMeshDecal::getWorldPosition() const
{
return mParentNode->getWorldPosition();
}

Real TerrainMeshDecal::getSquaredViewDepth( const Camera* cam ) const
{
return ( getWorldPosition() - cam->getDerivedPosition() ).squaredLength();
}

tuan kuranes

18-09-2006 13:05:25

Did you try depth_bias material script option ?

Let me know if there's any interest in posting it on the wiki, etc.:
Yes, There's some interest.

Falagard

18-09-2006 16:05:01

Interesting. However, I would think that you need to actually match the vertices of the terrain in order for it to work. You don't seem to be doing that.

What I mean is that the terrain is generated on a grid, so your vertices should be created along the same grid, except for the boundary vertices, which should have vertices created where the boundary intersects the lines of the grid. This will mean that the verts will match up with the terrain and the polys won't drop below the terrain.

If we had code for this it would work for decals as well as things like roads ;-)

Here you can see the red square that is the decal, the blue dots are the verts for the decal.

sklug

18-09-2006 18:15:28

Indeed. I would like to do a new revision that does just what Falagard suggested. But wanted to get my first go at it out there for comment. It DOES work for a certain sub-set of problems, but not yet for all cases of decals. And it's pretty fast. Matching the landscape mesh has all the nasty details of how to deal with terrain LOD, etc. Any suggestions on how to quickly get at the appropriate mesh data from PLSM would be appreciated.

sklug

sklug

20-09-2006 02:45:52

So I had a few minutes last night and took a look at what it might take to do the decal using height data from PLSM2. As far as I can tell, there is no way to get a collection of map vertices from PLSM from a particular region (say, an AABB). What I suspect would be needed is a custom AABB scene query that returns vertices in the world AABB given. Once I had that info, I could probably devise some kind of mechanism to do what Falagard suggests above. I can take a crack at putting in the custom scene query, unless anyone thinks there is a better way. It might be doable, for example, if there was some way to find the vertex closest to a given x, z position. All of this will need to take LOD into consideration if it's going to work at all distances, of course.

sklug

tuan kuranes

20-09-2006 13:02:29

Sorry for late anwer, somewhat missed following the thread...

On decal following exaclty terrain, I begun some work once, and it's in demo and scenemanager, search for "getAreaSize".

Actually will transform an Area defined in global coordinates in a Area in page coordinates, andsor of gives number of vertices needed to build the Vertex Buffer.

What is left to do :
- get height for each of this vertices defined by this area. build a vertex buffer/index buffer of it. (mData2DManager->getHeightAtPage (), mData2DManager->getHeight (), etc...)

Now to do after first working previous step done :
- handle multiple page area... (could be done afterwards)
- Handle LOD, which means asking each tile concerned its LOD/stitching, and asking vertices concerned. (Harder, needs a thing like what is done in "PagingLandScapeData2DManager::getInterpolatedWorldHeight()"
- About Lod, a tile event could be bind to every Tile Lod Change so that you use correct decal/ rebuild a new one.

sklug

22-09-2006 05:58:29

Hrm, it looks like getAreaSize is broken. It doesn't return the number of vertices as the code in the demo might lead one to conclude. It seems to return the number of pages involved though.

Wouldn't it be cleaner to use the SceneQuery interface? Maybe using the WFT_CUSTOM_GEOMETRY option perhaps? I don't think it will be possible to pass the vertex buffer directly to the scene manager to fill, because I will need to do some filtering on the vertices and then add new ones at the true boundary of the area, as the vertices of the landscape may not lie exactly in the right places (probably rarely will).

sklug

tuan kuranes

26-09-2006 15:15:30

Hrm, it looks like getAreaSize is broken. It doesn't return the number of vertices as the code in the demo might lead one to conclude. It seems to return the number of pages involved though.


Sorry, didn't look over that code for a long time...

Wouldn't it be cleaner to use the SceneQuery interface? Maybe using the WFT_CUSTOM_GEOMETRY option perhaps?
That would indeed be better.

sklug

27-09-2006 02:45:22

I'm working on it. I've got code for the AABB scene query that seems to work, including handling appropriate LOD levels (at least within one page...I gotta test it across page boundaries). Now the hard part of taking that data and creating a mesh that is arbitrarily rotated in the scene, etc.

I'll keep you guys posted.

Sklug

Falagard

27-09-2006 03:55:25

I'm really really looking forward to whatever you come up with sklug. In fact, I'm counting on using it, if you'd be so kind as to share it!

Texture splatting is great, but some nice extra texture detail could be added to specific places on the terrain such as paths, small patches of grass, etc. with decals. The decals would only need to be visible when relatively close to the camera, and could fade out as the camera gets further away.

If the decal calculation is too expensive, I could actual save out the decals as a mesh to disk, stuff like that.

So, good luck and keep us updated!

sklug

02-10-2006 07:09:23

Got some time in on this over the weekend. It's definitely tricky. I've yet to come up with a satisfactory algorithm for making my mesh when it may contain different LODs for the data. But in order to try some things out, I need an easy way to force PLSM2 to start using lower LOD levels closer to my camera. From walking through the code it looks like the first kick down is quite far away (bigger than my test map, and you'd not be able to see the decal that far away anyway most likely). I looked over the options and tried to find it in the code, but was unsuccessful. I tried putting a LOD bias on the camera, but even though the code in OgrePagingLandScapeRenderable.cpp asks the camera for its LOD bias, it doesn't then seem to use it to determine the current renderLevel. There's also some dead code in _notifyCurrentCamera():


const AxisAlignedBox& aabb = getWorldBoundingBox(true);
Vector3 diff(0, 0, 0);
diff.makeFloor(cpos - aabb.getMinimum());
diff.makeCeil(cpos - aabb.getMaximum());


Nothing seems to use the diff vector or aabb anywhere else in the method.

I guess the good news is, I now can put a nice decal on in the simplest case. That's when everything is at max lod, and I'm not yet stiching in the boundary vertices (waiting til I figure out how to arbitrarily create a mesh with different LODS). Also, supporting rotated decals will be an additional challenge, though not as hard as doing the multi-lod meshing.

So, what's the magic config option to change LOD ? I can't figure out if DistanceLOD does anything.

sklug

tuan kuranes

02-10-2006 20:27:59

Thanks for the code bloat finding, I'll clean that.
It not possible right now, as lod is based on distance AND tile "roughness".

You'll have to compose with LOD and/or get LOD events and rebuild decals if needed.

tuan kuranes

03-10-2006 16:20:59

Finally I backported a plsm3 option. now PLSM3 can have tile LOD based on distance only.
so It's in CVS only, and you need to add
RoughnessLod=no
in the terrain config file.

Falagard

03-10-2006 18:07:16

So what exactly does this setting do, Tuan? Doesn't use pixel error anymore and just LODs based on distance?

Does this mean that sklug can know exactly what vertices are visible for a particular tile? I assume the tile seams still have to stitch together?

The pixel error thing was a bit of a problem for me because distant pages were sometimes showing a pretty high level of detail at times, so this might be a good option. Nice work :-)

tuan kuranes

03-10-2006 19:55:53

DistanceLOD=4
RoughnessLod=no

makes it use "4 tiles" as the distance between first and second lod.
Then each next level is DistanceLOD *= DistanceLOD;

so if distance of 4 tiles is 10
lod=0 => distance = 0
lod=1 => distance = 10
lod=2 => distance = 100
lod=3 => distance = 1000
lod=4 => distance = 10000
etc...

ps: in code, it does the same but always using squaredistance to save computations.

sklug

05-11-2006 00:53:17

Hi guys! Sorry it's been so long. I haven't had as much time to work on this lately. Here's where I'm at. I have the decals drawing with LOD, etc. I do not have them hooked up so they automatically update when their LOD changes (unless there was some other reason to re-create them). Tuan hinted at some kind of LOD events? I didn't see any currently in PLSM2. Is this a feature that exists? Or were you implying that I'd also need to implement some kind of LOD delegates? I can certainly do this if need be, but don't want to re-invent the wheel.

Speaking of re-inventing the wheel. I'm not super happy with the way I ended up doing the decals. They seem to work great. They're reasonably fast (though there's several areas they could be optimized...some of which I've noted in the comments). What is a little smelly is that I split the work up between a new custom axis aligned bounding box scene query I added to PLSM, and the code in the TerrainMeshDecal class. The scene query basically returns sub-sections of tiles, so that the TerrainMeshDecal class can stitch them up the same way PLSM does. The problem with this is that there's a lot of semi-duplicated code in TerrainMeshDecal in order to stitch like PLSM does. It's not identical, as PLSM does everything on a per-tile basis, not non-uniform tile sub-sections. But it's pretty close. A nice refactoring would be to put the whole thing inside PLSM. However, as the whole mechanism for stitching geometry is likely changing quite a bit for PLSM3, it seems like not worth the effort at this time. Perhaps Tuan and I can chat about how it might all be better done for PLSM3, as it's a very very useful feature.

That said, I'm probably pretty close to wanting to submit this thing to everyone. So how do I do that? Especially since it entails an addition to PLSM itself?

tuan kuranes

05-11-2006 13:07:23

Tuan hinted at some kind of LOD events? I didn't see any currently in PLSM2.
I'll add them asap. event lod will look likes actual tile load event for instance.
However, as the whole mechanism for stitching geometry is likely changing quite a bit for PLSM3, it seems like not worth the effort at this time.
mmm not planned or in todo to change any part of the stitching algo.
Perhaps Tuan and I can chat about how it might all be better done for PLSM3, as it's a very very useful feature.
Indeed, let me understand fully your submission, and we'll start a new thread on that. (other uses may want to join)
That said, I'm probably pretty close to wanting to submit this thing to everyone. So how do I do that? Especially since it entails an addition to PLSM itself?
At first use cvs/tortoisecvs to create a patch against latest cvs version of plsm2. Then, best is to submit the patch on Ogre sourceforge tracker, otherwise you can send it by mail to me.

sklug

05-11-2006 17:20:33

Ok, let me know when there are some LOD events to hook up to, and I'll put that in.

I'll lookup how to submit stuff on sourceforge, and if I have any trouble, I'll just email you the files.

sklug

sklug

11-11-2006 18:38:59

Any word on getting LOD events in place? Should be the last thing I'll need to make the decals fully usable.

sklug

davesh

13-11-2006 13:45:42

I'm really really looking forward to whatever you come up with sklug. In fact, I'm counting on using it, if you'd be so kind as to share it!


Very much agreed!

jacmoe

13-11-2006 18:19:35

I'm really really looking forward to whatever you come up with sklug. In fact, I'm counting on using it, if you'd be so kind as to share it!


Very much agreed!


I am thirding that! This is useful as useful can get! :)

sklug

14-11-2006 05:00:50

Posted a patch, though there's at least one PLSM2 patch ahead of it in the queue. Looks like Tuan hasn't been around. :( It still needs to be hooked into LOD events, but some folks were asking to take a look at what I had.

I'll work on a wiki page explaining how to use it. Hopefully it will meet people's needs. I'm pretty new to graphics programming, so commentary is welcome to make it better. I'll post the wiki link here when I get a chance to complete it (definitely this week).

sklug

sklug

27-11-2006 00:28:52

So, anyone heard from Tuan? I hope he's ok. I guess since the patches aren't being applied, I could post the files to these forums for those chomping at the bit to use them. What do you guys think?

--sklug

tuan kuranes

29-11-2006 17:23:52

Patch in CVS. Will add a Decal Demo asap.

tulio

14-12-2006 22:21:53

hey guys...

is this demo available already?

tuan kuranes

15-12-2006 15:12:08

sadly not, I have a pretty high bug list fix before I can tackle that. If one want to do that, now that it's inside PLSM2, I won't be against (specially if using same common headers as demo, so that It ease maintenance afterwards.)

sklug

16-12-2006 03:21:25

It doesn't appear that you checked in the application side code (TerrainMeshDecal.*), so I should probably get off my rear-end and write the Wiki page I said I'd write, as that would be the place for it I imagine. You'll need that app side code to really use the new AxisAlignedBoundingBoxSceneQuery to implement a decal, though there's nothing too hard about the code.

I'm on vacation, so hopefully I'll get a chance to put up the wiki page amidst all the other ambitious plans I have for my vacation. :)

sklug

sklug

20-12-2006 17:17:30

As I've been learning more about the architecture of Ogre, I think I've figured a way to organize the decal code to place it inside PLSM. I believe this will make it easier to use, and later allow some internal optimization and code re-use in the decal code (for a later time). I'm going to try it and see how I like it and post another patch if it works out. Just to let anyone who might be looking at using it know. Should be done today or tomorrow if things go well.

sklug

sklug

21-12-2006 01:59:35

Ok, Tuan. There's a new patch waiting for you. It should make explaining how to use the decals much easier.

sklug

tuan kuranes

21-12-2006 14:28:39

added in CVS. still have to update VS8 project files.

sklug

21-12-2006 18:18:55

As promised, I've added a wiki page (and reorganized slightly the section on decals). Here's the new page:

http://www.ogre3d.org/wiki/index.php/Mesh_Decals

sklug

kungfoomasta

23-12-2006 04:09:57

Hey Sklug,

I just grabbed latest from CVS and compiled and got some errors compiling PLSM2, they look related to decals:


1>------ Build started: Project: Plugin_PagingLandScapeSceneManager2, Configuration: Debug Win32 ------
1>Linking...
1> Creating library ..\bin\Debug/Plugin_PagingLandScapeSceneManager2_d.lib and object ..\bin\Debug/Plugin_PagingLandScapeSceneManager2_d.exp
1>OgrePagingLandScapeSceneManager.obj : error LNK2001: unresolved external symbol "protected: virtual class Ogre::MovableObject * __thiscall Ogre::PagingLandScapeMeshDecalFactory::createInstanceImpl(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,class std::map<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,struct std::less<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >,class std::allocator<struct std::pair<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const ,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > > > const *)" (?createInstanceImpl@PagingLandScapeMeshDecalFactory@Ogre@@MAEPAVMovableObject@2@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@PBV?$map@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V12@U?$less@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@V?$allocator@U?$pair@$$CBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V12@@std@@@2@@5@@Z)
1>OgrePagingLandScapeSceneManager.obj : error LNK2001: unresolved external symbol "public: virtual class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const & __thiscall Ogre::PagingLandScapeMeshDecalFactory::getType(void)const " (?getType@PagingLandScapeMeshDecalFactory@Ogre@@UBEABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ)
1>OgrePagingLandScapeSceneManager.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall Ogre::PagingLandScapeMeshDecalFactory::destroyInstance(class Ogre::MovableObject *)" (?destroyInstance@PagingLandScapeMeshDecalFactory@Ogre@@UAEXPAVMovableObject@2@@Z)
1>..\bin\Debug/Plugin_PagingLandScapeSceneManager2_d.dll : fatal error LNK1120: 3 unresolved externals
1>Build log was saved at "file://d:\ogreaddons\paginglandscape\PlugIns\PagingLandScape2\obj\Debug\BuildLog.htm"
1>Plugin_PagingLandScapeSceneManager2 - 4 error(s), 0 warning(s)


I'm using 1.2.4 SDK and CVS ogreaddons/paginglandscape module.
Any ideas how I can fix this?

Thanks

KungFooMasta

sklug

23-12-2006 06:45:25

I suspect, if it's like last time, the decals weren't included in the project. Make sure to add OgrePagingLandScapeMeshDecal.cpp and .h into the PLSM project. I'm not sure why those changes aren't making it into CVS, as I'm including the patch to the .vcproj. Maybe it's a VC8 vs older VC issue? What compiler are you using?

Also make sure OgrePagingLandScapeAxisAlignedBoxSceneQuery.cpp and .h are in the project, though those should have been added with my last patch.

sklug

kungfoomasta

23-12-2006 09:38:14

I'm using VC8. I'll give it a shot tomorrow and post the results.

Thanks!

KungFooMasta

[edit] I've been lazy to try this out, since I got around it by getting CVS right before Tuan submitted your files :oops: Anybody else able to compile latest CVS? [/edit]