1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-22 15:23:58 +00:00

Implemented slightly better texture splatting

This commit is contained in:
Jacob Essex 2012-03-02 20:27:20 +00:00
parent 461ec9f3d6
commit 3ecc427b96
2 changed files with 90 additions and 88 deletions

View file

@ -31,7 +31,7 @@ namespace MWRender
static_cast<TerrainMaterialGeneratorB::SM2Profile*>(activeProfile);
mTerrainGlobals->setMaxPixelError(8);
mTerrainGlobals->setLayerBlendMapSize(SPLIT_TERRAIN ? 256 : 1024);
mTerrainGlobals->setLayerBlendMapSize(SPLIT_TERRAIN ? 32 : 1024);
mTerrainGlobals->setLightMapSize(SPLIT_TERRAIN ? 256 : 1024);
mTerrainGlobals->setCompositeMapSize(SPLIT_TERRAIN ? 256 : 1024);
mTerrainGlobals->setDefaultGlobalColourMapSize(256);
@ -255,15 +255,29 @@ namespace MWRender
fromY+size <= ESM::Land::LAND_TEXTURE_SIZE &&
"Can't get a terrain texture on terrain outside the current cell");
//there is one texture that we want to use as a base (i.e. it won't have
//a blend map). This holds the ltex index of that base texture so that
//we know not to include it in the output map
int baseTexture = -1;
//this ensures that the ltex indexes are sorted (or retrived as sorted
//which simplifies shading between cells).
//
//If we don't sort the ltex indexes, the splatting order may differ between
//cells which may lead to inconsistent results when shading between cells
std::set<uint16_t> ltexIndexes;
for ( int y = fromY - 1; y < fromY + size + 1; y++ )
{
for ( int x = fromX - 1; x < fromX + size + 1; x++ )
{
const uint16_t ltexIndex = getLtexIndexAt(store, x, y);
ltexIndexes.insert(getLtexIndexAt(store, x, y));
}
}
//there is one texture that we want to use as a base (i.e. it won't have
//a blend map). This holds the ltex index of that base texture so that
//we know not to include it in the output map
int baseTexture = -1;
for ( std::set<uint16_t>::iterator iter = ltexIndexes.begin();
iter != ltexIndexes.end();
++iter )
{
const uint16_t ltexIndex = *iter;
//this is the base texture, so we can ignore this at present
if ( ltexIndex == baseTexture )
{
@ -314,7 +328,6 @@ namespace MWRender
}
}
}
}
//----------------------------------------------------------------------------------------------
@ -335,8 +348,8 @@ namespace MWRender
//that need to result in an integer for correct splatting
assert( (size & (size - 1)) == 0 && "Size must be a power of 2");
const int blendSize = terrain->getLayerBlendMapSize();
const int blendDist = TERRAIN_SHADE_DISTANCE * (blendSize / size);
const int blendMapSize = terrain->getLayerBlendMapSize();
const int splatSize = blendMapSize / size;
//zero out every map
std::map<uint16_t, int>::const_iterator iter;
@ -344,7 +357,7 @@ namespace MWRender
{
float* pBlend = terrain->getLayerBlendMap(iter->second)
->getBlendPointer();
memset(pBlend, 0, sizeof(float) * blendSize * blendSize);
memset(pBlend, 0, sizeof(float) * blendMapSize * blendMapSize);
}
//covert the ltex data into a set of blend maps
@ -354,11 +367,6 @@ namespace MWRender
{
const uint16_t ltexIndex = getLtexIndexAt(store, texX, texY);
//whilte texX is the splat index relative to the entire cell,
//relX is relative to the current segment we are splatting
const int relX = texX - fromX;
const int relY = texY - fromY;
//check if it is the base texture (which isn't in the map) and
//if it is don't bother altering the blend map for it
if ( indexes.find(ltexIndex) == indexes.end() )
@ -366,45 +374,45 @@ namespace MWRender
continue;
}
//while texX is the splat index relative to the entire cell,
//relX is relative to the current segment we are splatting
const int relX = texX - fromX;
const int relY = texY - fromY;
const int layerIndex = indexes.find(ltexIndex)->second;
float* const pBlend = terrain->getLayerBlendMap(layerIndex)
->getBlendPointer();
const int splatSize = blendSize / size;
for ( int y = -1; y < splatSize + 1; y++ ){
for ( int x = -1; x < splatSize + 1; x++ ){
//setup the bounds for the shading of this texture splat
const int startX = std::max(0, relX*splatSize - blendDist);
const int endX = std::min(blendSize, (relX+1)*splatSize + blendDist);
//Note: Y is reversed
const int splatY = blendMapSize - 1 - relY * splatSize - y;
const int splatX = relX * splatSize + x;
const int startY = std::max(0, relY*splatSize - blendDist);
const int endY = std::min(blendSize, (relY+1)*splatSize + blendDist);
for ( int blendX = startX; blendX < endX; blendX++ )
if ( splatX >= 0 && splatX < blendMapSize &&
splatY >= 0 && splatY < blendMapSize )
{
for ( int blendY = startY; blendY < endY; blendY++ )
{
assert(blendX >= 0 && blendX < blendSize &&
"index must be within texture bounds");
const int index = (splatY)*blendMapSize + splatX;
assert(blendY >= 0 && blendY < blendSize &&
"index must be within texture bounds");
const int index = blendSize*(blendSize - 1 - blendY) + blendX;
if ( blendX >= relX*splatSize && blendX < (relX+1)*splatSize &&
blendY >= relY*splatSize && blendY < (relY+1)*splatSize )
if ( y >= 0 && y < splatSize &&
x >= 0 && x < splatSize )
{
pBlend[index] = 1;
}
else
{
pBlend[index] = std::max((float)pBlend[index], 0.5f);
}
//this provides a transition shading but also
//rounds off the corners slightly
pBlend[index] = std::min(1.0f, pBlend[index] + 0.5f);
}
}
}
}
}
}
for ( int i = 1; i < terrain->getLayerCount(); i++ )
{

View file

@ -61,12 +61,6 @@ namespace MWRender{
*/
int mRealSize;
/**
* The distance that the current cell should be shaded into the neighbouring
* texture. The distance is in terms of the splat size of a texture
*/
static const float TERRAIN_SHADE_DISTANCE = 0.25f;
/**
* Setups up the list of textures for part of a cell, using indexes as
* an output to create a mapping of MW LtexIndex to the relevant terrain