一种简单的材质排序方法

        在实时渲染中,渲染不同物体时进行的材质切换是影响效率的主要因素之一。为了减少材质切换带来的负面影响,对需要渲染的物体进行材质排序是优化的主要思路。通过将材质进行排序,可以尽可能的减少材质切换的次数和每次切换带来的效率损耗。本文通过引入一种简单的数据结构来完成这个功能。该方案目前仅限于设计和功能实现阶段,没有进行实际的测试和优化。材质排序主要需要考虑两个方面,1-尽可能少的切换次数,2-尽可能低的效率影响。在实际操作中,这两个要求其实是相互制约的。举个例子:假设在整个渲染周期最复杂的材质包括以下3部分:纹理贴图,光照,Alpha混合。需要渲染的物体为4个:A,B,C,D。它们的材质分布如图:

 

       简单的统计一下可以看到:纹理有3种,灯火有3种,Alpha有2种。如果按照最小切换次数的思想,应该先优化Alpha的切换,然后是纹理和灯光。但在实际操作中,切换纹理的消耗要远高于Alpha的切换,因为应该先考虑纹理的优化,然后是灯光,最后才是Alpha。

       这里就引入以优先级的概念,即在材质中,每种属性都有其优先级。优先级高的属性需要尽可能的减少切换次数。优先级的设定是用户制定的,可能会随开发平台或不同的渲染底层有相应的改变。本文使用 纹理 - 灯光 - alpha 从高到低的顺序。

       对材质进行排序必然需要一种能保存排序结果的数据结构。通过以上分析,可以推导出该数据结构至少需要满足以下条件:

1. 无歧义的保存排序结果

2. 动态的添加和删除

3. 能遍历该结构,每次返还的结果与上次返还的结果需要进行的状态切换最优化。

4. 能根据用户指定的优先级进行排序

同时我们再添加一个要求,在常数时间完成遍历和删除功能。

 

 

下图是一种满足以上条件的数据结构,由于它是按元素的差异值作为排序的关键操作的,因此可以称它为Diff-Tree。

 

Diff-Tree中的每个节点都有4个指针。分别为:NextPtr,PrevPtr,FirstChildPtr,ParentPtr。

NextPtr指向其右邻居,PrevPtr指向左邻居,FirstChildPtr指向第一个子节点。ParentPtr指向父节点。其中ParentPtr比较特殊,只有在一个节点本身是另一个节点的第一个子节点时,该指针才有效。即上图中阴影显示的节点。

       Node提供Diff操作,该操作返回两个Node的差异值。差异值的计算如下:按材质属性的优先级顺序从高到低比较,如果该属性不相同,返还优先级。

         

None.gif   enum ShaderFeature
None.gif
ExpandedBlockStart.gifContractedBlock.gif              
dot.gif{
InBlock.gif
InBlock.gif                     SF_PAD 
= 0,
InBlock.gif
InBlock.gif                     SF_BASETEXTURE 
= 1,
InBlock.gif
InBlock.gif                     SF_LIGHT     
= 2,
InBlock.gif
InBlock.gif                     SF_ALPHAFUNC 
= 3,
InBlock.gif
InBlock.gif                     SF_MAX_COUNT
InBlock.gif
ExpandedBlockEnd.gif              }
;
None.gif
int SG_Shader::operator - (const SG_Shader& rkShader)
None.gif
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif
InBlock.gif        
for(int i = SF_PAD + 1; i < SF_MAX_COUNT; i++)
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif
InBlock.gif              ShaderFeature eFeature 
= (ShaderFeature)i;
InBlock.gif
InBlock.gif              
if(GetShaderFeature(eFeature) != rkShader.GetShaderFeature(eFeature))
InBlock.gif
InBlock.gif                     
return i;
InBlock.gif
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
return SF_MAX_COUNT; //equal
InBlock.gif

ExpandedBlockEnd.gif}

None.gif
None.gif

 

如上面的代码片断,如果两个材质的纹理不同,Diff操作返回1,如果纹理相同,灯光不同,返回2,如果只有Alpha不同,返回3。

用[ x, x, x]的格式来表示一个材质,第1个x是纹理编号,第2个x是灯光编号,第3个是Alpha混合类型编号。在添加的多个节点后,Diff Tree能成为一种深度优先的结构:


 

DiffTree保证在按深度遍历时,每次返还的结果与上次返还的结果需要进行的状态切换最优化。如上图,首先保证了纹理切换的次数最少(先遍历完所有纹理为1的节点)。

DiffTree的插入排序算法如下:

    1.如果树为空,root = insert。

  2.check = root,depth = 1

 3.遍历check和它所有同级节点,返回与插入节点差异度最大的节点 beinsert.

  4.如果insert和beinsert相同,插入结束。

  5.如果insert与beinsert差异度小于等于depth,insert被插入为beinsert的邻居节点,返回。

6.如果insert与beinsert差异度大于depth,并且beinsert没有子节点,insert为beinsert的子节点。

7.check = beinsert. FirstChildPtr,跳回第3步。

 

以下是向树中插入一个[1,2,3]的材质的过程。

















附上代码:
ExpandedBlockStart.gifContractedBlock.gif/**//********************************************************************
InBlock.gifcreated:    2:7:2007   11:35
InBlock.giffilename:     SG_Shader.h
InBlock.gifauthor:        Badkeeper
InBlock.gifpurpose:    Shader is uesd order scenenode render. scene node with same shader
InBlock.gif            will render in a batch
ExpandedBlockEnd.gif********************************************************************
*/

None.gif
None.gif#ifndef _SG_SHADER_H
None.gif
#define _SG_SHADER_H
None.gif
None.gif#include 
"SG_SceneNode.h"
None.gif
None.gif
namespace MayEX
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
class SG_Shader
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif    
public:
InBlock.gif        SG_Shader();
InBlock.gif        
~SG_Shader();
InBlock.gif        
enum ShaderFeature
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            SF_PAD 
= 0,
InBlock.gif            SF_BASETEXTURE 
= 1,
InBlock.gif            SF_LIGHT     
= 2,
InBlock.gif            SF_ALPHAFUNC 
= 3,
InBlock.gif            SF_MAX_COUNT
ExpandedSubBlockEnd.gif        }
;
InBlock.gif
InBlock.gif        
bool operator == (const SG_Shader& rkShader);
InBlock.gif        
//this operator is used in shader order tree sorting
InBlock.gif
        int  operator -  (const SG_Shader& rkShader); 
InBlock.gif        
int  operator -  (const SG_Shader& rkShader) const;
InBlock.gif        
InBlock.gif        
void SetShaderFeature(ShaderFeature eFeature,int ID);
InBlock.gif    
InBlock.gif        
int  GetShaderFeature(ShaderFeature eFeature);
InBlock.gif        
int  GetShaderFeature(const ShaderFeature eFeature) const;
InBlock.gif
InBlock.gif        SG_Shader
* GetNext();
InBlock.gif        SG_Shader
* GetFirstChild();
InBlock.gif        SG_Shader
* GetPrev();
InBlock.gif        SG_Shader
* GetParent();
InBlock.gif    
InBlock.gif        
const SG_Shader* GetNext() const;
InBlock.gif        
const SG_Shader* GetFirstChild() const;
InBlock.gif        
const SG_Shader* GetPrev() const;
InBlock.gif        
const SG_Shader* GetParent() const;
InBlock.gif        
InBlock.gif        
void       SetNext(SG_Shader* pkShader);
InBlock.gif        
void       SetFirstChild(SG_Shader* pkShader);
InBlock.gif
InBlock.gif    
protected:
InBlock.gif        
void       SetPrev(SG_Shader* pkShader);
InBlock.gif        
void       SetParent(SG_Shader* pkShader);
InBlock.gif
InBlock.gif
InBlock.gif        
int     m_aiShaderFeatures[SF_MAX_COUNT];
InBlock.gif
InBlock.gif        SG_Shader
* m_pkNextShader;
InBlock.gif        SG_Shader
* m_pkChildShader;
InBlock.gif        SG_Shader
* m_pkPrevShader;
InBlock.gif        SG_Shader
* m_pkParentShader;
ExpandedSubBlockEnd.gif    }
;
ExpandedBlockEnd.gif}

None.gif
None.gif
None.gif
None.gif
#endif

 

 

 

None.gif#include "SG_Shader.h"
None.gif
None.gif
using namespace MayEX;
None.gif
None.gif
//---------------------------------------------------------
None.gif
SG_Shader::SG_Shader()
None.gif: m_pkChildShader(NULL)
None.gif, m_pkNextShader(NULL)
None.gif, m_pkPrevShader(NULL)
None.gif, m_pkParentShader(NULL)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
for(int i = SF_PAD; i < SF_MAX_COUNT; i++)
InBlock.gif        m_aiShaderFeatures[i] 
= -1;
ExpandedBlockEnd.gif}

None.gif
//---------------------------------------------------------
None.gif
SG_Shader::~SG_Shader()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
if(m_pkNextShader)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        delete m_pkNextShader;
InBlock.gif        m_pkNextShader 
= NULL;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
if(m_pkChildShader)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        delete m_pkChildShader;
InBlock.gif        m_pkChildShader 
= NULL;
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
//destory this
ExpandedBlockEnd.gif
}

None.gif
//---------------------------------------------------------
None.gif
int SG_Shader::operator - (const SG_Shader& rkShader)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
for(int i = SF_PAD + 1; i < SF_MAX_COUNT; i++)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        ShaderFeature eFeature 
= (ShaderFeature)i;
InBlock.gif        
InBlock.gif        
if(GetShaderFeature(eFeature) != rkShader.GetShaderFeature(eFeature))
InBlock.gif            
return i;
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
return SF_MAX_COUNT; //equal
ExpandedBlockEnd.gif
}

None.gif
//---------------------------------------------------------
None.gif
int SG_Shader::operator - (const SG_Shader& rkShader) const
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
for(int i = SF_PAD + 1; i < SF_MAX_COUNT; i++)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        ShaderFeature eFeature 
= (ShaderFeature)i;
InBlock.gif
InBlock.gif        
if(GetShaderFeature(eFeature) != rkShader.GetShaderFeature(eFeature))
InBlock.gif            
return i;
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
return SF_MAX_COUNT; //equal
ExpandedBlockEnd.gif
}

None.gif
None.gif
//---------------------------------------------------------
None.gif
void SG_Shader::SetShaderFeature(ShaderFeature eFeature,int ID)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    assert(eFeature 
!= SF_PAD && "Set error shader feature");
InBlock.gif    m_aiShaderFeatures[eFeature] 
= ID;
ExpandedBlockEnd.gif}

None.gif
//---------------------------------------------------------
None.gif
int SG_Shader::GetShaderFeature(ShaderFeature eFeature)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    assert(eFeature 
!= SF_PAD && "Get error shader feature");
InBlock.gif    
return m_aiShaderFeatures[eFeature];
ExpandedBlockEnd.gif}

None.gif
//---------------------------------------------------------
None.gif
int SG_Shader::GetShaderFeature(const ShaderFeature eFeature) const
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    assert(eFeature 
!= SF_PAD && "Get error shader feature");
InBlock.gif    
return m_aiShaderFeatures[eFeature];
ExpandedBlockEnd.gif}

None.gif
None.gif
//---------------------------------------------------------
None.gif
SG_Shader* SG_Shader::GetNext()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
return m_pkNextShader;
ExpandedBlockEnd.gif}

None.gif
//---------------------------------------------------------
None.gif
SG_Shader* SG_Shader::GetFirstChild()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
return m_pkChildShader;
ExpandedBlockEnd.gif}

None.gif
//---------------------------------------------------------
None.gif
SG_Shader* SG_Shader::GetPrev()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
return m_pkPrevShader;
ExpandedBlockEnd.gif}

None.gif
//---------------------------------------------------------
None.gif
SG_Shader* SG_Shader::GetParent()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
return m_pkParentShader;
ExpandedBlockEnd.gif}

None.gif
//---------------------------------------------------------
None.gif
const SG_Shader* SG_Shader::GetNext() const
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
return m_pkNextShader;
ExpandedBlockEnd.gif}

None.gif
//---------------------------------------------------------
None.gif
const SG_Shader* SG_Shader::GetFirstChild() const
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
return m_pkChildShader;
ExpandedBlockEnd.gif}

None.gif
//---------------------------------------------------------
None.gif
const SG_Shader* SG_Shader::GetPrev() const
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
return m_pkPrevShader;
ExpandedBlockEnd.gif}

None.gif
//---------------------------------------------------------
None.gif
const SG_Shader* SG_Shader::GetParent() const
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
return m_pkParentShader;
ExpandedBlockEnd.gif}

None.gif
//---------------------------------------------------------
None.gif
void SG_Shader::SetNext(SG_Shader* pkShader)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    m_pkNextShader 
= pkShader;
InBlock.gif    
if(pkShader)
InBlock.gif        pkShader
->SetPrev(this);
ExpandedBlockEnd.gif}

None.gif
//---------------------------------------------------------
None.gif
void SG_Shader::SetFirstChild(SG_Shader* pkShader)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    m_pkChildShader 
= pkShader;
InBlock.gif    
if(pkShader)
InBlock.gif        pkShader
->SetParent(this);
ExpandedBlockEnd.gif}

None.gif
//---------------------------------------------------------
None.gif
void SG_Shader::SetPrev(SG_Shader* pkShader)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    m_pkPrevShader 
= pkShader;
ExpandedBlockEnd.gif}

None.gif
//---------------------------------------------------------
None.gif
void SG_Shader::SetParent(SG_Shader* pkShader)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    m_pkParentShader 
= pkShader;
ExpandedBlockEnd.gif}


ExpandedBlockStart.gifContractedBlock.gif/**//********************************************************************
InBlock.gifcreated:    3:7:2007   11:35
InBlock.giffilename:     SG_ShaderTree.h
InBlock.gifauthor:        Badkeeper
InBlock.gifpurpose:    Shader Tree is used sort geometry render. 
ExpandedBlockEnd.gif********************************************************************
*/

None.gif#ifndef _SG_SHADER_TREE_H
None.gif
#define _SG_SHADER_TREE_H
None.gif
None.gif#include 
"c_string_utility.h"
None.gif#include 
"SG_Shader.h"
None.gif
None.gif
namespace MayEX
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
class SG_ShaderTree
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif    
public:
InBlock.gif        SG_ShaderTree();
InBlock.gif        
~SG_ShaderTree();
InBlock.gif
InBlock.gif        
bool InsertShader(SG_Shader* pkShader);
InBlock.gif        
bool RemoveShader(SG_Shader* pkShader);
InBlock.gif        
int  Size();
InBlock.gif
InBlock.gif        
void OutputShaderTreeStruct();
InBlock.gif        
InBlock.gif        SG_Shader
* GetFirstNode();
InBlock.gif        SG_Shader
* GetNext(SG_Shader* pkNode);
InBlock.gif        SG_Shader
* GetParent(SG_Shader* pkNode);
InBlock.gif
InBlock.gif
InBlock.gif
InBlock.gif    
protected:
InBlock.gif        
bool       _insertShader(SG_Shader* pkFirstNode,
InBlock.gif                                 SG_Shader
* pkInsertShader,
InBlock.gif                                 
int iTreeLevel);
InBlock.gif        SG_Shader
* _findMaxDiffNodeOnThisLevel(const SG_Shader* pkFirstNode,
InBlock.gif            
const SG_Shader* pkCompareShader);
InBlock.gif        
InBlock.gif        
void _outputShaderTreeStruct(const SG_Shader* pkTreeRoot,int iTreeLevel);
InBlock.gif        
void _outputShaderStruct(const SG_Shader* pkNode,int iTreeLevel);
InBlock.gif
InBlock.gif        SG_Shader
*   m_pkRootShader;    
InBlock.gif        
int             m_iSize;
ExpandedSubBlockEnd.gif    }
;
ExpandedBlockEnd.gif}

None.gif
None.gif
None.gif
None.gif
#endif


None.gif#include "SG_ShaderTree.h"
None.gif#include 
"c_logger_manager.h"
None.gif
None.gif
using namespace MayEX;
None.gif
using namespace LogSystem;
None.gif
None.gif
//-----------------------------------------------------
None.gif
SG_ShaderTree::SG_ShaderTree()
None.gif: m_pkRootShader(NULL)
None.gif, m_iSize(
0)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif
ExpandedBlockEnd.gif}

None.gif
//---------------------------------------------------------
None.gif
SG_ShaderTree::~SG_ShaderTree()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
if(m_pkRootShader)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        delete m_pkRootShader;
InBlock.gif        m_pkRootShader 
= NULL;
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif
//---------------------------------------------------------
None.gif
bool SG_ShaderTree::RemoveShader(SG_Shader* pkShader)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
if(!pkShader)
InBlock.gif        
return false;
InBlock.gif    SG_Shader
* pkReplaceShader = NULL;
InBlock.gif    
if(pkShader->GetFirstChild())
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        pkReplaceShader 
= pkShader->GetFirstChild();
InBlock.gif        pkReplaceShader
->SetFirstChild(pkReplaceShader->GetNext());
InBlock.gif        pkReplaceShader
->SetNext(pkShader->GetNext());
ExpandedSubBlockEnd.gif    }

InBlock.gif    
else if(pkShader->GetNext())
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        pkReplaceShader 
= pkShader->GetNext();
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    SG_Shader
* pkPrevShader = pkShader->GetPrev();
InBlock.gif    
if(pkPrevShader)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        assert(pkPrevShader
->GetNext() == pkShader && "ShaderTree Critical Error");
InBlock.gif        pkPrevShader
->SetNext(pkReplaceShader);
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    SG_Shader
* pkParentShader = pkShader->GetParent();
InBlock.gif    
if(pkParentShader)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        assert(pkParentShader
->GetFirstChild() == pkShader && "ShaderTree Critical Error");
InBlock.gif        assert(
!pkPrevShader && "ShaderTree Critical Error");
InBlock.gif        pkParentShader
->SetFirstChild(pkReplaceShader);
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
return true;
ExpandedBlockEnd.gif}

None.gif
//---------------------------------------------------------
None.gif
bool SG_ShaderTree::InsertShader(SG_Shader* pkShader)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
if(!pkShader)
InBlock.gif        
return false;
InBlock.gif
InBlock.gif    
if(!m_pkRootShader)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        m_pkRootShader 
= pkShader;
InBlock.gif        m_iSize
++;
InBlock.gif        
return true;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
InBlock.gif    SG_Shader
* pkRootShader =  _findMaxDiffNodeOnThisLevel(m_pkRootShader,pkShader);
InBlock.gif    
return _insertShader(pkRootShader,pkShader,1);
ExpandedBlockEnd.gif}

None.gif
//---------------------------------------------------------
None.gif
bool SG_ShaderTree::_insertShader(SG_Shader* pkFirstNode,
None.gif                                  SG_Shader
* pkInsertShader,int iTreeLevel)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
int iDiff = *pkFirstNode - *pkInsertShader;
InBlock.gif    
if(iDiff == SF_MAX_COUNT)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
//Equal TODO
InBlock.gif
        return true;
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
if(iDiff <= iTreeLevel)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        SG_Shader
* pkFirstNeigborNode = pkFirstNode->GetNext();
InBlock.gif        pkFirstNode
->SetNext(pkInsertShader);
InBlock.gif        pkInsertShader
->SetNext(pkFirstNeigborNode);
InBlock.gif        m_iSize
++;
InBlock.gif        
return true;
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
if(pkFirstNode->GetFirstChild() == NULL)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        pkFirstNode
->SetFirstChild(pkInsertShader);
InBlock.gif        m_iSize
++;
InBlock.gif        
return true;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
else
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        SG_Shader
* pkFirstChildNode = pkFirstNode->GetFirstChild();
InBlock.gif        SG_Shader
* pkParent = _findMaxDiffNodeOnThisLevel(pkFirstChildNode,pkInsertShader);
InBlock.gif        assert(pkParent 
&& "ShaderTree insert failure");
InBlock.gif
InBlock.gif        
return _insertShader(pkParent,pkInsertShader,iTreeLevel+1);
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif
//---------------------------------------------------------
None.gif
SG_Shader* SG_ShaderTree::_findMaxDiffNodeOnThisLevel(const SG_Shader* pkFirstNode,
None.gif                                                      
const SG_Shader* pkCompareShader)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
int iDiff = *pkFirstNode - *pkCompareShader;
InBlock.gif    SG_Shader
* pkResult = const_cast<SG_Shader*>(pkFirstNode);
InBlock.gif    SG_Shader
* pkDummy = pkResult;
InBlock.gif
InBlock.gif    
while(pkDummy->GetNext())
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        pkDummy 
= pkDummy->GetNext();
InBlock.gif        
int iDiff2 = *pkDummy - *pkCompareShader;
InBlock.gif        
if(iDiff2 >= iDiff)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            pkResult 
= pkDummy;
InBlock.gif            iDiff 
= iDiff2;
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
return pkResult;
ExpandedBlockEnd.gif}

None.gif
//---------------------------------------------------------
None.gif
void SG_ShaderTree::OutputShaderTreeStruct()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    LOGLISTBEGIN(LOGTYPE_PROFILE,
"");
InBlock.gif    _outputShaderTreeStruct(m_pkRootShader,
1);
InBlock.gif    LOGLISTEND(LOGTYPE_PROFILE);
ExpandedBlockEnd.gif}

None.gif
//---------------------------------------------------------
None.gif
void SG_ShaderTree::_outputShaderTreeStruct(const SG_Shader* pkTreeRoot,
None.gif                                                           
int iTreeLevel)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    SG_Shader
* pkOutputShader = const_cast<SG_Shader*>(pkTreeRoot);
InBlock.gif    
if(!pkOutputShader)
InBlock.gif        
return;
InBlock.gif
InBlock.gif    _outputShaderStruct(pkOutputShader,iTreeLevel);
InBlock.gif
InBlock.gif    
//output child
InBlock.gif
    const SG_Shader* pkChildShader = pkTreeRoot->GetFirstChild();
InBlock.gif    
if(pkChildShader)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        LOGLISTBEGIN(LOGTYPE_PROFILE,
"");
InBlock.gif        _outputShaderTreeStruct(pkChildShader,iTreeLevel 
+ 1);
InBlock.gif        LOGLISTEND(LOGTYPE_PROFILE);
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
//output neighbor
InBlock.gif
    const SG_Shader* pkNeighborShader = pkTreeRoot->GetNext();
InBlock.gif    
while(pkNeighborShader)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        _outputShaderTreeStruct(pkNeighborShader,iTreeLevel);
InBlock.gif        pkNeighborShader 
= pkNeighborShader->GetNext();
ExpandedSubBlockEnd.gif    }

InBlock.gif    
return ;
ExpandedBlockEnd.gif}

None.gif
//---------------------------------------------------------
None.gif
void SG_ShaderTree::_outputShaderStruct(const SG_Shader* pkNode,int iTreeLevel)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
if(!pkNode)
InBlock.gif        
return;
InBlock.gif    
InBlock.gif    Utility::StringType kResult 
= "[";
InBlock.gif    
for(int i = SG_Shader::SF_PAD + 1; i < SG_Shader::SF_MAX_COUNT; i++)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
char cFeature[32= dot.gif{0};
InBlock.gif        
int iID = pkNode->GetShaderFeature(SG_Shader::ShaderFeature(i));
InBlock.gif        sprintf(cFeature,
" %i," ,iID);
InBlock.gif        kResult 
+= cFeature;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
InBlock.gif    kResult 
+= "]";
InBlock.gif    
InBlock.gif    LOGLISTITEM(LOGTYPE_PROFILE,kResult.c_str());
InBlock.gif
InBlock.gif    
InBlock.gif    
return;
ExpandedBlockEnd.gif}

None.gif
//---------------------------------------------------------
None.gif
SG_Shader* SG_ShaderTree::GetFirstNode()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
return m_pkRootShader;
ExpandedBlockEnd.gif}

None.gif
//---------------------------------------------------------
None.gif
SG_Shader* SG_ShaderTree::GetParent(SG_Shader* pkNode)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    SG_Shader
* pkParent = NULL;
InBlock.gif    
InBlock.gif    
if(!pkNode->GetPrev())
InBlock.gif        pkParent 
= pkNode->GetParent();
InBlock.gif    
else
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        SG_Shader
* pkPrev = pkNode->GetPrev();
InBlock.gif        
while(pkPrev->GetPrev())
InBlock.gif            pkPrev 
= pkPrev->GetPrev();
InBlock.gif        assert(pkPrev);
InBlock.gif        pkParent 
= pkPrev->GetParent();
ExpandedSubBlockEnd.gif    }

InBlock.gif    
InBlock.gif    
return pkParent;
ExpandedBlockEnd.gif}

None.gif
//---------------------------------------------------------
None.gif
SG_Shader* SG_ShaderTree::GetNext(SG_Shader* pkNode)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
if(!pkNode)
InBlock.gif        
return NULL;
InBlock.gif
InBlock.gif    
if(pkNode->GetFirstChild())
InBlock.gif        
return pkNode->GetFirstChild();
InBlock.gif    
else if(pkNode->GetNext())
InBlock.gif        
return pkNode->GetNext();
InBlock.gif    
InBlock.gif    SG_Shader
* pkParent = GetParent(pkNode);
InBlock.gif    
InBlock.gif    
while(pkParent && !pkParent->GetNext())
InBlock.gif        pkParent 
= GetParent(pkParent);
InBlock.gif
InBlock.gif    
if(pkParent)
InBlock.gif        
return pkParent->GetNext();
InBlock.gif
InBlock.gif    
return NULL;
ExpandedBlockEnd.gif}

None.gif

转载于:https://www.cnblogs.com/badkeeper/articles/807332.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值