1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-16 11:49:56 +00:00

Merge branch 'terrain' of https://github.com/Yacoby/openmw into terrain_next

Conflicts:
	apps/openmw/mwrender/terrain.cpp
This commit is contained in:
scrawl 2012-02-29 19:38:34 +01:00
commit bac7f23604
3 changed files with 128 additions and 64 deletions

View file

@ -17,9 +17,6 @@ namespace MWRender
{ {
mTerrainGlobals = OGRE_NEW Ogre::TerrainGlobalOptions(); mTerrainGlobals = OGRE_NEW Ogre::TerrainGlobalOptions();
mTerrainGlobals->setMaxPixelError(8);
mTerrainGlobals->setLayerBlendMapSize(SPLIT_TERRAIN ? 256 : 1024);
Ogre::TerrainMaterialGeneratorPtr matGen; Ogre::TerrainMaterialGeneratorPtr matGen;
TerrainMaterialGeneratorB* matGenP = new TerrainMaterialGeneratorB(); TerrainMaterialGeneratorB* matGenP = new TerrainMaterialGeneratorB();
matGen.bind(matGenP); matGen.bind(matGenP);
@ -31,12 +28,27 @@ namespace MWRender
TerrainMaterialGeneratorB::SM2Profile* matProfile = TerrainMaterialGeneratorB::SM2Profile* matProfile =
static_cast<TerrainMaterialGeneratorB::SM2Profile*>(activeProfile); static_cast<TerrainMaterialGeneratorB::SM2Profile*>(activeProfile);
mTerrainGlobals->setMaxPixelError(8);
//mTerrainGlobals->setLayerBlendMapSize(SPLIT_TERRAIN ? 256 : 1024);
//mTerrainGlobals->setLightMapSize(SPLIT_TERRAIN ? 256 : 1024);
//mTerrainGlobals->setCompositeMapSize(SPLIT_TERRAIN ? 256 : 1024);
//mTerrainGlobals->setDefaultGlobalColourMapSize(256);
//10 (default) didn't seem to be quite enough
mTerrainGlobals->setSkirtSize(128);
/*
* Here we are pushing the composite map distance beyond the edge
* of the rendered terrain due to not having setup lighting
*/
//mTerrainGlobals->setCompositeMapDistance(ESM::Land::REAL_SIZE*4);
matProfile->setLightmapEnabled(false); matProfile->setLightmapEnabled(false);
matProfile->setReceiveDynamicShadowsEnabled(false); matProfile->setLayerSpecularMappingEnabled(false);
matProfile->setLayerNormalMappingEnabled(false); matProfile->setLayerNormalMappingEnabled(false);
matProfile->setLayerParallaxMappingEnabled(false); matProfile->setLayerParallaxMappingEnabled(false);
matProfile->setLayerSpecularMappingEnabled(false); matProfile->setReceiveDynamicShadowsEnabled(false);
mLandSize = ESM::Land::LAND_SIZE; mLandSize = ESM::Land::LAND_SIZE;
mRealSize = ESM::Land::REAL_SIZE; mRealSize = ESM::Land::REAL_SIZE;
if ( SPLIT_TERRAIN ) if ( SPLIT_TERRAIN )
@ -95,8 +107,6 @@ namespace MWRender
const int cellX = store->cell->getGridX(); const int cellX = store->cell->getGridX();
const int cellY = store->cell->getGridY(); const int cellY = store->cell->getGridY();
Ogre::Terrain::ImportData terrainData =
mTerrainGroup->getDefaultImportSettings();
if ( SPLIT_TERRAIN ) if ( SPLIT_TERRAIN )
{ {
@ -107,6 +117,9 @@ namespace MWRender
{ {
for ( int y = 0; y < 2; y++ ) for ( int y = 0; y < 2; y++ )
{ {
Ogre::Terrain::ImportData terrainData =
mTerrainGroup->getDefaultImportSettings();
const int terrainX = cellX * 2 + x; const int terrainX = cellX * 2 + x;
const int terrainY = cellY * 2 + y; const int terrainY = cellY * 2 + y;
@ -133,6 +146,8 @@ namespace MWRender
x * numTextures, y * numTextures, x * numTextures, y * numTextures,
numTextures, indexes); numTextures, indexes);
assert( mTerrainGroup->getTerrain(cellX, cellY) == NULL &&
"The terrain for this cell already existed" );
mTerrainGroup->defineTerrain(terrainX, terrainY, &terrainData); mTerrainGroup->defineTerrain(terrainX, terrainY, &terrainData);
mTerrainGroup->loadTerrain(terrainX, terrainY, true); mTerrainGroup->loadTerrain(terrainX, terrainY, true);
@ -146,6 +161,9 @@ namespace MWRender
} }
else else
{ {
Ogre::Terrain::ImportData terrainData =
mTerrainGroup->getDefaultImportSettings();
//one cell is one terrain segment //one cell is one terrain segment
terrainData.inputFloat = OGRE_ALLOC_T(float, terrainData.inputFloat = OGRE_ALLOC_T(float,
mLandSize*mLandSize, mLandSize*mLandSize,
@ -167,6 +185,7 @@ namespace MWRender
ESM::Land::LAND_TEXTURE_SIZE, indexes); ESM::Land::LAND_TEXTURE_SIZE, indexes);
} }
mTerrainGroup->freeTemporaryResources();
} }
//---------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------
@ -179,14 +198,14 @@ namespace MWRender
{ {
for ( int y = 0; y < 2; y++ ) for ( int y = 0; y < 2; y++ )
{ {
mTerrainGroup->removeTerrain(store->cell->getGridX() * 2 + x, mTerrainGroup->unloadTerrain(store->cell->getGridX() * 2 + x,
store->cell->getGridY() * 2 + y); store->cell->getGridY() * 2 + y);
} }
} }
} }
else else
{ {
mTerrainGroup->removeTerrain(store->cell->getGridX(), mTerrainGroup->unloadTerrain(store->cell->getGridX(),
store->cell->getGridY()); store->cell->getGridY());
} }
} }
@ -206,19 +225,17 @@ 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");
//have a base texture for now, but this is probably not needed on most cells //there is one texture that we want to use as a base (i.e. it won't have
terrainData->layerList.resize(1); //a blend map). This holds the ltex index of that base texture so that
terrainData->layerList[0].worldSize = 256; //we know not to include it in the output map
terrainData->layerList[0].textureNames.push_back("textures\\_land_default.dds"); // diffuseSpec int baseTexture = -1;
//terrainData->layerList[0].textureNames.push_back("textures\\_land_default.dds"); // normalHeight
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); const uint16_t ltexIndex = getLtexIndexAt(store, x, y);
//this is the base texture, so we can ignore this at present //this is the base texture, so we can ignore this at present
if ( ltexIndex == 0 ) if ( ltexIndex == baseTexture )
{ {
continue; continue;
} }
@ -232,21 +249,38 @@ namespace MWRender
store->landTextures->ltex.size() > (size_t)ltexIndex - 1 && store->landTextures->ltex.size() > (size_t)ltexIndex - 1 &&
"LAND.VTEX must be within the bounds of the LTEX array"); "LAND.VTEX must be within the bounds of the LTEX array");
std::string texture = store->landTextures->ltex[ltexIndex-1].texture; std::string texture;
//TODO this is needed due to MWs messed up texture handling if ( ltexIndex == 0 )
texture = texture.substr(0, texture.rfind(".")) + ".dds"; {
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(); const size_t position = terrainData->layerList.size();
terrainData->layerList.push_back(Ogre::Terrain::LayerInstance()); terrainData->layerList.push_back(Ogre::Terrain::LayerInstance());
terrainData->layerList[position].worldSize = 256; Ogre::TexturePtr normDisp = getNormalDisp("textures\\" + texture);
//terrainData->layerList[position].worldSize = 256;
terrainData->layerList[position].textureNames.push_back("textures\\" + texture); terrainData->layerList[position].textureNames.push_back("textures\\" + texture);
//Normal map. This should be removed but it would require alterations to //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 //the material generator. Another option would be to use a 1x1 blank texture
//terrainData->layerList[position].textureNames.push_back("textures\\" + texture); //terrainData->layerList[position].textureNames.push_back(normDisp->getName());
indexes[ltexIndex] = position; if ( baseTexture == -1 )
{
baseTexture = ltexIndex;
}
else
{
indexes[ltexIndex] = position;
}
} }
} }
} }
@ -278,9 +312,9 @@ namespace MWRender
std::map<uint16_t, int>::const_iterator iter; std::map<uint16_t, int>::const_iterator iter;
for ( iter = indexes.begin(); iter != indexes.end(); ++iter ) for ( iter = indexes.begin(); iter != indexes.end(); ++iter )
{ {
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) * blendSize * blendSize);
} }
//covert the ltex data into a set of blend maps //covert the ltex data into a set of blend maps
@ -295,15 +329,13 @@ namespace MWRender
const int relX = texX - fromX; const int relX = texX - fromX;
const int relY = texY - fromY; const int relY = texY - fromY;
//this is the ground texture, which is currently the base texture //check if it is the base texture (which isn't in the map) and
//so don't alter the splatting map //if it is don't bother altering the blend map for it
if ( ltexIndex == 0 ){ if ( indexes.find(ltexIndex) == indexes.end() )
{
continue; continue;
} }
assert (indexes.find(ltexIndex) != indexes.end() &&
"Texture layer must exist");
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)
@ -317,7 +349,7 @@ namespace MWRender
const int startY = std::max(0, relY*splatSize - blendDist); const int startY = std::max(0, relY*splatSize - blendDist);
const int endY = std::min(blendSize, (relY+1)*splatSize + blendDist); const int endY = std::min(blendSize, (relY+1)*splatSize + blendDist);
for ( int blendX = startX; blendX < endX; blendX++ ) for ( int blendX = startX; blendX < endX; blendX++ )
{ {
for ( int blendY = startY; blendY < endY; blendY++ ) for ( int blendY = startY; blendY < endY; blendY++ )
@ -328,34 +360,16 @@ namespace MWRender
assert(blendY >= 0 && blendY < blendSize && assert(blendY >= 0 && blendY < blendSize &&
"index must be within texture bounds"); "index must be within texture bounds");
//calculate the distance from the edge of the square
// to the point we are shading
int distX = relX*splatSize - blendX;
if ( distX < 0 )
{
distX = std::max(0, blendX - (relX+1)*splatSize);
}
int distY = relY*splatSize - blendY;
if ( distY < 0 )
{
distY = std::max(0, blendY - (relY+1)*splatSize);
}
float blendAmount = blendDist - std::sqrt((float)distX*distX + distY*distY);
blendAmount /= blendDist;
//this is required as blendDist < sqrt(blendDist*blendDist + blendDist*blendDist)
//this means that the corners are slightly the "wrong" shape but totaly smooth
//shading for the edges
blendAmount = std::max( (float) 0.0, blendAmount);
assert(blendAmount >= 0 && "Blend should never be negative");
//flips the y
const int index = blendSize*(blendSize - 1 - blendY) + blendX; const int index = blendSize*(blendSize - 1 - blendY) + blendX;
pBlend[index] += blendAmount; if ( blendX >= relX*splatSize && blendX < (relX+1)*splatSize &&
pBlend[index] = std::min((float)1, pBlend[index]); blendY >= relY*splatSize && blendY < (relY+1)*splatSize )
{
pBlend[index] = 1;
}
else
{
pBlend[index] = std::max((float)pBlend[index], 0.5f);
}
} }
} }
@ -420,4 +434,43 @@ namespace MWRender
->textures[y * ESM::Land::LAND_TEXTURE_SIZE + x]; ->textures[y * ESM::Land::LAND_TEXTURE_SIZE + x];
} }
//----------------------------------------------------------------------------------------------
Ogre::TexturePtr TerrainManager::getNormalDisp(const std::string& fileName)
{
Ogre::TextureManager* const texMgr = Ogre::TextureManager::getSingletonPtr();
const std::string normalTextureName = fileName.substr(0, fileName.rfind("."))
+ "_n.dds";
if ( !texMgr->getByName(normalTextureName).isNull() )
{
return texMgr->getByName(normalTextureName);
}
const std::string textureName = "default_terrain_normal";
if ( !texMgr->getByName(textureName).isNull() )
{
return texMgr->getByName(textureName);
}
Ogre::TexturePtr tex = texMgr->createManual(
textureName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
Ogre::TEX_TYPE_2D, 1, 1, 0, Ogre::PF_BYTE_BGRA);
Ogre::HardwarePixelBufferSharedPtr pixelBuffer = tex->getBuffer();
pixelBuffer->lock(Ogre::HardwareBuffer::HBL_NORMAL);
const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock();
Ogre::uint8* pDest = static_cast<Ogre::uint8*>(pixelBox.data);
*pDest++ = 128; // B
*pDest++ = 128; // G
*pDest++ = 128; // R
*pDest++ = 0; // A
pixelBuffer->unlock();
return tex;
}
} }

View file

@ -65,7 +65,7 @@ namespace MWRender{
* The distance that the current cell should be shaded into the neighbouring * 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 * texture. The distance is in terms of the splat size of a texture
*/ */
static const float TERRAIN_SHADE_DISTANCE = 0.5; 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
@ -110,6 +110,17 @@ namespace MWRender{
* first splat of the current cell * first splat of the current cell
*/ */
int getLtexIndexAt(MWWorld::Ptr::CellStore* store, int x, int y); int getLtexIndexAt(MWWorld::Ptr::CellStore* store, int x, int y);
/**
* Retrives the texture that is the normal and parallax map for the
* terrain. If it doesn't exist a blank texture is used
*
* The file name of the texture should be the same as the file name of
* the base diffuse texture, but with _n appended before the extension
*
* @param fileName the name of the *diffuse* texture
*/
Ogre::TexturePtr getNormalDisp(const std::string& fileName);
}; };

View file

@ -544,7 +544,7 @@ namespace Ogre
params->setNamedAutoConstant("ambient", GpuProgramParameters::ACT_AMBIENT_LIGHT_COLOUR); params->setNamedAutoConstant("ambient", GpuProgramParameters::ACT_AMBIENT_LIGHT_COLOUR);
params->setNamedAutoConstant("lightPosObjSpace", GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE, 0); params->setNamedAutoConstant("lightPosObjSpace", GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE, 0);
params->setNamedAutoConstant("lightDiffuseColour", GpuProgramParameters::ACT_LIGHT_DIFFUSE_COLOUR, 0); params->setNamedAutoConstant("lightDiffuseColour", GpuProgramParameters::ACT_LIGHT_DIFFUSE_COLOUR, 0);
params->setNamedAutoConstant("lightSpecularColour", GpuProgramParameters::ACT_LIGHT_SPECULAR_COLOUR, 0); //params->setNamedAutoConstant("lightSpecularColour", GpuProgramParameters::ACT_LIGHT_SPECULAR_COLOUR, 0);
params->setNamedAutoConstant("eyePosObjSpace", GpuProgramParameters::ACT_CAMERA_POSITION_OBJECT_SPACE); params->setNamedAutoConstant("eyePosObjSpace", GpuProgramParameters::ACT_CAMERA_POSITION_OBJECT_SPACE);
params->setNamedAutoConstant("fogColour", GpuProgramParameters::ACT_FOG_COLOUR); params->setNamedAutoConstant("fogColour", GpuProgramParameters::ACT_FOG_COLOUR);
@ -948,7 +948,7 @@ namespace Ogre
"uniform float3 ambient,\n" "uniform float3 ambient,\n"
"uniform float4 lightPosObjSpace,\n" "uniform float4 lightPosObjSpace,\n"
"uniform float3 lightDiffuseColour,\n" "uniform float3 lightDiffuseColour,\n"
"uniform float3 lightSpecularColour,\n" //"uniform float3 lightSpecularColour,\n"
"uniform float3 eyePosObjSpace,\n" "uniform float3 eyePosObjSpace,\n"
// pack scale, bias and specular // pack scale, bias and specular
"uniform float4 scaleBiasSpecular,\n"; "uniform float4 scaleBiasSpecular,\n";
@ -1274,7 +1274,7 @@ namespace Ogre
else else
{ {
// Apply specular // Apply specular
outStream << " outputCol.rgb += litRes.z * lightSpecularColour * specular * shadow;\n"; //outStream << " outputCol.rgb += litRes.z * lightSpecularColour * specular * shadow;\n";
if (prof->getParent()->getDebugLevel()) if (prof->getParent()->getDebugLevel())
{ {