拉出来的地下不平滑怎么办,笨办法就是美工一个顶点一个顶点的调整,而且效果还不好。实际上程序只要实现一个完美平滑算法,随便一刷,地形就平滑了。
平滑算法最重要的就是不能改变原来的地形的大概结构,
基本思路,就是和相邻的点取一个混合值。混合公式和alpha混合公式一样。
海滩边岩石的平滑效果非常好。
#include "SmoothHeightAction.h" #include "SceneManipulator.h" #include "HitIndicator.h" namespace WX { ////////////////////////////////////////////////////////////////////////// SmoothHeightAction::SmoothHeightAction(SceneManipulator* sceneManipulator) : TimeBasedHeightAction(sceneManipulator) { } const String& SmoothHeightAction::getName(void) const { static const String name = "SmoothHeightAction"; return name; } void SmoothHeightAction::_onBegin(const Point& pt) { TimeBasedHeightAction::_onBegin(pt); //computeAverageHeight(); } void SmoothHeightAction::_onDrag(const Point& pt) { TimeBasedHeightAction::_onDrag(pt); //computeAverageHeight(); } void SmoothHeightAction::computeAverageHeight(void) { //Real totalHeight = 0; //Real totalWeight = 0; //JunctionSelection* selection = static_cast<JunctionSelection*>( // getSceneManipulator()->_getSelection("JunctionSelection")); //const JunctionSelection::JunctionMap& junctions = selection->getJunctions(); //JunctionSelection::JunctionMap::const_iterator it; //for (it = junctions.begin(); it != junctions.end(); ++it) //{ // const JunctionSelection::Junction& junction = it->second; // totalWeight += junction.weight; // totalHeight += getTerrainData()->getHeight(junction.x, junction.z) * junction.weight; //} //mAverageHeight = totalWeight ? totalHeight / totalWeight : 0; } Real SmoothHeightAction::_computeHeight(const JunctionSelection::Junction& junction, Real seconds) { //Real height = getTerrainData()->getHeight(junction.x, junction.z); //Real diff = mAverageHeight - height; //Real secondsRequest = Ogre::Math::Abs(diff * junction.weight / getSceneManipulator()->_getHeightAdjustSpeed()); //if (secondsRequest < seconds) // return mAverageHeight; //else // return height + diff * seconds / secondsRequest; return 0; } void SmoothHeightAction::_onUpdate(const Point& pt, Real seconds) { // 控制每秒平滑的次数 static Real time = 0; time += seconds; if (time > 0.1) { smooth(); time = 0; } getSceneManipulator()->getHitIndicator("JunctionPoints")->refresh(); getSceneManipulator()->getHitIndicator("IntersectPoint")->setHitPoint(pt); } void SmoothHeightAction::smooth(void) { // 2012.9.16 luoyinan 实现新的平滑算法,基本思路是和相邻的点取 // 一个混合值.再通过多次采样实现完美平滑效果 JunctionSelection* selection = static_cast<JunctionSelection*>( getSceneManipulator()->_getSelection("JunctionSelection")); //_prepareUpdate(*selection, seconds); const JunctionSelection::JunctionMap& junctions = selection->getJunctions(); JunctionSelection::JunctionMap::const_iterator it; std::vector<TerrainInfo> terrainInfo; float k = 0.98; // 从左到右 for (it = junctions.begin(); it != junctions.end(); ++it) { const JunctionSelection::Junction& junction = it->second; mModifiedJunctions->add(junction.x, junction.z, 1); // if (getTerrainData()->isValidJunction(junction.x-1,junction.z)) { float oldHeight = getTerrainData()->getHeight(junction.x,junction.z); float newHeight = getTerrainData()->getHeight(junction.x-1,junction.z) * (1-k) + oldHeight * k; TerrainInfo terrInfo; terrInfo.x = junction.x; terrInfo.z = junction.z; terrInfo.oldHeight = junction.height; terrInfo.nowHeight = newHeight; terrainInfo.push_back(terrInfo); getTerrainData()->setHeight(junction.x, junction.z, newHeight); } } // 从右到左 for (it = junctions.begin(); it != junctions.end(); ++it) { const JunctionSelection::Junction& junction = it->second; mModifiedJunctions->add(junction.x, junction.z, 1); // if (getTerrainData()->isValidJunction(junction.x+1,junction.z)) { float oldHeight = getTerrainData()->getHeight(junction.x,junction.z); float newHeight = getTerrainData()->getHeight(junction.x+1,junction.z) * (1-k) + oldHeight * k; TerrainInfo terrInfo; terrInfo.x = junction.x; terrInfo.z = junction.z; terrInfo.oldHeight = junction.height; terrInfo.nowHeight = newHeight; terrainInfo.push_back(terrInfo); getTerrainData()->setHeight(junction.x, junction.z, newHeight); } } // 从上到下 for (it = junctions.begin(); it != junctions.end(); ++it) { const JunctionSelection::Junction& junction = it->second; mModifiedJunctions->add(junction.x, junction.z, 1); // if (getTerrainData()->isValidJunction(junction.x,junction.z+1)) { float oldHeight = getTerrainData()->getHeight(junction.x,junction.z); float newHeight = getTerrainData()->getHeight(junction.x,junction.z+1) * (1-k) + oldHeight * k; TerrainInfo terrInfo; terrInfo.x = junction.x; terrInfo.z = junction.z; terrInfo.oldHeight = junction.height; terrInfo.nowHeight = newHeight; terrainInfo.push_back(terrInfo); getTerrainData()->setHeight(junction.x, junction.z, newHeight); } } // 从下到上 for (it = junctions.begin(); it != junctions.end(); ++it) { const JunctionSelection::Junction& junction = it->second; mModifiedJunctions->add(junction.x, junction.z, 1); // if (getTerrainData()->isValidJunction(junction.x,junction.z-1)) { float oldHeight = getTerrainData()->getHeight(junction.x,junction.z); float newHeight = getTerrainData()->getHeight(junction.x,junction.z-1) * (1-k) + oldHeight * k; TerrainInfo terrInfo; terrInfo.x = junction.x; terrInfo.z = junction.z; terrInfo.oldHeight = junction.height; terrInfo.nowHeight = newHeight; terrainInfo.push_back(terrInfo); getTerrainData()->setHeight(junction.x, junction.z, newHeight); } } getSceneManipulator()->_fireTerrainHeightChanged(terrainInfo); selection->notifyModified(); } }