mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-22 19:23:52 +00:00
Implemented slightly better texture splatting
This commit is contained in:
parent
461ec9f3d6
commit
3ecc427b96
2 changed files with 90 additions and 88 deletions
|
@ -31,7 +31,7 @@ namespace MWRender
|
||||||
static_cast<TerrainMaterialGeneratorB::SM2Profile*>(activeProfile);
|
static_cast<TerrainMaterialGeneratorB::SM2Profile*>(activeProfile);
|
||||||
|
|
||||||
mTerrainGlobals->setMaxPixelError(8);
|
mTerrainGlobals->setMaxPixelError(8);
|
||||||
mTerrainGlobals->setLayerBlendMapSize(SPLIT_TERRAIN ? 256 : 1024);
|
mTerrainGlobals->setLayerBlendMapSize(SPLIT_TERRAIN ? 32 : 1024);
|
||||||
mTerrainGlobals->setLightMapSize(SPLIT_TERRAIN ? 256 : 1024);
|
mTerrainGlobals->setLightMapSize(SPLIT_TERRAIN ? 256 : 1024);
|
||||||
mTerrainGlobals->setCompositeMapSize(SPLIT_TERRAIN ? 256 : 1024);
|
mTerrainGlobals->setCompositeMapSize(SPLIT_TERRAIN ? 256 : 1024);
|
||||||
mTerrainGlobals->setDefaultGlobalColourMapSize(256);
|
mTerrainGlobals->setDefaultGlobalColourMapSize(256);
|
||||||
|
@ -255,62 +255,75 @@ namespace MWRender
|
||||||
fromY+size <= ESM::Land::LAND_TEXTURE_SIZE &&
|
fromY+size <= ESM::Land::LAND_TEXTURE_SIZE &&
|
||||||
"Can't get a terrain texture on terrain outside the current cell");
|
"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
|
//this ensures that the ltex indexes are sorted (or retrived as sorted
|
||||||
//a blend map). This holds the ltex index of that base texture so that
|
//which simplifies shading between cells).
|
||||||
//we know not to include it in the output map
|
//
|
||||||
int baseTexture = -1;
|
//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 y = fromY - 1; y < fromY + size + 1; y++ )
|
||||||
{
|
{
|
||||||
for ( int x = fromX - 1; x < fromX + size + 1; x++ )
|
for ( int x = fromX - 1; x < fromX + size + 1; x++ )
|
||||||
{
|
{
|
||||||
const uint16_t ltexIndex = getLtexIndexAt(store, x, y);
|
ltexIndexes.insert(getLtexIndexAt(store, x, y));
|
||||||
//this is the base texture, so we can ignore this at present
|
}
|
||||||
if ( ltexIndex == baseTexture )
|
}
|
||||||
|
|
||||||
|
//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 )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::map<uint16_t, int>::const_iterator it = indexes.find(ltexIndex);
|
||||||
|
|
||||||
|
if ( it == indexes.end() )
|
||||||
|
{
|
||||||
|
//NB: All vtex ids are +1 compared to the ltex ids
|
||||||
|
|
||||||
|
assert( (int)store->landTextures->ltex.size() >= (int)ltexIndex - 1 &&
|
||||||
|
"LAND.VTEX must be within the bounds of the LTEX array");
|
||||||
|
|
||||||
|
std::string texture;
|
||||||
|
if ( ltexIndex == 0 )
|
||||||
{
|
{
|
||||||
continue;
|
texture = "_land_default.dds";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
texture = store->landTextures->ltex[ltexIndex-1].texture;
|
||||||
|
//TODO this is needed due to MWs messed up texture handling
|
||||||
|
texture = texture.substr(0, texture.rfind(".")) + ".dds";
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<uint16_t, int>::const_iterator it = indexes.find(ltexIndex);
|
const size_t position = terrainData->layerList.size();
|
||||||
|
terrainData->layerList.push_back(Ogre::Terrain::LayerInstance());
|
||||||
|
|
||||||
if ( it == indexes.end() )
|
Ogre::TexturePtr normDisp = getNormalDisp("textures\\" + texture);
|
||||||
|
|
||||||
|
terrainData->layerList[position].worldSize = 256;
|
||||||
|
terrainData->layerList[position].textureNames.push_back("textures\\" + texture);
|
||||||
|
|
||||||
|
//Normal map. This should be removed but it would require alterations to
|
||||||
|
//the material generator. Another option would be to use a 1x1 blank texture
|
||||||
|
//terrainData->layerList[position].textureNames.push_back(normDisp->getName());
|
||||||
|
|
||||||
|
if ( baseTexture == -1 )
|
||||||
{
|
{
|
||||||
//NB: All vtex ids are +1 compared to the ltex ids
|
baseTexture = ltexIndex;
|
||||||
|
}
|
||||||
assert( (int)store->landTextures->ltex.size() >= (int)ltexIndex - 1 &&
|
else
|
||||||
"LAND.VTEX must be within the bounds of the LTEX array");
|
{
|
||||||
|
indexes[ltexIndex] = position;
|
||||||
std::string texture;
|
|
||||||
if ( ltexIndex == 0 )
|
|
||||||
{
|
|
||||||
texture = "_land_default.dds";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
texture = store->landTextures->ltex[ltexIndex-1].texture;
|
|
||||||
//TODO this is needed due to MWs messed up texture handling
|
|
||||||
texture = texture.substr(0, texture.rfind(".")) + ".dds";
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t position = terrainData->layerList.size();
|
|
||||||
terrainData->layerList.push_back(Ogre::Terrain::LayerInstance());
|
|
||||||
|
|
||||||
Ogre::TexturePtr normDisp = getNormalDisp("textures\\" + texture);
|
|
||||||
|
|
||||||
terrainData->layerList[position].worldSize = 256;
|
|
||||||
terrainData->layerList[position].textureNames.push_back("textures\\" + texture);
|
|
||||||
|
|
||||||
//Normal map. This should be removed but it would require alterations to
|
|
||||||
//the material generator. Another option would be to use a 1x1 blank texture
|
|
||||||
//terrainData->layerList[position].textureNames.push_back(normDisp->getName());
|
|
||||||
|
|
||||||
if ( baseTexture == -1 )
|
|
||||||
{
|
|
||||||
baseTexture = ltexIndex;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
indexes[ltexIndex] = position;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -335,8 +348,8 @@ namespace MWRender
|
||||||
//that need to result in an integer for correct splatting
|
//that need to result in an integer for correct splatting
|
||||||
assert( (size & (size - 1)) == 0 && "Size must be a power of 2");
|
assert( (size & (size - 1)) == 0 && "Size must be a power of 2");
|
||||||
|
|
||||||
const int blendSize = terrain->getLayerBlendMapSize();
|
const int blendMapSize = terrain->getLayerBlendMapSize();
|
||||||
const int blendDist = TERRAIN_SHADE_DISTANCE * (blendSize / size);
|
const int splatSize = blendMapSize / size;
|
||||||
|
|
||||||
//zero out every map
|
//zero out every map
|
||||||
std::map<uint16_t, int>::const_iterator iter;
|
std::map<uint16_t, int>::const_iterator iter;
|
||||||
|
@ -344,7 +357,7 @@ namespace MWRender
|
||||||
{
|
{
|
||||||
float* pBlend = terrain->getLayerBlendMap(iter->second)
|
float* pBlend = terrain->getLayerBlendMap(iter->second)
|
||||||
->getBlendPointer();
|
->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
|
//covert the ltex data into a set of blend maps
|
||||||
|
@ -354,11 +367,6 @@ namespace MWRender
|
||||||
{
|
{
|
||||||
const uint16_t ltexIndex = getLtexIndexAt(store, texX, texY);
|
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
|
//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 it is don't bother altering the blend map for it
|
||||||
if ( indexes.find(ltexIndex) == indexes.end() )
|
if ( indexes.find(ltexIndex) == indexes.end() )
|
||||||
|
@ -366,43 +374,43 @@ namespace MWRender
|
||||||
continue;
|
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;
|
const int layerIndex = indexes.find(ltexIndex)->second;
|
||||||
|
|
||||||
float* const pBlend = terrain->getLayerBlendMap(layerIndex)
|
float* const pBlend = terrain->getLayerBlendMap(layerIndex)
|
||||||
->getBlendPointer();
|
->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
|
//Note: Y is reversed
|
||||||
const int startX = std::max(0, relX*splatSize - blendDist);
|
const int splatY = blendMapSize - 1 - relY * splatSize - y;
|
||||||
const int endX = std::min(blendSize, (relX+1)*splatSize + blendDist);
|
const int splatX = relX * splatSize + x;
|
||||||
|
|
||||||
const int startY = std::max(0, relY*splatSize - blendDist);
|
if ( splatX >= 0 && splatX < blendMapSize &&
|
||||||
const int endY = std::min(blendSize, (relY+1)*splatSize + blendDist);
|
splatY >= 0 && splatY < blendMapSize )
|
||||||
|
|
||||||
for ( int blendX = startX; blendX < endX; blendX++ )
|
|
||||||
{
|
|
||||||
for ( int blendY = startY; blendY < endY; blendY++ )
|
|
||||||
{
|
|
||||||
assert(blendX >= 0 && blendX < blendSize &&
|
|
||||||
"index must be within texture bounds");
|
|
||||||
|
|
||||||
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 )
|
|
||||||
{
|
{
|
||||||
pBlend[index] = 1;
|
const int index = (splatY)*blendMapSize + splatX;
|
||||||
}
|
|
||||||
else
|
if ( y >= 0 && y < splatSize &&
|
||||||
{
|
x >= 0 && x < splatSize )
|
||||||
pBlend[index] = std::max((float)pBlend[index], 0.5f);
|
{
|
||||||
|
pBlend[index] = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//this provides a transition shading but also
|
||||||
|
//rounds off the corners slightly
|
||||||
|
pBlend[index] = std::min(1.0f, pBlend[index] + 0.5f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,12 +61,6 @@ namespace MWRender{
|
||||||
*/
|
*/
|
||||||
int mRealSize;
|
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
|
* 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
|
* an output to create a mapping of MW LtexIndex to the relevant terrain
|
||||||
|
|
Loading…
Reference in a new issue