Splatting with Dynamic Textures

bymulker

11-10-2008 14:58:59

hi everyone ,

With all the limits of my graphics card , i've been looking forward to do splatting by modifying the material of the terrain. This way i one would organize splat textures dynamically. I first began by color painting. It works great ;


void EditableTerrain::ColorPaint(int x, int z, float intensity)
{
if(!m_paintBox)
return;

Ogre::Pass* splatPass = mTerrainMgr->getMaterial()->getTechnique(0)->getPass(0);
Ogre::TexturePtr tex = splatPass->getTextureUnitState(0)->_getTexturePtr();
HardwarePixelBufferSharedPtr buffer = tex->getBuffer();

float x_padding = m_paintBox->getWidth() * 0.5f;
float z_padding = m_paintBox->getHeight() * 0.5f;

int v1 = z - z_padding;
int v2 = z + z_padding;
int u1 = x - x_padding;
int u2 = x + x_padding;

u1 = u1 < 0 ? 0 : u1;
v1 = v1 < 0 ? 0 : v1;

Ogre::Image::Box wbox(u1, v1, u2, v2);

if(wbox.getWidth() == m_paintBox->getWidth() &&
wbox.getHeight() == m_paintBox->getHeight())
{

const Ogre::PixelBox& pbox = buffer->lock(wbox, Ogre::HardwareBuffer::HBL_DISCARD);

PixelUtil::bulkPixelConversion(*m_paintBox, pbox);

buffer->unlock();

}


}

void EditableTerrain::createEditBrush(Ogre::ColourValue& color, int width, int height)
{
ET::TerrainInfo info = mTerrainMgr->getTerrainInfo();

Ogre::Pass* splatPass = mTerrainMgr->getMaterial()->getTechnique(0)->getPass(0);
Ogre::TexturePtr tex = splatPass->getTextureUnitState(0)->_getTexturePtr();
HardwarePixelBufferSharedPtr buffer = tex->getBuffer();
Ogre::PixelFormat pf = tex->getSrcFormat();

Ogre::Image::Box box(0, 0, width, height);

if(m_paintBox)
{
delete m_paintBox->data;
delete m_paintBox;
}

m_paintBox = new PixelBox(box, pf);

m_paintBox->data = new uchar[ box.getWidth()* box.getHeight() * PixelUtil::getNumElemBytes(pf) ];

for (size_t j = box.left; j < box.right; j++)
for(size_t i = box.top; i < box.bottom; i++)
{
Ogre::Image::Box wbox(j, i, j, i);
PixelUtil::packColour(color, pf, m_paintBox->getSubVolume(wbox).data);
}


}


THis is also useful for showing navigation meshes, a* path debugging, blood splatting etc.

When it comes to texture splatting i fail for i only get a 8x8 greeny texture on the terrain ;


void EditableTerrain::paint(unsigned int textureNum, int x, int y, float intensity)
{
Ogre::Pass* splatPass = mTerrainMgr->getMaterial()->getTechnique(0)->getPass(0);
Ogre::TexturePtr tex = splatPass->getTextureUnitState(0)->_getTexturePtr();
HardwarePixelBufferSharedPtr buffer = tex->getBuffer();
Ogre::PixelFormat pf = tex->getSrcFormat();

size_t bytenum = PixelUtil::getNumElemBytes(pf);

float x_padding = mEditBrush.getWidth() * 0.5f;
float z_padding = mEditBrush.getHeight() * 0.5f;

int v1 = y - z_padding;
int v2 = y + z_padding;
int u1 = x - x_padding;
int u2 = x + x_padding;

u1 = u1 < 0 ? 0 : u1;
v1 = v1 < 0 ? 0 : v1;

Ogre::Image::Box wbox(u1, v1, u2, v2);

if(wbox.getWidth() == mEditBrush.getWidth() &&
wbox.getHeight() == mEditBrush.getHeight())
{
Ogre::PixelBox* pb = mSplatMgr->paint2(textureNum, m_textures, x, y, mEditBrush, intensity);

const Ogre::PixelBox& pbox = buffer->lock(wbox, Ogre::HardwareBuffer::HBL_DISCARD);

PixelUtil::bulkPixelConversion(*pb, pbox);

buffer->unlock();

delete pb->data;
delete pb;

}




}



and i made a small addon to ETM 2.3.1 -> paint2 function

Ogre::PixelBox* SplattingManager::paint2(unsigned int textureNum, Ogre::ImagePtrList textures, int x, int y, const Brush& brush,
float intensity)
{
Ogre::ColourValue val;
uint texture;
Ogre::Image* img;
ET::Impl::CoverageMap* cov_map;

paint(textureNum, x, y, brush, intensity, false);

img = textures[0];
Ogre::Image::Box box(0, 0, brush.getWidth(), brush.getHeight());
Ogre::PixelBox* writebox = new PixelBox(box, img->getFormat());
writebox->data = new uchar[brush.getWidth()* brush.getHeight() * 4];

for(Ogre::ImagePtrList::iterator ix = textures.begin(); ix != textures.end(); ix++)
{
img = *ix;
img->resize(128, 128);
}

for (size_t i = box.left; i < box.right; i++)
{
for (size_t j = box.top; j < box.bottom; j++)
{
val = ColourValue::ZERO;
texture = -1;

for(Ogre::ImagePtrList::iterator ix = textures.begin(); ix != textures.end(); ix++)
{
texture += 1;
img = *ix;

uint cov_map_ind = texture / mImpl->channels;
cov_map = mImpl->maps[cov_map_ind];

uint channel = texture % mImpl->channels;

Ogre::ColourValue imgcol = img->getColourAt((uint)(x+i), (uint)(y+j), 0);
float cov_val = (float) (cov_map->getValue((uint)(i), (uint)(j), channel) / 255);
Ogre::ColourValue final = imgcol * cov_val;

val += final;

}

Ogre::Image::Box wbox(j, i, j, i);
PixelUtil::packColour(val, img->getFormat(), writebox->getSubVolume(wbox).data);

}
}

return writebox;

}


Here i 'paint'. This adjusts the coverage maps. Then i tend to do whats in the shaders. The implementation is too straightforward.Does someone have any suggestions??

CABAListic

11-10-2008 16:13:34

Can you please explain what exactly it is you want to do. I dislike having to step through code I don't even know what it's intended to do ;)

bymulker

12-10-2008 15:19:03

The post was written in a rush, sorry.

Currently ETM - 2.3.1 doesnt support color painting. Also splatting through shaders isnt too user friendly for me especially if you have i.e. 16 textures etc. and poor graphics card. I've read version 3.0 development thread and you've began to write a shader maker utility code. Great news indeed! :) I just thought i could do both of them by just dynamic textures, modifying materials. These textures might be more than one to achieve different layers for different materials (Grass, rock etc.) For the beginning i just tried to achieve it on one texture.
Now, color painting is just a memory copying and i did it successfully and put it here (first code block) thinking ppl might use it for different goals (i.e. AI, path finding etc.) Converting PSSplat2.cg to dynamic textures is a story of failure anyway.
I'm not a pro but isnt a shader generator open to many possible bugs? Might be many incompatibilities.. i dont know.

In paint2 function i paint as usual but dont send it to the pipeline by a false option. I've modified

// finally, update the textures
mImpl->updateTextures();

to

// finally, update the textures
if(updateBuffer)
mImpl->updateTextures();


This way i make sure that the coverage maps are 'painted' but not sent to the pipeline yet. Then i loop through the textures (splatting0, splatting1 etc.) and multiply the color in the range of the brush with the corresponding rgb with proper channel imitating PSSplat2.cg .. nothing more. I just get a green square on the mouse coordinates not a mixing textures..splatting effect. I'm getting a pixelbox of splatted area by paint2 function and send it to the pipeline in Editable terrains paint function.
Finally i hate 'whats wrong in my code' style questions. I just thought i could find an easy and dirty way of splatting by one pass, one texture. thanks for any recommendations :)

CABAListic

12-10-2008 16:10:06

Oh wait, are you trying to emulate what real splatting does, i. e. create a texture which statically contains what splatting would otherwise do in realtime? So you want a texture which contains the combined layout so that you only have to render that texture on the terrain instead of actually splatting it.

Well, first of all I have to warn you that this will look kind of ugly. Sizes of textures are limited, and therefore one single texture laid over the whole terrain will never look quite convincing. In fact, that's the whole reason why splatting was invented in the first place ;)

Second, the SplattingManager already has a function to generate just such a texture (image, rather), see SplattingManager::createBaseTexture. However, it's potentially slow and not made for realtime-editing.

As for the shader generator: If your graphics card is too weak to handle realtime splatting, then it won't help you much. Still, the pattern of splatting shaders are relatively simple, so once I've verified their working for each supported shader model, there is only little room for bugs.

bymulker

13-10-2008 07:51:19

Thanks for your kind answer. It was rather convincing. I think i'll have to go further reading about shaders.

SongOfTheWeave

14-10-2008 07:11:41

I recommend a new graphics card. Here's a dirt cheap Nvidia 8400 for $26 after mail in rebate. It's really a very low end 8400, but... $26!

http://www.newegg.com/Product/Product.a ... 6814130316

Note: Posted on 10/14/2008, dunno how long this link will still be good or the price relevant.

bymulker

14-10-2008 07:45:43

hey its a kick-a..s price to promote from shader 2.0 to 4.0 and directx 10.1. :) Thank you very much. (a quick search : Radeon HD 3450 is 49$ btw)
I'm impatient to see some shadows on my dynamically editable terrain ver.3.0!! ;).

jjp

14-10-2008 08:40:23

I recommend a new graphics card. Here's a dirt cheap Nvidia 8400 for $26 after mail in rebate. It's really a very low end 8400, but... $26!

Never ever buy that card! ;) The ultra-lowend class has a very bad performance to cost ratio. It is always wiser to spend a little bit more money.

Seriously, it is entirely possible that an 8400 won't do much good even for relativly simple stuff like the splatting shaders at a normal screen resolution. At least get something like a Geforce 8600 or a Radeon 3650. That still isn't the sweet spot for performance/price but at least these cards are somewhat usable.