前一篇配置了MOGRE的运行环境,这里记录一些MOGRE基础知识,仅仅是最基础的一些东西。由于本人接触ogre的时间比较短,对于很多知识都是一知半解,所以理解起来不免会有一些错误,本人也希望自己在对ogre知识有了一个较深的认识后能重新温故这篇日记,更改自己的误解或者是对mogre进行补漏。废话不说了,进入正题。
(1)在写ogre应用前,应该了解ogre的启动过程,有:
1 生成一个Root对象
2 定义资源:
3 设置RenderSystem
4 生成RenderWindow
5 初始化资源组(Resource Group)
6 建立场景
7 Rander循环
(2)Ogre的三大基础元素大致包括:
场景管理器:场景节点,动态对象。
资源管理器:资源组管理,资源管理
渲染模块:硬件缓冲区管理,渲染系统,渲染窗口
(3)Ogre中的SceneManagers Entities SceneNodes三个类
SceneManagers管理着所有出现在屏幕上的东西,一个东西出现在在场景中的时候SceneManagers一直跟踪着其位置。你创建一个Camera时SceneManagers也跟踪着它,你创建什么,SceneManagers都跟踪着……
举个小例子:
SceneManager sceneMgr;
SceneNode nodeRoot;
Entity ent = sceneMgr.CreateEntity("Ninja", "ninja.mesh");
nodeRoot = sceneMgr.CreateSceneNode("node0");
sceneMgr.RootSceneNode.AddChild(nodeRoot); //important
SceneNode node1 = sceneMgr.CreateSceneNode("node1");
nodeRoot.AddChild(node1);
node1.AttachObject(ent);
(4)OGRE坐标问题:
确切来说是camera的位置,它指向的位置,实体位置,三者之间的关系。
Ogre采用的是右手坐标系。
Ogre中有一些定义坐标位置和旋转位置的函数:
调用setPosition(30,20,10),那个结点在就在世界空间的位置(30,20,10)
如果我们调用translate(30,20,10),结点就会在位置(40,40,40)
pitch()函数绕X轴旋转,yaw()函数绕Y轴旋转,roll()函数绕Z轴旋转。我们可以使用Ogre::Degree(degree) 或者Ogre::Radian(radian)其中一个来明确指明我们想要旋转的程度
Ogre 3D提供了一个可以使编译器自动转换角度到弧度的操作的Degree()类
Ogre系统中camera和viewport关系:
OGRE抽象出的两个概念则是模拟观察者(人)的位置和眼睛。
一个Viewport是对一个Camera所拍摄到的场景的反映。所以说一个Viewport只能绑定一个Camera
一个Camera所拍摄到的场景可以通过多个Viewport反映到不同的区域,所以一个Camera则可以绑定多个Viewport.
一个Camera同时只可以拍摄一个场景,所以一个Camera只可以绑定一个场景
一个场景可以由多个观察者去观察,所以它可以绑定多个Camera
所以ogre系统中多视图多窗口展现系统场景是可以实现的,而做出类似的效果的前提是对上述几个概念灵活掌握,更重要的是灵活运用。
从代码上来反映问题. 以下是OGRE的伪代码.
Camera * camera1 = scene->CreateCamera("camera1"); (一个camera1 绑定到了scene)
Camera * camera2 = scene->CreateCamera("camera2"); (一个camera2 绑定到了scene)
scene创建了2个Camera对象,即一个场景绑定了多个Camera.
我们可以通过设置Camera的位置,角度等来确定观察者的位置.如:
camera1->SetPosition(Vector3(0,0,100));
camera1->LookAt(Vector3(0,0,0);
camera2->SetPosition(Vector3(0,0,0));
camera2->LookAt(Vector3(-300,0,-300);
Viewport * vp1 = render_win->addViewport(camera1,0,0,0,1,1);
Viewport * vp11 = render_win->addViewport(camera1,1,0.7,0.7,0.3,0.3);
Viewport * vp2 = render_win->addViewport(camera2,2,0,0,0.3,0.3);
这里我们用 vp1和vp11来同时绑定了camera1,不同的只是它们的大小和位置不同而已.
vp2绑定了camera。3个Viewport在render_win上的显示的位置是由他们的Z值决定的。所以顺序是vp1 vp11 vp2.
经过实践证明,几个窗体确实是由camera和viewport造成的。
(5)合成器框架Compositor
合成器框架脚本**.compositior
工作原理:合成器框架是在场景已被渲染后来改变场景的显示,是一种后处理技术。
1.合成器框架将已经渲染的场景渲染到一个texture上去。
2.然后根据需要改变这个texture的内容。
3.为了渲染texture中的改变后的场景,需要创建一个quad用来cover the monitor。
4. 将texture渲染到quad中去(也即是渲染到屏幕上去)。
调用流程:
1. 代码中加入合成器框架。
2. 合成器脚本中定义被渲染到的纹理和输出目标quad。
3. 被渲染到的纹理在mayerial文件夹下面的*.material文件。
4. *.material中定义了用到的fragment_program_ref。
合成器框架这部分,本人也做了一些尝试,这个过程中会遇这样那样的问题,所以还是一知半解,这里就贴了一些摘抄的东西。以待后面再解。
(6)材料设置
material MyMaterial3
{
technique
{
pass
{
texture_unit
{
texture terr_rock6.jpg
}
}
}
}
每一个material XXX 代表是一个材质单元。其中,每一个technique代表一个材质渲染手法,pass是每个渲染通路模式, texture_unit则是一个纹理单元。一个材质脚本允许有多个渲染手法技术,一个渲染手法技术中允许有多个渲染通路模式,一个渲染通道允许有多个纹理单元。
tex_address_mode clamp :在纹理单位段中,添加一行代码告诉Ogre 3D 使用clamp 模式:
wrapping 模式重复的结果。在一块纹理的最左边,纹理又以其右边重新开始重复,纹理下方的重复同理。这种纹理被称为无缝纹理
改变纹理模式为clamp。这个模式使用纹理的边缘像素来填充所有大于1的纹理坐标、在实践中,这意味着一个图片的边缘在模型上得到了拉伸
改变了纹理模式——这次是mirroring。当用于渲染一块像石墙那样的大面积区域时,使用mirror模式就显得比较简单而有效了。每次纹理坐标值大于1时,纹理就得到翻转,然后就如使用wrap模式一般了。
border模式并不是如mirro模设计或wrap模式一般创建了纹理的多份拷贝。当纹理坐标大于1的时候,这个模式画任何东西为边框颜色——默认的颜色显然是黑色的,黑色的RGB颜色值为(0,0,0)。
纹理继承:
material MyMaterial3
{
technique
{
pass
{
texture_unit
{
texture terr_rock6.jpg
}
}
}
}
material MyMaterial4:MyMaterial3
{
technique
{
pass
{
texture_unit
{
set_texture_alias texture1 Water02.jpg
//texture Water02.jpg
}
}
}
}
(texture alias)为另一个可使用的纹理
(7)顶点和片段着色器。
定义着色器。Ogre 3D 需要有关着色器的五条信息。 】
The name of the shader
In which language it is written
In which source file it is stored
How the main function of this shader is called
In what profile we want the shader to be compiled
l 着色器的名称。
l 用哪种语言写的。
l 在哪个文件中储存。
l 着色器的main函数是如何调用的。
我们需要编译着色器的哪些文件。
fragment_program MyFragmentShader1 cg
{
source Ogre3DBeginnersGuideShaders.cg
entry_point MyFragmentShader1
profiles ps_1_1 arbfp1
}
vertex_program MyVertexShader1 cg
{
source Ogre3DBeginnersGuideShaders.cg
entry_point MyVertexShader1
profiles vs_1_1 arbvp1
default_params
{
param_named_auto worldViewMatrix worldviewproj_matrix
}
}
material MyMaterial13
{
technique
{
pass
{
vertex_program_ref MyVertexShader1
{
}
fragment_program_ref MyFragmentShader1
{
}
}
}
}
接着定义着色器:
//片段着色器;现在来到顶点着色器。顶点着色器有三个参数 —— 顶点的位置,顶点变换的位置作为传出变量,并且作为我们用于变换矩阵uniform变量
void MyFragmentShader1(out float4 color: COLOR)
{
color = float4(0,0,1,0);
}
//在着色器内部,使用了矩阵和传入的位置来计算传出位置
void MyVertexShader1(float4 position:POSITION, out float4 oPosition:POSITION,uniform float4x4 worldViewMatrix)
{
oPosition = mul(worldViewMatrix, position);
}
(8)帧监听
基于帧的运动有一些缺点。基于时间的运动更为出众,因为大家需要在所有的电脑上达到同样的运动效果而且在运动速度上有更高的可控性。在第一步,使用Ogre 3D的一个FrameEvent传递给调用的frameStarted() 函数。这个FrameEvent类包含了在短时间内自从上一帧被渲染到现在的时间: (Ogre::Vector3(10,0,0) * evt.timeSinceLastFrame); 这行代码使用这个公式来计算移动模型每帧移动的大小。使用一个三维向量乘以自上一帧到现在的秒数来计算。在当前的情况下,使用了向量(10,0,0)。这意味着是想要模型每秒沿X轴移动10个单位。比如说,每秒渲染10帧;然后对于每一帧,evt.timeSinceLastFrame将会是0.1f。在每帧中,我们用向量(10,0,0)乘以evt.timeSinceLastFrame,那么结果会是(1,0,0).这一结果将会应用于场景结点移动的每一帧。
看mogre快2个礼拜了,对mogre还只是一知半解,接下来再接再厉吧。