目标:(四十五)中的问题115
每个着色器文件中都有一个vp_location,rex引擎是根据这个来判断是属于那种着色器类型,如果没有设置vp_location那么该着色器文件将安装在所有管线阶段。
osgEarth/ShaderLoader.cpp
bool
ShaderLoader::load(VirtualProgram* vp,
const std::string& filename,
const ShaderPackage& package,
const osgDB::Options* dbOptions)
{
std::string loc = getPragmaValue(source, "vp_location");
ShaderComp::FunctionLocation location;
bool locationSet = true;
if ( ciEquals(loc, "vertex_model") )
location = ShaderComp::LOCATION_VERTEX_MODEL;
else if ( ciEquals(loc, "vertex_view") )
location = ShaderComp::LOCATION_VERTEX_VIEW;
else if ( ciEquals(loc, "vertex_clip") )
location = ShaderComp::LOCATION_VERTEX_CLIP;
else if ( ciEquals(loc, "tess_control") || ciEquals(loc, "tessellation_control") )
location = ShaderComp::LOCATION_TESS_CONTROL;
else if ( ciEquals(loc, "tess_eval") || ciEquals(loc, "tessellation_eval") || ciEquals(loc, "tessellation_evaluation") || ciEquals(loc, "tess_evaluation") )
location = ShaderComp::LOCATION_TESS_EVALUATION;
else if ( ciEquals(loc, "vertex_geometry") || ciEquals(loc, "geometry") )
location = ShaderComp::LOCATION_GEOMETRY;
else if ( ciEquals(loc, "fragment" ) )
location = ShaderComp::LOCATION_FRAGMENT_COLORING;
else if ( ciEquals(loc, "fragment_coloring") )
location = ShaderComp::LOCATION_FRAGMENT_COLORING;
else if ( ciEquals(loc, "fragment_lighting") )
location = ShaderComp::LOCATION_FRAGMENT_LIGHTING;
else if ( ciEquals(loc, "fragment_output") )
location = ShaderComp::LOCATION_FRAGMENT_OUTPUT;
else
{
locationSet = false;
}
osg::Shader::Type type =
location == ShaderComp::LOCATION_VERTEX_MODEL ||
location == ShaderComp::LOCATION_VERTEX_VIEW ||
location == ShaderComp::LOCATION_VERTEX_CLIP ?
osg::Shader::VERTEX:osg::Shader::FRAGMENT;
osg::Shader* shader = new osg::Shader(type, source);
shader->setName( filename );
vp->setShader( filename, shader );
}
osgEarth组织着色器是有一套流程的,这套流程可以让用户很方便地添加自定义的着色器函数:
1、在构建场景图阶段,加载着色器文件,这些文件只包含不同管线阶段的处理函数,并没有main函数,从文件中#pragma vp_location可以解析出来是顶点或者片段着色器,比如vertex_model、vertex_view、vertex_clip对应顶点着色器中的函数,tess_control、tessellation_control、tess_eval、tessellation_eval、tessellation_eval、tess_evaluation对应细分着色器的函数,vertex_geometry、geometry对应几何着色器,fragment、fragment_coloring、fragment_lighting、fragment_output对应片段着色器。
Rex引擎包含以下着色器文件:
RexEngine.vert.glsl ENGINE_VERT_MODEL 顶点着色器中的获取顶点位置的函数,
RexEngine.frag.glsl ENGINE_FRAG 是片段着色器,
RexEngine.elevation.glsl ENGINE_ELEVATION_MODEL 顶点着色器中获取
RexEngine.gs.glsl ENGINE_GEOM 是几何着色器
RexEngine.Morphing.vert.glsl MORPHING_VERT
RexEngine.NormalMap.frag.glsl NORMAL_MAP_FRAG
RexEngine.NormalMap.vert.glsl NORMAL_MAP_VERT
RexEngine.SDK.vert.glsl SDK 所有着色器阶段的文件
RexEngine.tcs.glsl 是细分着色器中的细分控制着色器,需要ogl4.x版本支持
RexEngine.tes.glsl 是细分着色器中的细分计算着色器,需要ogl4.x版本支持
RexEngine.vert.view.glsl ENGINE_VERT_VIEW
RexEngine.SDK.vert.glsl
RexEngine.frag.glsl
RexEngine.vert.glsl
RexEngine.vert.view.glsl
RexEngine.elevation.glsl
RexEngine.NormalMap.vert.glsl
RexEngine.NormalMap.frag.glsl
RexEngine.Morphing.vert.glsl
2、在场景图渲染阶段,生成各个管线的main函数,并将文件中的函数组织起来,经过编译链接生成着色器程序。
是不是只有顶点和片段着色器有main函数呢,不是的,每个着色器阶段都有main函数。下面的函数负责生成每个着色器阶段的main函数。对于osgEarth2.9还不支持计算着色器。
osgEarth/ShaderFactory.cpp
ShaderComp::StageMask
ShaderFactory::createMains(const ShaderComp::FunctionLocationMap& functions,
const VirtualProgram::ShaderMap& in_shaders,
const VirtualProgram::ExtensionsSet& in_extensions,
std::vector< osg::ref_ptr<osg::Shader> >& out_shaders) const
{
}
osgEarth的着色器框架:
1、顶点着色器框架
// VERTEX SHADER:
#version 330 compatibility
#pragma vp_name VP Vertex Shader Main
#extension GL_ARB_gpu_shader5 : enable
// Vertex stage globals:
float oe_layer_rangeOpacity;
float oe_rex_morphFactor;
vec2 oe_normalMapCoords;
vec3 oe_UpVectorView;
vec3 oe_normalMapBinormal;
vec3 vp_Normal;
vec4 oe_layer_texc;
vec4 oe_layer_texcParent;
vec4 oe_layer_tilec;
vec4 vp_Color;
vec4 vp_Vertex;
// Vertex stage outputs:
out VP_PerVertex {
float oe_layer_rangeOpacity;
float oe_rex_morphFactor;
vec2 oe_normalMapCoords;
vec3 oe_UpVectorView;
vec3 oe_normalMapBinormal;
vec3 vp_Normal;
vec4 oe_layer_texc;
vec4 oe_layer_texcParent;
vec4 oe_layer_tilec;
vec4 vp_Color;
vec4 vp_Vertex;
} vp_out;
// Function declarations:
//从其它着色器文件中提取过来的函数
void oe_rexEngine_vert(inout vec4);
void oe_rexEngine_morph(inout vec4);
void oe_rexEngine_elevation(inout vec4);
void oe_rex_elevateVertexAndSetTexCoords(inout vec4);
void oe_normalMapVertex(inout vec4);
void main(void)
{
vp_Vertex = gl_Vertex;
vp_Normal = gl_Normal;
vp_Color = gl_Color;
// "LOCATION_VERTEX_MODEL" user functions are called here:
//模型空间的顶点处理过程函数
oe_rexEngine_vert(vp_Vertex);
oe_rexEngine_morph(vp_Vertex);
oe_rexEngine_elevation(vp_Vertex);
...
// "LOCATION_VERTEX_VIEW" user functions are called here:
//视口空间的顶点处理过程函数
vp_Vertex = gl_ModelViewMatrix * vp_Vertex;
vp_Normal = normalize(gl_NormalMatrix * vp_Normal);
oe_rex_elevateVertexAndSetTexCoords(vp_Vertex);
oe_normalMapVertex(vp_Vertex);
...
// "LOCATION_VERTEX_CLIP" user functions are called last:
//裁剪空间的顶点处理过程函数
gl_Position = gl_ProjectionMatrix * vp_Vertex;
...
//用于细分、几何、片段着色器使用
vp_out.oe_layer_rangeOpacity = oe_layer_rangeOpacity;
vp_out.oe_rex_morphFactor = oe_rex_morphFactor;
vp_out.oe_normalMapCoords = oe_normalMapCoords;
vp_out.oe_UpVectorView = oe_UpVectorView;
vp_out.oe_normalMapBinormal = oe_normalMapBinormal;
vp_out.vp_Normal = vp_Normal;
vp_out.oe_layer_texc = oe_layer_texc;
vp_out.oe_layer_texcParent = oe_layer_texcParent;
vp_out.oe_layer_tilec = oe_layer_tilec;
vp_out.vp_Color = vp_Color;
vp_out.vp_Vertex = vp_Vertex;
}
用户只需要设计好顶点模型、视图、裁剪处理的功能即可,osgEarth着色器框架会将这些函数功能放入main函数的相应位置,进行处理。当然,每一个功能函数的编写要遵守一定的规则,这样osgEarth着色器框架才能争取识别,规则详见osgEarth的Re