我们为什么要用RTSS.

  Ogre如计算物体位置,纹理,光照都有固定API如(glMatrixFrustumEXT, glLoadmatrix, glTexture, glLight ),使用这些API渲染称之为固定渲染管线,而最新的如D3D11,OpenGL3.0+都在淘汰固定渲染管线功能了,对应的都全力支持可编程管线,用shader实现各个方面的功能.二者详细的区别大家可以google.而Ogre之前默认采用固定渲染管线,对应的D3D9,而Ogre2.0+版本对应的DirectX是D3D11,这个版本已经完全放弃了固定渲染管线的实现,OpenGL因为扩展集的存在,OpenGL3+也还是可以使用固定渲染管线,但是官方的API对应的固定渲染API已经越来越少了,而在移动设备上使用的OpenGL ES2.0同D3D11一样完全不支持固定渲染管线,所以使用固定渲染管线已经不是一个明智的选择.

  主要实现如下功能:

  1.模拟固定管线功能,对于D3D10+,OpenGL ES2.0就能不写着色器代码而使用对应的固定管线功能(顶点转换,模型颜色,灯光,纹理,Alpha混合,雾等).

  2.可定制组合各个功能,定义好相关的功能,可以根据当前条件,选择是否需要相应功能.

  3.易维护,自成生成管理代替每个材质管理材料和程序.

RTSS类介绍.

模拟着色器程序

  简单来说,下面这些类演示如何模拟着色器程序,我们编写一个程序,程序由入口函数和调用函数构成,其中每个函数在前面包含参数,内部包含针对参数和局部变量的各个操作.

  ProgramSet:包含二个模拟着色器程序,一个顶点,一个片断.还包含这二个Program生成对应的GpuProgram,其中GpuProgram就是我们对应的着色器资源(请看前文Ogre GpuProgram分析),插入到Pass中使用.

  Program:在这我们称模拟着色器程序,能转化成GpuProgram,在这主要封装头文件名与函数列表与参数列表,注意这里的参数是在下面的Function外部,针对这整个Program相当于全局函数,同时这些参数要求GPU自动封装的(自动根据场景填值),请看下面的UniformParameter.

  Function:模拟一个函数,包含输入,输出,局部变量,内部包含针对这些参数的原子操作,如赋值,加减乘除,请看下面FunctionInvocation.

  Parameter:模拟参数,主要有Semantic, Content二个主要类型参数, Semantic指明参数语义,如顶点,法线点,非Unknown的Semantic参数一般用做入口函数的参数, 反之Unknown的参数一般用做局部变量.而Content指定语义里的具体内部,如顶点分别有坐标空间,世界空间,视图空间,投影空间.最后GpuConstantType上文链接有说过,指明当前参数float,float2,mat4等类型的.

  UniformParameter: Parameter的子类,包装的由GPU自动管理的参数,如MVP矩阵,一些场景参数如雾,灯光等,用户也可以自定义,但需自己在相应位置更新(具体请看下面SubRenderState),需要注意的是,纹理参数也是用这个包装,会与别的自动管理参数有些区别,后面例说.这类参数直接由Program持有,不由Function持有,后面会绑定到对应的GpuProgram的GpuProgramParameters上.

  ConstParameter: Parameter的泛型子类,一般会做声明局部变量并初始化值.

  FunctionAtom:模拟函数内部的每个原子函数,指明每个原子函数的顺序(分组,组顺序,组内部顺序).抽象类.

  FunctionInvocation: FunctionAtom的子类,具体用来指明每个子函数,小时小到时前所面所说的赋值,加减乘除,点乘,叉乘. 大时大到一些算法如点光,方向光,平行光算法,或者是骨骼动画算法.

  Operand: FunctionInvocation是每子操作,操作的是参数,Operand就是包装的参数,用于FunctionInvocation中,指定参数是传入,传出,传入传出,以及参数的使用位,如使用xy,xz,xyz,xyzw等.

  整个过程差不多如下,在RTSS中,定义了一些常用的FunctionInvocation,我们要做的是生成Program,根据函数目的先想出要用的UniformParameter(场景参数或模型参数),添加头文件,然后生成入口Function,生成要用的Parameter(这里一般是顶点参数),把对应的Parameter包装成Operand给相应的FunctionInvocation使用,最后Function根据顺序排序,生成GpuProgram.

  我们来看下如下代码,加深理解,首先是RTSS文件中,我所说的一些常用的FunctionInvocation的定义.

void FFP_Transform(in float3x3 m, in float3 v, out float3 vOut)
{vOut = mul(m, v);
}
//-----------------------------------------------------------------------------
void FFP_Transform(in float4x4 m, in float4 v, out float4 vOut)
{vOut = mul(m, v);
}
//-----------------------------------------------------------------------------
#ifndef OPENGL_ES_2//-----------------------------------------------------------------------------
void FFP_Transform(in float3x4 m, in float4 v, out float3 vOut)
{vOut = mul(m, v);
}//-----------------------------------------------------------------------------
void FFP_Transform(in float3x4 m, in float3 v, out float3 vOut)
{vOut = mul((float3x3)m, v);
}
//-----------------------------------------------------------------------------
#endif
//-----------------------------------------------------------------------------
void FFP_Transform(in float4x4 m, in float3 v, out float3 vOut)
{vOut = mul((float3x3)m, v);
}

FunctionInvocation

  这里RTSS中一段代码,用于MVP转换,从局部坐标到投影坐标.

bool FFPTransform::createCpuSubPrograms(ProgramSet* programSet)
{Program* vsProgram = programSet->getCpuVertexProgram();Function* vsEntry = vsProgram->getEntryPointFunction();// Resolve World View Projection Matrix.UniformParameterPtr wvpMatrix = vsProgram->resolveAutoParameterInt(GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX, 0);// Resolve input position parameter.ParameterPtr positionIn = vsEntry->resolveInputParameter(Parameter::SPS_POSITION, 0, Parameter::SPC_POSITION_OBJECT_SPACE, GCT_FLOAT4); // Resolve output position parameter.ParameterPtr positionOut = vsEntry->resolveOutputParameter(Parameter::SPS_POSITION, 0, Parameter::SPC_POSITION_PROJECTIVE_SPACE, GCT_FLOAT4);if (!(wvpMatrix.get()) || !(positionIn.get()) || !(positionOut.get())){OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Not all parameters could be constructed for the sub-render state.","FFPTransform::createCpuSubPrograms" );}// Add dependency.vsProgram->addDependency(FFP_LIB_TRANSFORM);FunctionInvocation* transformFunc = OGRE_NEW FunctionInvocation(FFP_FUNC_TRANSFORM,  FFP_VS_TRANSFORM, 0); transformFunc->pushOperand(wvpMatrix, Operand::OPS_IN);transformFunc->pushOperand(positionIn, Operand::OPS_IN);transformFunc->pushOperand(positionOut, Operand::OPS_OUT);vsEntry->addAtomInstance(transformFunc);return true;
}

FFPTransform

  根据这段代码里的参数与函数名,结合我们上面所说,差不多都能理解上面的代码,其中不管是Progrma还是Function,得到参数相应函数前缀都是resolve,简单来说,就是查找相关参数,有则返回,无则添加后返回. Progrma里的addDependency用于添加下面的FunctionInvocation所对应的头文件,其中FFP_LIB_TRANSFORM就是对应的字符串FFPLib_Transform,也就是上面的Cg文件名.而下面的FunctionInvocation中的第一个初始化参数FFP_FUNC_TRANSFORM对应的字符串FFP_Transform,我们可以看到,就是上面的对应函数名,而调用pushOperand把对应参数包装成Operand添加.

渲染状态

  用户使用这里的类来控制材质的渲染状态,定制组合渲染.上面定义了RTSS中模拟着色器程序的组成,这里的类则是根据要实现的效果填充模拟着色器程序.

  SubRenderState:我们前面所说,固定管线的常用功能有顶点转换,模型颜色,灯光,纹理,Alpha混合,雾等,这里每个固定管线的功能对应着一个SubRenderState,当然我们也可以自定义我们的SubRenderState实现某些特效.他的一些相关字段与方法:

  getType():指明当前SubRenderState的类型,如"FFP_Transform","FFP_Fog",如果自己定义的,不要和这些同名.

  getExecutionOrder():指明在RenderState中的顺序,一般的顺序为transorm,color,lighting….(自行查看FFPShaderStage),自定义的需要正确设定这个值.

  createCpuSubPrograms():当前SubRenderState 需要对ProgramSet的更新,包含参数,头文件,原子函数,可以对照前面的FFPTransform代码来看,这是最简单的createCpuSubPrograms代码了.

  updateGpuProgramsParams():有些SubRenderState在渲染Renderable时,需要根据当前Renderable, Pass, 场景参数集合,灯光做相应处理,主要更新参数,如Program中用户自定义而场景自动管理的UniformParameter,当前SubRenderState自定义的参数,或是针对传入的参数的修改.

  preAddToRenderState():在添加前RenderState前,一般针对SGPass中的dstPass的修改,一般是针对自定义的纹理.

  resolveParameters():当前SubRenderState 需要对ProgramSet的参数获取或添加.

  resolveDependencies():当前SubRenderState所需要的头文件.

  addFunctionInvocations():当前SubRenderState需要添加的原子函数.

  RenderState: SubRenderState的集合,记录各个灯光的个数.这个类中的东东虽然不多,但是在RTSS中承上取下,各个类都多多少少和这个类直接联系.

  TargetRenderState: RenderState的子类, RenderState只记录了各个SubRenderState,而这个类还会生成ProgramSet,相应ProgramSet的顶点,片断模拟Program,以及相应模拟Program的入口函数,并把SubRenderState集合更新对应的ProgramSet.(请看上面SubRenderState函数createCpuSubPrograms).

  FFPRenderStateBuilder:方便创建常用固定管线的几类SubRenderState到TargetRenderState.

RTSS材质

  RTSS本质就是针对原来Material自动生成一个新Technique,新Technique中生成新的Pass.新Pass包含RTSS自动生成的着色器资源.

  SGScheme:包含方案名,方案下的SGTechnique集合.方案下的RenderState.

  SGMaterial:原材质名,材质下针对各方案的生成的SGTechnique. SGScheme与 SGMaterial并没包含关系.

  SGTechnique:如上所说,主要包含一个原Technique,一个RTSS生成的Technique,方案名,是那个材质,SGPass列表,Pass对应的RenderState列表.其中createSGPasses()根据原Technique与RTSS生成的Technique分别得到同一索引下的Pass,构成SGPass,如果当前有自定义的RenderState,赋给相应的SGPass.

  SGPass:和SGTechnique一样,包含一个原Pass,一个RTSS生成的Pass.

  buildTargetRenderState():生成TargetRenderState,使用FFPRenderStateBuilder针对TargetRenderState创建固定管线的相应SubRenderState,并合并SGPass的自定义RenderState.

  acquirePrograms():调用下面的ProgramManager,把TargetRenderState生成的着色器资源添加到RTSS生成的Pass里.

  notifyRenderSingleObject():调用TargetRenderState的SubRenderState集合.针对每个SubRenderState调用updateGpuProgramsParams()[此方法前面有说明].

生成着色器

  用于着色质生成.前面只说的模拟着色器如何生成,那么模拟着色器Program如何生成对应的GpuProgram,我们来看如下这几个类.

  ProgramManager:这个类管理所有模拟着色器程序,生成的GpuProgram,以及下面的二个类.主要作用把ProgramSet中的模拟着色器转化成GpuProgram.并关联到对应的Pass上.

  createGpuProgram():使用ProgramWriter(看下面说明)把Program转化成着色器代码,然后根据代码生成HighLevelGpuProgram,设置相应的入口函数,设置profiles,加载.

  createGpuPrograms():根据选择的着色器语言,生成正确的ProgramWriter和ProgramProcessor,然后分别调用createGpuProgram生成顶点和片断着色器程序.

  acquirePrograms():先调用createGpuPrograms()生成顶点和片断着色器,然后关联到Pass中,最后绑定模拟着色器程序中的UniformParameter到对应GpuProgram中的GpuProgramParameters.这样针对GpuProgram中的UniformParameter改动实际是改动到了GpuProgramParameters中.

  ProgramWriter:把模拟着色器程序Program转化成着色器代码,主要把Program的各个部分,头文件,UniformParameter列表,入口函数,原子函数转化成正确的着色器文本.因不同的着色器语言不同的写法,所以子类对应有Cg,glsl,glsles,hlsl.

  ProgramProcessor:重新排列Program顶点和片断入口函数的参数.

  其实最主要的操作应该是ProgramWriter的几个子类,这几个子类才是把Program转化成GpuProgram的关键,其中代码大家可以仔细看看.他和RenderState还有模拟着色器程序的类图大致如下:

RTSS运行流程

  上面我们主要讲解了RTSS中的大部分类,那么这些类是如何开始运行,如何开头,如何更新了,在这先讲一个非常重要,但是前面没有提到的类ShaderGenerator.这个类整合了前面所说的类,并把这个类按照特定顺序执行.先简单说明这个类如下几个方法.

  Initialize():初始化上面所说的ProgramManager,FFPRenderStateBuilder,RTSS文件解析节点(从这里来看,应该先初始RTSS,再调用资源的初始化,否则RTSS的文件节点是解析不到的),创建一个默认的SGScheme.

  addSceneManager():添加一个场景,二个监听事件,这二个监听事件很重要,下面细说.

  createShaderBasedTechnique():根据material创建或返回已经创建的SGMaterial, SGTechnique, SGScheme.并把相应的SGTechnique添加到对应的SGMaterial与SGScheme中.

  validateScheme():对应SGScheme开始验证,针对SGScheme的SGTechnique集合验证,验证过程就是生成SGPass,SGPass调用acquirePrograms完成着色器代码创建并关联到对应的Pass上.这个函数一般由Ogre自动调用.

  invalidateScheme():如果我们修改了SGScheme里的RenderState,就需要告诉RTSS我已经被修改过,请重新验证.

  notifyRenderSingleObject():在渲染模型前,给出模型,Pass,Ogre场景与模型参数,灯光供用户来更新参数,具体请看SubRenderState中的updateGpuProgramsParams().

  我们使用ShaderGenerator时,一般先初始化,然后调用addSceneManager添加场景,在添加场景中会添加如下二个监听类.

  一是SGSceneManagerListener添加模型以渲染通道前,得到当前场景与视窗.主要二个方法preFindVisibleObject与postFindVisibleObjects.

  二是SGRenderObjectListener在渲染当前Renderable前(提供对应Pass,Ogre自动管理参数集,灯光).主要包含notifyRenderSingleObject这个方法.

  这二个事件就是RTSS和Ogre核心交互的基本,这二个事件发生的时机请看上文中渲染目标解析,简单说下,Ogre先把模型添加到渲染通道,这个是MovableObject负责,RTSS中的SGSceneManagerListener的preFindVisibleObject 在这个发生之前,而postFindVisibleObjects在这个这后.然后Ogre开始渲染在渲染通道里的模型,这个是Renderable负责,而RTSS中第二个事件中的notifyRenderSingleObject发生前面所说postFindVisibleObjects后,而在Ogre开始渲染模型前.

  那么SGSceneManagerListener的preFindVisibleObject监听到时,注意到前面所说的发生位置,这个时候还得到的信息不多,大多是场景管理里的一些参数设置以及对应viewport的设置,RTSS得到viewport后开始验证当前Viewport的材质方案,然后在RTSS中已有的材质方案(SGScheme)中查找,如果没找到,Viewport原来该做啥继续做啥,如果找到了,则找到对应的材质方案(SGScheme)中的开始验证.

  首先我们需要知道,SGScheme中的SGTechnique集合如何来的,主要有如下二个方法,在初始化资源文件时,查找到material中的pass包含有rtshader_system节点,那这个材质文件会根据方案名添加对应的方案中.还有就是我们程序员调用方法createShaderBasedTechnique方法,上一种到内部也是调用这个方法.

  接着上面的SGScheme开始验证, 针对SGScheme中的SGTechnique集合中的每个SGTechnique调用buildTargetRenderState(),这个方法首先生成SGPass集合,然后调用SGPass中的buildTargetRenderState(), acquirePrograms(),这二个方法请看前面说明. acquirePrograms这个方法完成后,RTSS生成的着色器代码已经附加到原材质中的新Technique中的新Pass中了.最后关闭SGTechnique中的一个状态,说明已经生成过了.

  如果有用户自定义的SubRenderState,添加到方案中的RenderState后,我们一般要调用invalidateScheme告诉RTSS需要重新验证,这样在下次渲染时, preFindVisibleObject监听到时,就会检测到方案需要重新验证,这样就生成新的着色器代码.

  因为有些参数是自定义的,我们需要在渲染模型前获取某些信息来更新,通过监听SGRenderObjectListener中的notifyRenderSingleObject,我们就可以在相应的SubRenderState里updateGpuProgramsParams 完善参数信息.

  RTSS的整个分析差不多就到这里,如果有什么不对的地方,欢迎大家指出.

转载于:https://www.cnblogs.com/zhouxin/p/4537929.html

Ogre RTSS组件解析相关推荐

  1. 【SSM框架系列】Spring-MVC的组件解析

    SpringMVC完整执行流程 用户发送请求至前端控制器DispatcherServlet. DispatcherServlet收到请求调用HandlerMapping处理器映射器. 处理器映射器找到 ...

  2. element-plus 组件解析 - Collapse 折叠面板

    element-plus 组件解析 - Collapse 折叠面板 1, 组件介绍 2,组件组成 3,组件实现 3.1,el-collapse 1,v-model="activeNames& ...

  3. 跨平台的.NET邮件协议MailKit组件解析

    发起的.NET Core开源组织号召,进展的速度是我自己也没有想到的,很多园友都积极参与(虽然有些人诚心砸场子,要是以我以前的宝脾气,这会应该被我打住院了吧,不过幸好是少数,做一件事总有人说好,也有人 ...

  4. 【转】开源的C# websocket-sharp组件解析

    下面我们介绍一款WebSocket组件websocket-sharp的相关内容. 一.websocket-sharp组件概述 websocket-sharp是一个C#实现websocket协议客户端和 ...

  5. 中国移动oneos框架基础及其组件解析

    <关键字> 中国移动oneos .开发环境 .开机自启动. shell .单元测试. 源码分析 1.oneos系统 1.1 开发手册 OneOS是中国移动针对物联网领域推出的轻量级操作系统 ...

  6. Rasa Core Policy策略组件解析

    RASA CORE Policy (策略组件) RASA NLU模块提供了用户消息中意图.槽位等信息,RASA DST模块提供了对话跟踪功能,记录了用户的历史消息,Policy要根据这些信息预测出,下 ...

  7. ansible-playbook组件解析及操作全解

    playbook是由一个或多个"play"组成的列表.play的主要功能在于将事先归为一组的主机装扮成事先通过ansible中的task定义好的角色.从根本上来将,所谓的task无 ...

  8. Cinder组件解析

    1  Cinder架构图 Cinder是在虚拟机和具体存储设备之间引入了一层"逻辑存储卷"的抽象,Cinder本身并不是一种存储技术,只是提供一个中间的抽象层,Cinder通过调用 ...

  9. React Native组件(四)TextInput组件解析

    相关文章 React Native探索系列 React Native组件系列 1 概述 TextInput组件和Text组件类似,内部都没有使用FlexBox布局,不同的是TextInput组件支持文 ...

最新文章

  1. 每日一皮:前程序员离职后没人想接的代码...
  2. 4 .2 .4 配置存储系统
  3. Python flask 开发工具和框架安装
  4. 文本对抗攻击入坑宝典
  5. 复数卷积 tensorflow_PyTorch 中的傅里叶卷积
  6. python pip下载安装教程_python详细安装pip教程
  7. python调用程序压缩文件_Python实现文件压缩和解压的示例代码
  8. python解析.he4文件
  9. 【转】android开发必看资源URL
  10. VS2005 + VSS2005 的方法
  11. unity3D实现小游戏案例--弹开小球
  12. steam服务器连接不稳定WIN10,小编操作win10系统steam连接不稳的解决步骤
  13. 关于新正方教务系统(湖北工程学院)的one day越权漏洞的说明
  14. 复数基础——负数的虚数根,复共轭,复数加法、减法、乘法、除法_6
  15. tableau货架图制作_Tableau代写制作地图可视化和树形图、条形图
  16. Ajax+JDBC+Json处理多个数据
  17. Liferay的学习
  18. Java【有哪些适合新手练手的Java项目?】
  19. C++制作打字小游戏
  20. 陕西美食羊肉泡馍,舌尖上的美感

热门文章

  1. 华为的折叠手机技术恐怕已无法跟上三星的脚步
  2. C#读取SPSS的SAV文件
  3. 一文带你深入了解函数栈帧的创建和销毁
  4. Axure RP Pro - Download下载 - Axure RP Pro 5.0.0.1515
  5. Android OpenGL ES (十)FrameBuffer离屏渲染
  6. 袋鼠云作为首批建设运营合作伙伴,助力中国(福建)茶产业互联网综合服务平台正式上线
  7. 华为快应用-怎样写一个全局的变量和方法
  8. 数据结构与算法之树(一)
  9. Depth Ranging Performance Evaluation and Improvement for RGB-D Cameras(提升深度测距的性能)
  10. 学会编程,能拿高薪?别再被洗脑了