OGRE例子:Demo_Ocean 源码解析

 
          因为最近在做水,所以这篇海洋的例子是必须要读懂的。

             耐着性子看了一下,还是能看懂的。现在将代码解析放上来。

程序共有四个文件:

MaterialControls.h    :

MaterialControls.cpp

包含一个Shader属性结构和材质结构。其中Shader属性结构对应于海洋中模型对应VS,PS的一些属性。

材质结构中包含了若干这个属性。使用一个容器来存放。

另外有两个函数讲述了如何从资源名称中得到scripts目录下的Ocean.controls文件,并从中将一大堆的的材质和Shader属性信息载入到对应的结构中。

 

 

OceanDemo.h

OceanDemo.cpp

 

程序和界面框架。

 

//============================================================

OceanDemo.h

/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2006 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

You may use this sample code for anything you like, it is not covered by the
LGPL like the rest of the engine.

材质控制器,对材质的各种参数进行设置
-----------------------------------------------------------------------------
*/

#ifndef __MaterialControls_H__
#define __MaterialControls_H__

#include "CEGUI/CEGUIForwardRefs.h"
#include "OgreString.h"

//Shader参数类型
enum ShaderValType
{
 GPU_VERTEX, GPU_FRAGMENT, MAT_SPECULAR, MAT_DIFFUSE, MAT_AMBIENT, MAT_SHININESS, MAT_EMISSIVE
};
//顶点
//碎片
//反射
//漫反射
//环境光
//镜面反射
//发射光
//---------------------------------------------------------------------------

//Shader控制器(一个Shader属性的结构)
struct ShaderControl
{
    Ogre::String Name;     //Shader名称
 Ogre::String ParamName;    //属性名称
 ShaderValType ValType;    //Shader参数类型
 float MinVal;      //最小值
 float MaxVal;      //最大值
 size_t ElementIndex;    //属性索引
 mutable size_t PhysicalIndex;  //物理索引

 float getRange(void) const { return MaxVal - MinVal; }   //取得差值
 float convertParamToScrollPosition(const float val) const { return val - MinVal; } //由属性取得对应滚动条的索引位置
 float convertScrollPositionToParam(const float val) const { return val + MinVal; } //由索引取得对应的属性
};

//Shader属性结构容器
typedef std::vector<ShaderControl> ShaderControlsContainer;
//对应的迭代器
typedef ShaderControlsContainer::iterator ShaderControlIterator;
// used for materials that have user controls

//---------------------------------------------------------------------------
//材质控制器
class MaterialControls
{
public:
    MaterialControls(const Ogre::String& displayName, const Ogre::String& materialName)
        : mDisplayName(displayName)
        , mMaterialName(materialName)
    {
    };

    ~MaterialControls(void){}
 //取得显示名称
    const Ogre::String& getDisplayName(void) const { return mDisplayName; }
 //取得材质名称
    const Ogre::String& getMaterialName(void) const { return mMaterialName; }
 //取得Shader属性的数量
    size_t getShaderControlCount(void) const { return mShaderControlsContainer.size(); }
 //取得对应的Shader控制结构
    const ShaderControl& getShaderControl(const size_t idx) const
    {
        assert( idx < mShaderControlsContainer.size() );
        return mShaderControlsContainer[idx];
    }
    /** add a new control by passing a string parameter

    @param
      params is a string using the following format:
        "<Control Name>, <Shader parameter name>, <Parameter Type>, <Min Val>, <Max Val>, <Parameter Sub Index>"

        <Control Name> is the string displayed for the control name on screen
        <Shader parameter name> is the name of the variable in the shader
        <Parameter Type> can be GPU_VERTEX, GPU_FRAGMENT
        <Min Val> minimum value that parameter can be
        <Max Val> maximum value that parameter can be
        <Parameter Sub Index> index into the the float array of the parameter.  All GPU parameters are assumed to be float[4].

    */
 //增加一个Shader属性结构
    void addControl(const Ogre::String& params);

protected:

    Ogre::String mDisplayName;   //显示名称
    Ogre::String mMaterialName;   //材质名称
          //Shader属性容器
    ShaderControlsContainer mShaderControlsContainer;
};

//多个材质的容器
typedef std::vector<MaterialControls> MaterialControlsContainer;
//对应的迭代器
typedef MaterialControlsContainer::iterator MaterialControlsIterator;


//---------------------------------------------------------------------------
//CEGUI的界面结构
struct ShaderControlGUIWidget
{
 CEGUI::Window*  TextWidget;     //标题
 CEGUI::Window*  NumberWidget;    //窗体数量
 CEGUI::Scrollbar*   ScrollWidget;    //滚动条

 ShaderControlGUIWidget() : TextWidget(NULL), NumberWidget(NULL), ScrollWidget(NULL) {}
};

//---------------------------------------------------------------------------
/** loads material shader controls from a configuration file
    A .controls file is made up of the following:

    [<material display name>]
    material = <material name>
    control = <Control Name>, <Shader parameter name>, <Parameter Type>, <Min Val>, <Max Val>, <Parameter Sub Index>

    <material display name> is what is displayed in the material combo box.
    <material name> is the name of the material in the material script.
    control is the shader control associated with the material. The order
    of the contol definions in the .controls file determins their order
    when displayed in the controls window.

    you can have multiple .controls files or put them all in one.
*/
//从文件中载入材质
void loadMaterialControlsFile(MaterialControlsContainer& controlsContainer, const Ogre::String& filename);
/** load all control files found in resource paths
*/
//载入所有的材质
void loadAllMaterialControlFiles(MaterialControlsContainer& controlsContainer);

#endif // __MaterialControls_H__

 

//======================================================

MaterialControls.cpp:

 

/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2006 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

You may use this sample code for anything you like, it is not covered by the
LGPL like the rest of the engine.
-----------------------------------------------------------------------------
*/

#include "MaterialControls.h"
#include "OgreLogManager.h"
#include "OgreStringVector.h"
#include "OgreStringConverter.h"
#include "OgreConfigFile.h"
#include "OgreResourceGroupManager.h"
#include "OgreException.h"

/********************************************************************************
            MaterialControls Methods 材质容器的各种方法
*********************************************************************************/
//增加一个控制器
void MaterialControls::addControl(const Ogre::String& params)
{
    // params is a string containing using the following format:
    //  "<Control Name>, <Shader parameter name>, <Parameter Type>, <Min Val>, <Max Val>, <Parameter Sub Index>"

    // break up long string into components
 // 由字符串','进行分隔得出属性名称装在字符串容器中
    Ogre::StringVector vecparams = Ogre::StringUtil::split(params, ",");

    // if there are not five elements then log error and move on
 // 如果容器大小不对则出错
    if (vecparams.size() != 6)
    {
        Ogre::LogManager::getSingleton().logMessage(
            "Incorrect number of parameters passed in params string for MaterialControls::addControl()" );

        return;
    }
 //一个新的Shader属性
    ShaderControl newControl;
 //字符串容器中第一个字符串取出后消除两边空格符
    Ogre::StringUtil::trim(vecparams[0]);
 //设置为对应的名称
    newControl.Name = vecparams[0];
 //字符串容器中第二个字符串取出后消除两边空格符
    Ogre::StringUtil::trim(vecparams[1]);
 //设置为对应的属性名称
    newControl.ParamName = vecparams[1];
 //字符串容器中第三个字符串取出后消除两边空格符
    Ogre::StringUtil::trim(vecparams[2]);
 //判断对应的属性类型是VS还是PS
    if (vecparams[2] == "GPU_VERTEX")
        newControl.ValType = GPU_VERTEX;
    else if (vecparams[2] == "GPU_FRAGMENT")
        newControl.ValType = GPU_FRAGMENT;
 //该属性对应的最小值和最大值
    newControl.MinVal = Ogre::StringConverter::parseReal(vecparams[3]);
    newControl.MaxVal = Ogre::StringConverter::parseReal(vecparams[4]);
 //属性索引
    newControl.ElementIndex = Ogre::StringConverter::parseInt(vecparams[5]);
 //放入属性容器中
    mShaderControlsContainer.push_back(newControl);

}

//载入材质
void loadMaterialControlsFile(MaterialControlsContainer& controlsContainer, const Ogre::String& filename)
{
    // Load material controls from config file
 // 一个CFG文件
    Ogre::ConfigFile cf;

    try
    {
  //载入文件

        cf.load(filename, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "/t;=", true);

        // Go through all sections & controls in the file
  //取得CFG文件读入后信息容器的对应的迭代器
        Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
  //键名,种类名,材质名,数据段
        Ogre::String secName, typeName, materialName, dataString;
  //轮循取出CFG文件信息
        while (seci.hasMoreElements())
        {
   //键名
            secName = seci.peekNextKey();
   //以MultiMap方式取得对应信息容器
            Ogre::ConfigFile::SettingsMultiMap* settings = seci.getNext();
            if (!secName.empty() && settings)
            {
    //取得材质名称
                materialName = cf.getSetting("material", secName);
    //一个新的材质控制器
                MaterialControls newMaaterialControls(secName, materialName);
    //放入材质容器
                controlsContainer.push_back(newMaaterialControls);
    //取得放入容器后对应的索引
                size_t idx = controlsContainer.size() - 1;
    //对应的迭代器
                Ogre::ConfigFile::SettingsMultiMap::iterator i;
    //将属性加入其对应的Shader属性容器
                for (i = settings->begin(); i != settings->end(); ++i)
                {
                    typeName = i->first;
                    dataString = i->second;
                    if (typeName == "control")
                        controlsContainer[idx].addControl(dataString);
                }
            }
        }
  //输入“安装完成”
     Ogre::LogManager::getSingleton().logMessage( "Material Controls setup" );
    }
    catch (Ogre::Exception e)
    {
        // Guess the file didn't exist
  // 如果有异常
    }
}

//载入所有材质文件
void loadAllMaterialControlFiles(MaterialControlsContainer& controlsContainer)
{
 //取得对应的controls文件名,生成一个字符串容器
    Ogre::StringVectorPtr fileStringVector = Ogre::ResourceGroupManager::getSingleton().findResourceNames( Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "*.controls" );
    std::vector<Ogre::String>::iterator controlsFileNameIterator = fileStringVector->begin();
 //遍历字符串容器,由字符串载入对应的材质文件
    while ( controlsFileNameIterator != fileStringVector->end() )
 {
  //载入对应材质
        loadMaterialControlsFile(controlsContainer, *controlsFileNameIterator);
  //迭代器++
        ++controlsFileNameIterator;
 }
}

对于框架文件,只需要知道:

/--------------------------------------------------------------------------
//将界面上的数据反映到Shader控制器上
bool OceanDemo::handleShaderControl(const CEGUI::EventArgs& e)
{
 using namespace CEGUI;
 using namespace Ogre;

 //由索引取得是哪个材质的哪个Shader控制器
 size_t index = ((Scrollbar*)((const WindowEventArgs&)e).window)->getID();
    const ShaderControl& ActiveShaderDef = mMaterialControlsContainer[mCurrentMaterial].getShaderControl(index);
 
 //由滚动条的值取得对应的属性
 float val = ((Scrollbar*)((const WindowEventArgs&)e).window)->getScrollPosition();
 val = ActiveShaderDef.convertScrollPositionToParam(val);
 setShaderControlVal( val, index );

 if(mActivePass)
 {
  switch(ActiveShaderDef.ValType)
  {
   //如果是VS或PS
   case GPU_VERTEX:
   case GPU_FRAGMENT:
    {
     GpuProgramParametersSharedPtr activeParameters =
      (ActiveShaderDef.ValType == GPU_VERTEX) ?
       mActiveVertexParameters : mActiveFragmentParameters;

     if(!activeParameters.isNull())
     {
      activeParameters->_writeRawConstant(
       ActiveShaderDef.PhysicalIndex + ActiveShaderDef.ElementIndex, val);
     }
    }
    break;
   //如果是镜面光
   case MAT_SPECULAR:
    {
     // get the specular values from the material pass
     ColourValue OldSpec(mActivePass->getSpecular());
     OldSpec[ActiveShaderDef.ElementIndex] = val;
     mActivePass->setSpecular( OldSpec );
    }

    break;
   //如果是漫射光
   case MAT_DIFFUSE:
    {
     // get the specular values from the material pass
     ColourValue OldSpec(mActivePass->getDiffuse());
     OldSpec[ActiveShaderDef.ElementIndex] = val;
     mActivePass->setDiffuse( OldSpec );
    }
    break;
   //如果是环境光
   case MAT_AMBIENT:
    {
     // get the specular values from the material pass
     ColourValue OldSpec(mActivePass->getAmbient());
     OldSpec[ActiveShaderDef.ElementIndex] = val;
     mActivePass->setAmbient( OldSpec );
    }
    break;
   //如果是自发光
   case MAT_SHININESS:
    // get the specular values from the material pass
    mActivePass->setShininess( val );
    break;
  }
 }

    return true;
}

 

              综上源码分析,可知,本质上海洋的表现是依靠材质来达成的。关键是掌握如何调节材质中对应的VS.PS属性值。


作者:pizi0475 发表于2011-7-29 15:29:38 原文链接
阅读:53 评论:0 查看评论

你可能感兴趣的:(demo)