时隔多日,先回想一下,ogre把资源配置文件称为脚本。ogre内置了几种脚本。
ScriptCompilerManager::ScriptCompilerManager()
{
OGRE_LOCK_AUTO_MUTEX;
mScriptPatterns.push_back("*.program");
mScriptPatterns.push_back("*.material");
mScriptPatterns.push_back("*.particle");
mScriptPatterns.push_back("*.compositor");
mScriptPatterns.push_back("*.os");
// ...
}
在资源文件里打开几个指定后缀的文件。
Examples.material
material Examples/SphereMappedRustySteel
{
technique
{
pass
{
texture_unit
{
texture RustySteel.jpg
}
texture_unit
{
texture spheremap.png
colour_op_ex add src_texture src_current
colour_op_multipass_fallback one one
env_map spherical
}
}
}
}
.pbr.program
vertex_program glTF2/PBR_vs hlsl glsl glsles
{
source pbr-vert.glsl
preprocessor_defines HAS_NORMALS,HAS_TANGENTS,HAS_UV
}
fragment_program glTF2/PBR_fs_glsl glsl
{
source pbr-frag.glsl
preprocessor_defines MANUAL_SRGB,SRGB_FAST_APPROXIMATION,HAS_NORMALS,HAS_TANGENTS,HAS_BASECOLORMAP,HAS_NORMALMAP,HAS_EMISSIVEMAP,HAS_METALROUGHNESSMAP,HAS_OCCLUSIONMAP,USE_IBL,USE_TEX_LOD
}
Examples.particle
particle_system Examples/GreenyNimbus
{
material Examples/FlarePointSprite
particle_width 35
particle_height 35
cull_each false
quota 5000
billboard_type point
point_rendering true
// Area emitter.
emitter Box
{
angle 30
emission_rate 30
time_to_live 1
direction 0 1 0
velocity 0
colour_range_start 1 1 0
colour_range_end 0.3 1 0.3
width 60
height 60
depth 60
}
// Make 'em float upwards.
affector LinearForce
{
force_vector 0 100 0
force_application add
}
// Fader.
affector ColourFader
{
red -0.25
green -0.25
blue -0.25
}
}
ssao.compositor
compositor SSAO/Volumetric // Szirmay-Kalos et al 2010
{
technique
{
texture_ref occlusion SSAO/GBuffer occlusion
target occlusion
{
input none
pass render_quad
{
material SSAO/Volumetric
}
}
}
}
.os(没找到)
//...
从上面的文件内容以及查找个ScriptCompiler分析,
.material 是材质
.program 是 shader
.particle 是粒子
.compostor 是后处理
.os 暂时不知道
但是,重点来了,Examples.material 里面发现了其他东西
fragment_program Examples/MorningCubeMapHDRfp cg
{
source hdr.cg
entry_point morningcubemap_fp
profiles ps_2_0 arbfp1
}
在 .material 文件里发现了 .program的内容。这几个脚本文件实际上没有明确的界限,可以混搭?什么乱七八糟的,定义了特定后缀,不需要遵守?定义它们干嘛?
算了算了,已经不是第一次吐槽了。
按照顺序,先看看每一种脚本怎么加载。都有哪些内容。
竟然 这个类叫做,ScriptComplierManager,那么就有 ScriptComplier,找到了 ScriptComplier,却没找到任何ScriptComplier的子类,难道就一个 ScriptComplier?就一个还管理个啥?继续继续
在 ScriptComplierManager 类中查找 ScriptCompiler
ScriptCompiler mScriptCompiler;
真的只有一个!???那么所有的脚本都是通过它来解析的?难怪可以混搭。
继续找,在 ScriptCompilerManager里找到一个函数
void ScriptCompilerManager::parseScript(DataStreamPtr& stream, const String& groupName)
{
ConcreteNodeListPtr nodes =
ScriptParser::parse(ScriptLexer::tokenize(stream->getAsString(), stream->getName()), stream->getName());
{
// compile is not reentrant
OGRE_LOCK_AUTO_MUTEX;
mScriptCompiler.compile(nodes, groupName);
}
}
下断点调试,看看堆栈,找到它正在编译的脚本:
\Media\packs\SdkTrays.zip 中的 SdkTrays.material
打开它,回到 parseScript函数,
它首先分析 token,调试发现又一个吐槽点,这个 skytrays.mateial 竟然找到了 718 个token,甚至连注释跟空行都算在内了。而且注释里的每一个文字都当成一个token。
继续,分析完所有的token,就分析每一个token,创建 ConcreteNode,然而,它竟然连 # 也当成了一个Node。不仅如此,什么空行, ctrl ,都当成了node,这完全就是一个无特定定义的文本解析器。作为一个特定后缀,特殊定义的文本,有点浪费时间。注释分析来干嘛。每一个token都是有特定意义的,不如直接分析来得快。
所以,只要是文本格式的都可以通过它来分析,无关后缀,无关格式。混搭啥的,小意思了。
当然,为什么脚本编译性能考虑,还是把注释,空行啥的,去掉吧。
既然,这只是经过了文本分析器,它分析完后,还是文本,当然也不具备特定的意义了。那,它是什么时候成为有特定意义的对象的呢?换一个问法,Material 是什么时候new的呢?问题转换后,就很容易了。直接在 Material的构造函数里下断点。
调试发现,在 compile之前,创建几个material :DefaultSettings, BaseWhite, BaseWhiteNoLighting。继续,分析完后,通过 ScriptTranslator 转换为 Material等。通过各种 Translator 转换成各种类型。这其中有两个类型比较特别,一个是gpuprogram,一个是texture,这两个都是需要转换成硬件/平台API支持的类型的。那么,他们是在这个时候编译/加载的吗?
使用的是D3D11,D3D11 shader, D3D11Texture,老规律,断点调试。
得到的结果是, texture 实际被使用的时候才加载成D3D11Texture。例如,SetMateriaName(...)的时候创建D3D11Texture。gpu program 有点奇怪,在此时,它会先编译一遍默认的参数,实际使用时通过RTShader再编译一遍。第一遍的编译,应该只是为了获取shader中的参数,RTShader才是真正使用的。需要后续再细看。
那么,资源脚本如何编译的已经了解了。就具体看看每个对象的配置。也就是各个 Translator。translator没有单个的文件,都在 OgreBuildInScriptTranslators.h里。
- MaterialTranslator
- TechniqueTranslator
- PassTranslator
- TextureUnitTranslator
- SamplerTranslator
- TextureSourceTranslator
- GpuProgramTranslator
- SharedParamsTranslator
- ParticleSystemTranslator
- ParticleEmitterTranslator
- ParticleAffectorTranslator
- CompositorTranslator
- CompositionTechniqueTranslator
- CompositionTargetPassTranslator
- CompositionPassTranslator
先从 MaterialTranslator 开始:
void MaterialTranslator::translate(ScriptCompiler *compiler, const AbstractNodePtr &node)
{
// ...
case ID_LOD_VALUES:
case ID_LOD_DISTANCES:
case ID_LOD_STRATEGY:
// ...
}
发现里面有很多的ID,直接看这些ID的定义,找到了所有的buildInID。
enum
{
ID_MATERIAL = 3,
ID_VERTEX_PROGRAM,
ID_GEOMETRY_PROGRAM,
ID_FRAGMENT_PROGRAM,
ID_TECHNIQUE,
ID_PASS,
ID_TEXTURE_UNIT,
ID_VERTEX_PROGRAM_REF,
ID_GEOMETRY_PROGRAM_REF,
ID_FRAGMENT_PROGRAM_REF,
ID_SHADOW_CASTER_VERTEX_PROGRAM_REF,
ID_SHADOW_CASTER_FRAGMENT_PROGRAM_REF,
ID_SHADOW_RECEIVER_VERTEX_PROGRAM_REF,
ID_SHADOW_RECEIVER_FRAGMENT_PROGRAM_REF,
ID_SHADOW_CASTER_MATERIAL,
ID_SHADOW_RECEIVER_MATERIAL,
// ...
ID_END_BUILTIN_IDS
};
这些就是脚本文件内容的定义了。了解完这些ID,并弄清层级关系,就知道脚本的所有功能了。
这些值是枚举,而文本中是 字符串,字符串如何转换为枚举的呢。通过搜索任一ID发现在ScriptCompiler::initWordMap里进行了一一对应。
void ScriptCompiler::initWordMap()
{
mIds["on"] = ID_ON;
mIds["off"] = ID_OFF;
mIds["true"] = ID_TRUE;
mIds["false"] = ID_FALSE;
mIds["yes"] = ID_YES;
mIds["no"] = ID_NO;
// ...
}
继续回到 MaterialTranslator,它是通过ID,来获取值,设置到对应的属性里。知道了这些,就不需要每一个translator都看了。只要知道了每个ID的意义以及层级结构就可以了。
- ID_MATERIAL
- ID_LOD_VALUES
- ID_LOD_DISTANCES
- ID_LOD_STRATEGY
- ID_RECEIVE_SHADOWS
- ID_SET_TEXTURE_ALIAS
- ID_TECHNIQUE
- ID_SCHEME
- ID_LOD_INDEX
- ID_SHADOW_CASTER_MATERIAL
- ID_SHADOW_RECEIVER_MATERIAL
- ID_GPU_VENDOR_RULE
- ID_GPU_DEVICE_RULE
- ID_PASS
- ID_AMBIENT
- ID_DIFFUSE
- ID_SPECULAR
- ID_EMISSIVE
- ID_SCENE_BLEND
- ID_SEPARATE_SCENE_BLEND
- ID_SCENE_BLEND_OP
- ID_SEPARATE_SCENE_BLEND_OP
- ID_DEPTH_CHECK
- ID_DEPTH_WRITE
- ID_DEPTH_BIAS
- ID_DEPTH_FUNC
- ID_ITERATION_DEPTH_BIAS
- ID_ALPHA_REJECTION
- ID_ALPHA_TO_COVERAGE
- ID_LIGHT_SCISSOR
- ID_LIGHT_CLIP_PLANES
- ID_TRANSPARENT_SORTING
- ID_ILLUMINATION_STAGE
- ID_CULL_HARDWARE
- ID_CULL_SOFTWARE
- ID_NORMALISE_NORMALS
- ID_LIGHTING
- ID_SHADING
- ID_POLYGON_MODE
- ID_POLYGON_MODE_OVERRIDEABLE
- ID_FOG_OVERRIDE
- ID_COLOUR_WRITE
- ID_MAX_LIGHTS
- ID_START_LIGHT
- ID_LIGHT_MASK
- ID_ITERATION
- ID_LINE_WIDTH
- ID_POINT_SIZE
- ID_POINT_SPRITES
- ID_POINT_SIZE_ATTENUATION
- ID_POINT_SIZE_MIN
- ID_POINT_SIZE_MAX
- ID_FRAGMENT_PROGRAM_REF
- ID_VERTEX_PROGRAM_REF
- ID_GEOMETRY_PROGRAM_REF
- ID_TESSELLATION_HULL_PROGRAM_REF
- ID_TESSELLATION_DOMAIN_PROGRAM_REF
- ID_COMPUTE_PROGRAM_REF
- ID_SHADOW_CASTER_VERTEX_PROGRAM_REF
- ID_SHADOW_CASTER_FRAGMENT_PROGRAM_REF
- ID_SHADOW_RECEIVER_VERTEX_PROGRAM_REF
- ID_SHADOW_RECEIVER_FRAGMENT_PROGRAM_REF
- ID_FRAGMENT_PROGRAM
- ID_VERTEX_PROGRAM
- ID_GEOMETRY_PROGRAM
- ID_TESSELLATION_HULL_PROGRAM
- ID_TESSELLATION_DOMAIN_PROGRAM
- ID_COMPUTE_PROGRAM
- ID_TEXTURE_UNIT
- ID_TEX_ADDRESS_MODE
- ID_TEX_BORDER_COLOUR
- ID_FILTERING
- ID_CMPTEST
- ID_CMPFUNC
- ID_COMP_FUNC
- ID_MAX_ANISOTROPY
- ID_MIPMAP_BIAS
- ID_SAMPLER_REF
- ID_TEXTURE_ALIAS
- ID_TEXTURE
- ID_ANIM_TEXTURE
- ID_CUBIC_TEXTURE
- ID_TEX_COORD_SET
- ID_COLOUR_OP
- ID_COLOUR_OP_EX
- ID_COLOUR_OP_MULTIPASS_FALLBACK
- ID_ALPHA_OP_EX
- ID_ENV_MAP
- ID_SCROLL
- ID_SCROLL_ANIM
- ID_ROTATE
- ID_ROTATE_ANIM
- ID_SCALE
- ID_WAVE_XFORM
- ID_TRANSFORM
- ID_BINDING_TYPE
- ID_CONTENT_TYPE
粗略列举了material包含的一些ID,具体细分的话,会很长的时间,等到具体使用的时候再考虑,现在只是梳理。
GpuTranslator
vertex_program glTF2/PBR_vs hlsl glsl glsles
{
source pbr-vert.glsl
preprocessor_defines HAS_NORMALS,HAS_TANGENTS,HAS_UV
}
fragment_program glTF2/PBR_fs_glsl glsl
{
source pbr-frag.glsl
preprocessor_defines MANUAL_SRGB,SRGB_FAST_APPROXIMATION,HAS_NORMALS,HAS_TANGENTS,HAS_BASECOLORMAP,HAS_NORMALMAP,HAS_EMISSIVEMAP,HAS_METALROUGHNESSMAP,HAS_OCCLUSIONMAP,USE_IBL,USE_TEX_LOD
}
fragment_program glTF2/PBR_fs_hlsl hlsl glsles
{
source pbr-frag.glsl
target ps_2_a
preprocessor_defines MANUAL_SRGB,SRGB_FAST_APPROXIMATION,HAS_NORMALS,HAS_TANGENTS,HAS_BASECOLORMAP,HAS_NORMALMAP,HAS_EMISSIVEMAP,HAS_METALROUGHNESSMAP,HAS_OCCLUSIONMAP,USE_IBL
}
fragment_program glTF2/PBR_fs unified
{
delegate glTF2/PBR_fs_glsl
delegate glTF2/PBR_fs_hlsl
}
gpu program 稍微不一样,
vertex_program glTF2/PBR_vs hlsl glsl glsles, 表示 类型:顶点着色器,名称: glTF2/PBR_vs,支持的shader语言:hlsl, glsl, glsles
- source 源文件
- target shader类型以及版本
- preprocessor_defines 预定义宏,与C/C++宏定义作用相同
fragment_program glTF2/PBR_fs unified 这种定义方式表示未定义语言
- delegate 表示它再运行时可使用的配置
通过delegeta的方式,在运行时决定使用哪一种语言,每种语言又可以用不同的配置。
- compositor
- ID_Composition_Technique
- ID_TEXTURE
- ID_TARGET_WIDTH
- ID_TARGET_HEIGHT
- ID_TARGET_WIDTH_SCALED
- ID_TARGET_HEIGHT_SCALED
- ID_POOLED
- ID_CUBIC
- ID_SCOPE_LOCAL
- ID_SCOPE_CHAIN
- ID_SCOPE_GLOBAL
- ID_GAMMA
- ID_NO_FSAA
- ID_DEPTH_POOL
- ID_TEXTURE_REF
- ID_SCHEME
- ID_COMPOSITOR_LOGIC
- //...
- ID_TEXTURE
- ID_Composition_Technique
compositor的层级关系,在enum中已经分出来了,就不用再自己列举了。为什么上面的它不表明层级呢?
ID_COMPOSITOR,
ID_TARGET,
ID_TARGET_OUTPUT,
ID_INPUT,
ID_PREVIOUS,
ID_TARGET_WIDTH,
ID_TARGET_HEIGHT,
ID_TARGET_WIDTH_SCALED,
ID_TARGET_HEIGHT_SCALED,
ID_COMPOSITOR_LOGIC,
ID_TEXTURE_REF,
ID_SCOPE_LOCAL,
ID_SCOPE_CHAIN,
ID_SCOPE_GLOBAL,
ID_POOLED,
//ID_GAMMA, - already registered for material
ID_NO_FSAA,
ID_DEPTH_POOL,
ID_ONLY_INITIAL,
ID_VISIBILITY_MASK,
ID_LOD_BIAS,
ID_MATERIAL_SCHEME,
ID_SHADOWS_ENABLED,
ID_CLEAR,
ID_STENCIL,
ID_RENDER_SCENE,
ID_RENDER_QUAD,
ID_IDENTIFIER,
ID_FIRST_RENDER_QUEUE,
ID_LAST_RENDER_QUEUE,
ID_QUAD_NORMALS,
ID_CAMERA_FAR_CORNERS_VIEW_SPACE,
ID_CAMERA_FAR_CORNERS_WORLD_SPACE,
ID_BUFFERS,
ID_COLOUR,
ID_DEPTH,
ID_COLOUR_VALUE,
ID_DEPTH_VALUE,
ID_STENCIL_VALUE,
ID_CHECK,
ID_COMP_FUNC,
ID_REF_VALUE,
ID_MASK,
ID_FAIL_OP,
ID_KEEP,
ID_INCREMENT,
ID_DECREMENT,
ID_INCREMENT_WRAP,
ID_DECREMENT_WRAP,
ID_INVERT,
ID_DEPTH_FAIL_OP,
ID_PASS_OP,
ID_TWO_SIDED,
.os 文件没有发现,暂时忽略吧。
到这里,就分析完了脚本。知道了材质,纹理,shader什么时候加载的。具体的数值如何使用,等待使用时再分析。
纹理,材质,shader,资源当中还有模型没有加载。看看模型如何加载的。通过之前的学习,知道了模型需要通过SceneManager::CreateEntity来加载。既然知道了,就不需要再看了。
之前导入的是.mesh文件。还能加载模型哪些文件呢?这个文件就需要回到cmake的时候了,cmake的时候有一个选项叫做,OGRE_BUILD_PLUGIN_ASSIMP,ogre的插件,打开plugins.cfg,有一行配置 Plugin=Codec_Assimp,如果这行没有被注释,就说明我们使用了 Assimp插件。
Assimp : The official Open-Asset-Importer-Library Repository. Loads 40+ 3D-file-formats into one unified and clean data structure.
assimphttps://github.com/assimp/assimphttps://github.com/assimp/assimp
使用了Assimp可以加载多达40多种3D模型。
资源还包括动画,通过之前的学习,知道了动画也包含在模型里了。
到这里,资源模块就了解完了。
to be continue...