這幾天看了GPU Gems Ch32之後開始注意Cg裡Interface的功能,上網google了一下資料還真少,除了Cg User manual之外幾乎沒有甚麼進一步的Example,既然這麼少那就讓小弟稍微整理下這幾天將此功能整合進PackedGL的心得吧!
首先,甚麼是Interface?我們用C++裡的抽象類別來解釋,抽象類別就是定義介面而不實做,對於User來說它只需要知道怎麼用就好,而其中的實做就交由開發人員來負責,最常看到的地方可能是Library裡,舊版本的實作可能比較慢,給個範例:
class Basic
{
public:
// User use this, no need to know how to implement.
virtual int pow( int Base, int Power ) = 0;
};
class A : public Basic
{
public:
virtual int pow( int Base, int Power )
{
while(Power!=0) { Base *= Base; Power--; }
return Base ;
}
};
class B : public Basic
{
public:
virtual int pow( int Base, int Power ) { return std::pow(Base, Power); }
}
Interface這個概念讓Sahder code也可以有如同上述的功能,定意好整個Shade的framework(抽象類別)之後,再採取不同的實作方式,達到不同的Rendering的效果,來看範例:
uniform sampler texture;
interface Color
{
float4 Cal( float4 color );
};
struct NegativeColor : Color
{
float4 Cal( float4 color ) { return (1.0 - color); }
}
struct BrightnessColor : Color
{
float4 Cal( float4 color )
{
float B = (0.2126*color.r) + (0.7152*color.g) + (0.0722*color.b);
return float4( B, B, B, 1.0 );
}
}
float4 PixelMain( VertexOUT In, uniform Color C ) : COLOR
{
return C.Cal( tex2D( texture, In.texcoord ) );
}
當使用這個PixelShader的時,可以依據狀況選擇Rendering的結果是“負片效果”或者“灰階效果”,基本上使用的還是同一個PixelMain為Sahder的進入點。神奇吧!!說穿了其實Cg只是幫你做這件事:
//果是負片效果,source code會被替換成:
float4 PixelMain( VertexOUT In, uniform Color C ) : COLOR
{
return (1.0 - color);
}
//如果是灰階效果,source code會被替換成:
float4 PixelMain( VertexOUT In, uniform Color C ) : COLOR
{
float B = (0.2126*color.r) + (0.7152*color.g) + (0.0722*color.b);
return float4( B, B, B, 1.0 );
}
只要將Sahder的架構定義好,根據物件上的Material屬性,隨時切換至實作模式,就可以達到所需的效果,這辦法在很多Shader系統中都看的到,差別在Cg提供了內建的方法幫你完成這件事,如果是使用HLSL或者GLSL,你必須自行對Shader code(文字檔)做操作,在適當的時間點做Sahder code的替換
至於要App中Cg提供了哪些API來達成這件事呢?首先必須先將Compile調成手動Compile模式,cgSetAutoCompile(context, CG_COMPILE_MANUAL);,因為在未選定實做模式前Shader code是不完整的,無法Cpmile成功是必然的,接下來透過:
CGtype nrmType = cgGetNamedUserType( prog, "NegativeColor " );
CGparameter stdNorm = cgCreateParameter( context, nrmType );
拿到NegativeColor的handler,接著將實做與Interface做連結:
CGparameter normIface = cgGetNamedParameter(prog, "Color");
cgConnectParameter(stdNorm, normIface);
完成以上動作後一個完整的Sahdre code就完成了,最後就手動呼叫cgCompileProgram(prog);
References:
GPU Gems: Chapter 32. An Introduction to Shader Interfaces
GPU Gems: Chapter 36. Integrating Shaders into Applications
GPU Gems2: Chapter 13. Implementing the mental images Phenomena Renderer on the GPU
ShaderX 6: 8.1 A Flexible Material System in Design by Maxime Beaudoin
沒有留言:
張貼留言