地形平滑算法

拉出来的地下不平滑怎么办,笨办法就是美工一个顶点一个顶点的调整,而且效果还不好。实际上程序只要实现一个完美平滑算法,随便一刷,地形就平滑了。

平滑算法最重要的就是不能改变原来的地形的大概结构,

基本思路,就是和相邻的点取一个混合值。混合公式和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();
	}

}


猜你喜欢

转载自blog.csdn.net/qq18052887/article/details/9139553