[原][譯]關於osgEarth::VirtualProgram說明


OE官方英文原文:http://docs.osgearth.org/en/latest/developer/shader_composition.html

cpp中的說明:

  VirtualProgram支持在osgEarth中進行GLSL着色器合成。 它會在運行時自動將着色器功能組裝為完整的着色器程序。 您可以隨時添加或刪除功能(注入點)。
  VirtualProgram(VP)是osg :: StateAttribute。 但是與大多數屬性不同,VP將繼承狀態堆棧中其他VP的屬性。
  VirtualProgram最初是由Wojciech Lewandowski完成的VirtualProgram着色器合成工作改編而成,在OSG的osgvirtualprogram示例中可以看到。

Shader Composition

着色器的合成系統

 

Shader Composition(使用組合着色器的原因)

osgEarth在其幾種渲染模式中使用GLSL着色器。 默認情況下,osgEarth將檢測圖形硬件的功能並自動選擇合適的模式使用。

由於osgEarth依賴着色器,因此作為開發人員,您可能希望自定義渲染或在GLSL中添加自己的效果和功能。 使用着色器的任何人都會遇到相同的挑戰:

  • 着色器程序是整體的。 添加新的着色器代碼要求您復制,修改和替換現有代碼,以免失去其功能。
  • 使您的更改與原始代碼的着色器的更改保持同步是維護的噩夢。
  • 維護着色器main()的多個版本既麻煩又困難。
  • 隨着GLSL代碼庫的復雜性增加和添加更多功能,維護可怕的“超級着色器”變得難以管理。

着色器合成(Shader Composition )通過將着色器管道模塊化來解決這些問題。 您可以在程序中的任何位置添加和刪除功能,而無需復制,粘貼或修改其他人的GLSL代碼。

接下來,我們將討論osgEarth的着色器合成框架的結構。

 

Framework Basics(基礎框架介紹)

組合着色器的框架自動提供main()函數。 您無需編寫它們。 而且,你可以編寫模塊化函數,並告訴框架在哪里執行它們。

下面,我們看看osgEarth創建的main()的偽代碼:

注意: LOCATION_XXXXX 是表示可以在着色器的執行管道中的哪個點插入我們自定義的函數。

 

// VERTEX SHADER:頂點着色器

void main(void)
{
    vec4 vertex = gl_Vertex;

    // "LOCATION_VERTEX_MODEL" user functions are called here:  模型操作
    model_func_1(vertex);
    model_func_2(vertex);
    ...

    vertex = gl_ModelViewMatrix * vertex;

    // "LOCATION_VERTEX_VIEW" user functions are called here:  視口操作
    view_func_1(vertex);
    ...

    vertex = gl_ProjectionMatrix * vertex;

    // "LOCATION_VERTEX_CLIP" user functions are called last:  裁剪操作
    clip_func_1(vertex);
    ...

    gl_Position = vertex;
}


// FRAGMENT SHADER: 片元着色器

void main(void)
{
    vec4 color = gl_Color;
    ...

    // "LOCATION_FRAGMENT_COLORING" user functions are called here:  自定義顏色
    coloring_func_1(color);
    ...

    // "LOCATION_FRAGMENT_LIGHTING" user functions are called here:  光照操作
    lighting_func_1(color);
    ...

    gl_FragColor = color;
}

 

如上,OE已經做出了指定功能注入點的設計決定。這並不是說它們對所有事物都是完美的,而是說OE相信這種方法使框架易於使用,且不太“低級”。

重要提醒:着色器組合框架此時只支持頂點和片段着色器。它不支持幾何或鑲嵌着色器。OE計划在將來增加這一點。

 

VirtualProgram

可編程着色器

osgEarth引入了一個新的osg狀態屬性,名為VirtualProgram的運行時着色器合成器。因為VirtualProgramosg::StateAttribute,你可以將其附加到場景圖中的任何節點上。

使用VirtualProgram的着色器可以在場景樹中作為一個更高層次的渲染存在。

通過這種方式,你可以在osgEarth中添加、組合、重寫每個着色器函數。

在運行時,VirtualProgram將查看當前狀態並組裝一個完整的osg::Program,它使用內置main(),調用VirtualProgram注入所有着色器功能。

 

Adding Functions

添加函數方案:

從我們前面看到的生成主管道中,osgEarth會調用用戶自定義函數。

這些自定義函數不在osgEarth默認生成的着色器中,但可以作為着色器代碼“注入”到管道中各個位置。

例如,讓我們使用用戶自定義函數創建一個簡單的“模糊”效果:

// haze_vertex:   將放在頂點着色器的view部分
out vec3 v_pos;
void setup_haze(inout vec4 vertexView)
{
    v_pos = vertexView.xyz;
}

// haze_fragment:  將放在片元着色器的lighting部分 
in vec3 v_pos;
void apply_haze(inout vec4 color)
{
    float dist = clamp( length(v_pos)/10000000.0, 0, 0.75 );
    color = mix(color, vec4(0.5, 0.5, 0.5, 1.0), dist);
}

// C++:       oe中加入這兩個函數,將兩個着色器函數放入正確位置
VirtualProgram* vp = VirtualProgram::getOrCreate( stateSet );

vp->setFunction( "setup_haze", haze_vertex,   ShaderComp::LOCATION_VERTEX_VIEW);
vp->setFunction( "apply_haze", haze_fragment, ShaderComp::LOCATION_FRAGMENT_LIGHTING);

在本例中,函數setup_haze在內置頂點函數之后,從內置頂點着色器main()調用。這個apply_haze函數在內置片段函數之后從核心片元着色器main()調用。

 

目前OE有六個可插入點,如下:

Location Shader Type Signature
ShaderComp::LOCATION_VERTEX_MODEL VERTEX void func(inout vec4 vertex)
ShaderComp::LOCATION_VERTEX_VIEW VERTEX void func(inout vec4 vertex)
ShaderComp::LOCATION_VERTEX_CLIP VERTEX void func(inout vec4 vertex)
ShaderComp::LOCATION_FRAGMENT_COLORING FRAGMENT void func(inout vec4 color)
ShaderComp::LOCATION_FRAGMENT_LIGHTING FRAGMENT void func(inout vec4 color)
ShaderComp::LOCATION_FRAGMENT_OUTPUT FRAGMENT void func(inout vec4 color)

 

每個VERTEX定位都可讓您在特定坐標空間中的頂點上進行操作。 您可以更改頂點,但必須將其放在相同的空間中。

頂點定位如下:

MODEL 模型: 頂點是幾何中未轉換的原始值。
VIEW 視圖: 頂點相對於眼點,它位於原點(0,0,0),指向-Z軸。在視圖空間中,原始頂點已被gl_ModelViewMatrix轉換.
CLIP 剪輯: 投影的裁剪空間。剪輯空間位於所有三個軸的[-w.w]范圍內,已將原始頂點通過gl_ModelViewProjectionMatrix轉換.

片元定位如下:

COLORING 着色: 在應用照明之前,解析片段顏色時調用這里的函數。紋理或顏色調整通常發生在這一階段。
LIGHTING 照明: 這里的功能影響到片元中的光照等算法。例如計算:太陽照明、凹凸貼圖或法線貼圖等。
OUTPUT 輸出: 這里是設置gl_FragColor的地方。默認情況下,內置片段main()將設置它。但是你可以設置一個輸出着色器來替換這種方式。這樣做的一個典型例子是實現MRT渲染(請參閱osgEarth_mrt示例)。

 

Shader Packages

更多着色器函數庫

Shader組合框架還提供了一個ShaderPackage支持更高級的着色器管理方法:

VirtualProgram Metadata

可編程着色器的元數據

正如我們所看到的,當您向管道中添加一個着色器函數時,可以使用VirtualProgram時,你需要告訴osgEarth要調用的GLSL函數的名稱,以及它在管道中調用的位置,如下所示:

VirtualProgram* vp;
....
vp->setFunction( "color_it_red", shaderSource, ShaderComp::LOCATION_FRAGMENT_COLORING );

這很管用。但是,如果函數名或注入位置發生變化,則需要記住使GLSL代碼與所有傳入setFunction()的參數。

這時,ShaderPackage將更容易使用。以下是一個例子:

#version 110

#pragma vp_entryPoint  color_it_red
#pragma vp_location    fragment_coloring
#pragma vp_order       1.0

void color_it_red(inout vec4 color)
{
    color.r = 1.0;
}

現在不用再調用VirtualProgram::setFunction()函數了,您可以創建一個ShaderPackage,添加您的代碼,並在VirtualProgram中調用Load即可

ShaderPackage package;
package.add( shaderFileName, shaderSource );
package.load( virtualProgram, shaderFileName );

它采用“文件名”,因為着色器可以在外部文件中調用。

這個vp_location取值如下:

  • vertex_model
  • vertex_view
  • vertex_clip
  • fragment_coloring
  • fragment_lighting
  • fragment_output

 

External GLSL Files

外部GLSL文件

這個ShaderPackage允許你從文件或字符串加載GLSL代碼。當你調用add方法,這個庫將會做:(A)首先使用該文件名查找文件並從該文件加載;(B)如果不存在該文件,則使用源字符串中的代碼。

讓我們來看看這個例子:

ShaderPackage package;
package.add( "myshader.frag.glsl", backupSourceCode );
...
package.load( virtualProgram, "myshader.frag.glsl" );

庫將嘗試從GLSL文件加載着色器。它將在OSG_FILE_PATH。如果它找不到文件,它將從軟件包中與該着色器相關聯的備份源代碼中加載着色器。

osgEarth在內部使用這種技術“內聯”儲存着色代碼。這使您可以選擇使用應用程序部署GLSL文件,或者將它們保持在內聯狀態--無論哪種方式,應用程序仍然可以工作。

 

Include Files

引用文件

這個ShaderPackage如果引用其他文件:你的GLSL代碼只要引用其他文件名就可以調用里面的函數。若要包含其他文件,需要使用自定義#pragma,請執行以下操作:

#pragma include myCode.vertex.glsl

 

就像在C++中一樣,include引用將直接內聯加載其他文件(或源代碼)。因此,你所引用的文件必須是結構化的。

再次提醒:引用的內容與引用文件必須用同一個 ShaderPackage.


Concepts Specific to osgEarth

特定於osgEarth的可編程着色器概念

盡管可編程着色器框架包含在osgEarth SDK中,但它實際上與地圖渲染無關。

下面,我們將介紹osgEarth對着色器組合所做的一些特別的操作。

 

Terrain Variables

地形變量

有一些內置的着色器uniformsvariables這是osgEarth地形引擎使用的,也是我們開發者可以使用的。

重要提醒:以前綴   “ OE_ ”  或者  “ osgEarth_ ”  開頭的着色變量請保留給 osgEarth 內部使用。

Uniforms:

oe_tile_key:

(vec4) elements 0-2 hold the x, y, and LOD tile key values; element 3 holds the tile’s bounding sphere radius (in meters)

前三個元素包含x、y和LOD的瓦片鍵值;第四個元素 保存瓦片的包圍盒半徑(以米為單位)。

oe_layer_tex:

(sampler2D) texture applied to the current layer of the current tile

紋理,適用於當前瓦片的當前層

oe_layer_texc:

(vec4) texture coordinates for current tile

當前瓦片的紋理坐標

oe_layer_tilec:

(vec4) unit coordinates for the current tile (0..1 in x and y)

當前瓦片的單位坐標(x和y中的0..1)

oe_layer_uid:

(int) Unique ID of the active layer

活動層的唯一ID

oe_layer_order:

(int) Render order of the active layer

活動層的渲染順序

 oe_layer_opacity:

(float) Opacity [0..1] of the active layer

活動層的不透明度[0到1]

Vertex attributes:

oe_terrain_attr:
 

(vec4) elements 0-2 hold the unit height vector for a terrain vertex, and element 3 holds the raw terrain elevation value

前三個元素為地形頂點的單位高度向量,最后一個元素為原始地形海拔值。

oe_terrain_attr2:
 

(vec4) element 0 holds the parent tile’s elevation value; elements 1-3 are currently unused.

第一個元素為父級瓷磚的高程值;后三個元素目前未使用.

Shared Image Layers

共享圖像層

如果你希望一次訪問多個圖像層。比如:你可能需要一個掩蔽層,以顯示土地和水。你可能真的不想繪制這一層,但您想要使用它來調整其他可見層。你可以用 共享圖像層。在Map,將圖像層標記為共享 (using ImageLayerOptions::shared(),渲染器會將其提供給所有其他層進行二采樣。

詳情參閱   osgearth_sharedlayer.cpp 的用法示例!

 

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////以上是官方文檔原內容的翻譯,下面介紹下目前的OE部分

 

OE目前支持了幾何着色器

// User function injection points.插入點位置:
        enum FunctionLocation
        {
            // vertex is in model space (equivalent to gl_Vertex).模型空間
            LOCATION_VERTEX_MODEL,

            // vertex is in view(aka eye) coordinates, with the camera at 0,0,0 視口空間
            // looking down the -Z axis.
            LOCATION_VERTEX_VIEW,

            // vertex is in post-perspective coordinates; [-w..w] along each axis裁剪空間
            LOCATION_VERTEX_CLIP,

            // tessellation control shader; model space
            LOCATION_TESS_CONTROL,

            // tessellation evalulation shader; model space
            LOCATION_TESS_EVALUATION,

            // geometry shader; inputs are in model space.
            LOCATION_GEOMETRY,

            // fragment is being colored.
            LOCATION_FRAGMENT_COLORING,

            // fragment is being lit.
            LOCATION_FRAGMENT_LIGHTING,

            // fragment output is being assigned.
            LOCATION_FRAGMENT_OUTPUT,

            // not defined.
            LOCATION_UNDEFINED
        };

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM