以致选拔Model类的Draw方法将模型绘制到显示屏上

【题外话】

上生机勃勃篇小说介绍了3D开荒功底与XNA开垦顺序的完全布局,以至选取Model类的Draw方法将模型绘制到显示器上。本文接着上风流倜傥篇文章继续,介绍XNA中模型的结构、BasicEffect的应用以至顾客输入和分界面呈现的法子等,本文尽量把蒙受的定义都解析清楚,但又避开复杂的数学方面包车型地铁知识,希望对未有接触过3D开采的同班有所扶植。

 

【类别索引】

  1. 从零3D根基入门XNFIT.0(1)——3D开辟幼功
  2. 从零3D底子入门XN君威.0(2)——模型和BasicEffect

 

【文章索引】

  1. Model模型的布局
  2. BasicEffect效果的设置
  3. XNA的顾客输入
  4. XNA分界面包车型的士显示格局

 

【一、Model模型的构造】

上意气风发篇小说使用Model自带的Draw方法完结了一贯将载入的Model绘制到钦赐的岗位上去,可是临时绘制出来的功效并不相符我们的预期,比如下图(下图的模子是因而Maya创设的二个房间卡塔 尔(英语:State of Qatar):

澳门皇冠官网app 1

由此ILSpy查看Microsoft.Xna.Framework.Graphics.Model,能够观看其Draw方法的代码如下:

澳门皇冠官网app 2澳门皇冠官网app 3

 1 public void Draw(Matrix world, Matrix view, Matrix projection)
 2 {
 3     int count = this.meshes.Count;
 4     int count2 = this.bones.Count;
 5     Matrix[] array = Model.sharedDrawBoneMatrices;
 6     if (array == null || array.Length < count2)
 7     {
 8         array = new Matrix[count2];
 9         Model.sharedDrawBoneMatrices = array;
10     }
11     this.CopyAbsoluteBoneTransformsTo(array);
12     for (int i = 0; i < count; i++)
13     {
14         ModelMesh modelMesh = this.meshes[i];
15         int index = modelMesh.ParentBone.Index;
16         int count3 = modelMesh.Effects.Count;
17         for (int j = 0; j < count3; j++)
18         {
19             Effect effect = modelMesh.Effects[j];
20             if (effect == null)
21             {
22                 throw new InvalidOperationException(FrameworkResources.ModelHasNoEffect);
23             }
24             IEffectMatrices effectMatrices = effect as IEffectMatrices;
25             if (effectMatrices == null)
26             {
27                 throw new InvalidOperationException(FrameworkResources.ModelHasNoIEffectMatrices);
28             }
29             effectMatrices.World = array[index] * world;
30             effectMatrices.View = view;
31             effectMatrices.Projection = projection;
32         }
33         modelMesh.Draw();
34     }
35 }

View Code

个中可知,Draw方法通过遍历模型的Mesh,然后再遍历每种Mesh的Effect,并对每一种Effect举行安装,最终动用Mesh的Draw方法将其绘制到荧屏上。

为了领会Model的渲染,大家首先必要通晓Model的构造。实际上,在二个Model对象中,包涵Bone集结(model.Bones卡塔尔国、Mesh集结(model.Meshes卡塔 尔(阿拉伯语:قطر‎以至根Bone(model.Root卡塔尔国多个属性,其结交涉事关如下

澳门皇冠官网app 4

能够观望对于种种ModelMesh,满含大器晚成组ModelMeshPart与三个ParentBone。当中,

  • ModelMesh代表单个能够单独运动的梗概对象。举例,一个car的Model可以满含一个车体(body卡塔 尔(阿拉伯语:قطر‎的ModelMesh、多个轮子(wheel卡塔 尔(英语:State of Qatar)的ModelMesh与黄金时代对门(door卡塔尔国的ModelMesh。
  • ModelMeshPart表示单个同样质地的构件,其象征贰个独立的绘图调用(draw
    call卡塔尔。比方,上述车身可以分包着色的外表、使用意况映射(environment
    mapping卡塔尔国效果的挡风玻璃以导致用法线贴图(normalmap
    texture卡塔 尔(英语:State of Qatar)效果的座椅等等。
  • ModelBone表示了对应的ModelMesh怎么着转换,其饱含二个Transform的转换矩阵。ModelBone是以树形存款和储蓄的,每种ModelBone都有多个父节点甚至若干个子节点。上述的各种ModelMesh都有贰个ParentBone,ModelMesh能够依据ModelBone的调换到分明最后展现的职位等。例如,上述车门的ModelBone与车轮的ModelBone是车身的子节点等等。

由此遍历三个Model中具备的ModelMesh,然后遍历此中具有的ModelMeshPart,况兼依据ModelMesh的ParentBone来将每八个ModelMeshPart绘制到钦赐的地点上就足以绘制出生龙活虎体化的Model。

不过对于每一种ModelMeshPart,其实际渲染的效果都存在Effect的性质中,对于默许来讲,Effect均为BasicEffect。别的,对于ModelBone,其转移矩阵都以相对其本身的Parent来的,不过Model类也提供了二个方法,即CopyAbsoluteBoneTransformsTo(),就能够将各样Bone绝对于RootBone的调换矩阵复制到一个矩阵数组中,然后将其行使到Effect中就可以。这种办法与上述提到的Model.Draw肖似,但是自个儿写的话就足以自定义每一个ModelMeshPart渲染的效劳,当然也可以设置各样ModelMeshPart的渲染地点。

那便是说接下去就依照那个思路去贯彻,同期在安装每三个Effect时,使用Effect提供的应用暗中同意光照的方法EnableDefaultLighting(),启用后效果如下:

澳门皇冠官网app 5

如此那般的作用就高达了大家的预料,按上述的方式完毕的代码如下:

澳门皇冠官网app 6澳门皇冠官网app 7

 1 Matrix world = Matrix.CreateWorld(Vector3.Zero, Vector3.Forward, Vector3.Up);
 2 
 3 Matrix[] transforms = new Matrix[model.Bones.Count];
 4 this.model.CopyAbsoluteBoneTransformsTo(transforms);
 5 
 6 foreach (ModelMesh mesh in model.Meshes)
 7 {
 8     Int32 boneIndex = mesh.ParentBone.Index;
 9 
10     foreach (ModelMeshPart part in mesh.MeshParts)
11     {
12         BasicEffect effect = part.Effect as BasicEffect;
13         
14         effect.EnableDefaultLighting();
15         effect.World = transforms[boneIndex] * world;
16         effect.View = cameraView;
17         effect.Projection = cameraProjection;
18     }
19 
20     mesh.Draw();
21 }

View Code

只是那与刚刚看见的Model.Draw的代码并不相通。实际上,XNA为了简化操作,已经将ModelMeshPart的各种Effect放到了ModelMesh的Effects集合中,只供给遍历那几个集合就足以,而无需再遍历ModelMeshPart,再赢得Effect了。所以上述代码可以简化为如下的代码:

 1 Matrix world = Matrix.CreateWorld(Vector3.Zero, Vector3.Forward, Vector3.Up);
 2 
 3 Matrix[] transforms = new Matrix[model.Bones.Count];
 4 this.model.CopyAbsoluteBoneTransformsTo(transforms);
 5 
 6 foreach (ModelMesh mesh in model.Meshes)
 7 {
 8     Int32 boneIndex = mesh.ParentBone.Index;
 9     
10     foreach (BasicEffect effect in mesh.Effects)
11     {
12         effect.EnableDefaultLighting();
13         effect.World = transforms[boneIndex] * world;
14         effect.View = cameraView;
15         effect.Projection = cameraProjection;
16     }
17 
18     mesh.Draw();
19 }

 

【二、BasicEffect效果的设置】

首先用ILSpy查看下BasicEffect的EnableDefaultLighting()的代码:

public void EnableDefaultLighting()
{
    this.LightingEnabled = true;
    this.AmbientLightColor = EffectHelpers.EnableDefaultLighting(this.light0, this.light1, this.light2);
}

其间this.light0-2为BasicEffect的DirectionalLight0-2,即BasicEffect能够时候的四个光源。而EffectHelpers的EnableDefaultLighting是如此写的:

澳门皇冠官网app 8澳门皇冠官网app 9

 1 internal static Vector3 EnableDefaultLighting(DirectionalLight light0, DirectionalLight light1, DirectionalLight light2)
 2 {
 3     light0.Direction = new Vector3(-0.5265408f, -0.5735765f, -0.6275069f);
 4     light0.DiffuseColor = new Vector3(1f, 0.9607844f, 0.8078432f);
 5     light0.SpecularColor = new Vector3(1f, 0.9607844f, 0.8078432f);
 6     light0.Enabled = true;
 7     light1.Direction = new Vector3(0.7198464f, 0.3420201f, 0.6040227f);
 8     light1.DiffuseColor = new Vector3(0.9647059f, 0.7607844f, 0.4078432f);
 9     light1.SpecularColor = Vector3.Zero;
10     light1.Enabled = true;
11     light2.Direction = new Vector3(0.4545195f, -0.7660444f, 0.4545195f);
12     light2.DiffuseColor = new Vector3(0.3231373f, 0.3607844f, 0.3937255f);
13     light2.SpecularColor = new Vector3(0.3231373f, 0.3607844f, 0.3937255f);
14     light2.Enabled = true;
15     return new Vector3(0.05333332f, 0.09882354f, 0.1819608f);
16 }

View Code

可以看到在启用暗中认可光照里其实是给条件光AmbientLightColor以至三束定向光(蕴莫邪线的取向、漫反射颜色及镜面反射颜色卡塔 尔(英语:State of Qatar)设置了开始时期定义好的颜色,并启用了这么些光源,这三束定向光的颜料(Light1的漫反射光的颜色如下,但其镜面反射光的水彩为深绿卡塔尔国和方向大致如下。

澳门皇冠官网app 10

下图第一个为启用了默许光照后的模子(上生龙活虎篇小说中的dude卡塔尔,第二、三、八个为只启用暗中认可光照的情状光及0、1、2三束定向光华的模子,第七个为未有启用暗许光照的模子(就如上生龙活虎篇发生的机能相同卡塔 尔(阿拉伯语:قطر‎:

澳门皇冠官网app 11

理所必然,在不知凡几场馆下(例如室外的阳光等卡塔尔,大家仅必要壹个光源,届期大家只要禁止使用(DirectionalLight*.Enabled
= false卡塔 尔(阿拉伯语:قطر‎其余四个定向光就可以,当然我们可能还必要矫正光源的颜色等等。

除外利用EnableDefaultLighting,BasicEffect还提供了比较丰硕的参数能够安装。首先来看下上述例子中Effect暗中同意的属性:

澳门皇冠官网app 12

个中与光线有关的:

  • LightingEnabled:是还是不是展开光照(默以为false卡塔尔国。
  • PreferPerPixelLighting:是或不是张开逐像素的普照(默以为false,为逐极点光照卡塔 尔(英语:State of Qatar),逐像素光照相对于逐点光照效果更加好,但速度也更慢,同一时候还供给显卡援助Pixel
    Shader Model 2.0,如果显卡不扶助的话会自行使用逐极点光照替代。
  • AmbientLightColor:意况光颜色(默感觉Vector3.Zero卡塔 尔(阿拉伯语:قطر‎。为了在局地光照模型(模型间的普照互不影响卡塔 尔(英语:State of Qatar)中压实真实感,引进了碰着光的概念。景况光不依附任何光源,但其震慑全数物体。
  • DiffuseColor:漫反射颜色(默以为Vector3.One卡塔尔国。光线照到物体后,物体举办漫反射,其颜色与光线的趋向有关。
  • SpecularColor:镜面反射颜色。光线照到物体后,物体举行全反射,其颜色不仅仅与光线的趋势有关,还与观看(相机卡塔 尔(阿拉伯语:قطر‎的动向有关。
  • EmissiveColor:放射颜色(默以为Vector3.Zero卡塔 尔(阿拉伯语:قطر‎。放射光是指物体发出的光泽,但在有个别光照模型中,实际上不会对任何物体发生影响。
  • DirectionalLight0、DirectionalLight1、DirectionalLight2:三束定向光(每束都席卷光线的样子、漫反射颜色与镜面反射颜色卡塔 尔(英语:State of Qatar)。

此中要求注意的是,在XNA中,颜色的储存并不是采纳的Color(AENVISIONGB或ABGQX56卡塔尔,而是接受的Vector3(或Vector4卡塔尔。对于Vector3,其x、y、z多个轻重存款和储蓄的各自是XC60、G、B分别除以255的浮点值(Vector4的w分量存款和储蓄的是Alpha通道除以255的浮点值),所以Vector3.Zero即为浅灰,而Vector3.One为卡其色。当然XNA也提供了一个Color类,并且Color也提供了提供了一直转变为Vector3(或Vector4卡塔 尔(英语:State of Qatar)的不二等秘书诀ToVector3()(或ToVector4()卡塔尔国。

除此而外,BasicEffect还协理设置雾的效果:

  • FogEnabled:是还是不是张开雾的魔法(默感觉false卡塔尔国。
  • FogColor:雾的水彩(默以为Vector3.Zero卡塔 尔(阿拉伯语:قطر‎。
  • FogStart:雾间隔相机的初阶(近期卡塔 尔(英语:State of Qatar)值(暗中认可为0.0F卡塔 尔(英语:State of Qatar),那些间距之内的东西不受雾的熏陶。
  • FogEnd:雾间距相机的截至(最远卡塔 尔(阿拉伯语:قطر‎值(私下认可为1.0F卡塔尔国,那几个间隔之外的事物完全看不清。

也正是说,雾将会在离开相机(FogStart –
FogEnd)的地点发生,这一个间隔须要基于物体所在的地点决定。设Distance为实体间隔相机的偏离,则Distance<FogStart<FogEnd时,物体不受雾的熏陶,与从不雾时相仿;当FogStart<FogEnd<Distance时,物体完全看不清(即物体全体为雾的水彩卡塔尔国;当FogStart<Distance<FogEnd时,物体受雾的熏陶,物体离FogEnd越近则越看不清。

澳门皇冠官网app,比方当人的模子在(0, 0, 0),相机在(120, 120,
120)处,雾的颜色为Gray。下图第三个为未有加雾的功能,第三个为FogStart –
FogEnd为200 – 300,第多少个为1 – 300,第几个为1 – 100。

澳门皇冠官网app 13

 

【三、XNA的顾客输入】

在暗中同意生成XNA程序中的Update方法里,有二个收获GamePad的情形,当顾客1的GamePad按下了“Back”键后将会脱离程序。微软对客户输入的支撑都在Microsoft.Xna.Framework.Input中,除了GamePad之外,微软还协助获取Keyboard、Mouse那三种的景况。其余在Microsoft.Xna.Framework.Input.Touch中,还应该有TouchPanel能够拿走触摸的动静。与GamePad相似,其余的这个情状也都以透过微软提须求类中的GetState()方法进行获取。

譬喻要博取键盘和鼠标的场所,大家能够透过如下情势:

KeyboardState kbState = Keyboard.GetState();
MouseState mouseState = Mouse.GetState();

对于判断键盘的按键,能够经过如下的办法得到是不是按下了钦点开关:

Boolean pressed = kbState.IsKeyDown(Keys.Enter);

而对于鼠标的按钮,则须要决断按钮的ButtonState才方可,譬如剖断鼠标左键是或不是按下:

Boolean pressed = (mouseState.LeftButton == ButtonState.Pressed);

而外,假诺要认清鼠标是还是不是在程序区域内,能够由此如下的艺术推断

if (this.GraphicsDevice.Viewport.Bounds.Contains(mouseState.X, mouseState.Y))
{
    //TODO
}

尽管在超多动静下,假使让客户操作鼠标的话会在程序内彰显七个自定义的指针。但不常写个小程序,为了轻松希望直接采取系统的指针,大家得以在程序的放四地点(构造方法、Initialize以至Update也可卡塔尔国写如下的代码,就足以展现鼠标指针了,反之则能够掩瞒:

this.IsMouseVisible = true;

 

【四、XNA界面包车型地铁呈现格局】

暗中同意情形下,运营XNA的程序会自行以800*480的分辨率展现,若要纠正显示的分辨率,其实很简单,仅供给在Game的构造方法中增加如下代码就可以:

graphics.PreferredBackBufferWidth = 1024;
graphics.PreferredBackBufferHeight = 768;

那般XNA的主次就能够遵照我们设定的分辨率展现了。除了那一个之外,要是我们期待XNA的顺序能全屏显示,大家还是能加上如下的代码:

graphics.IsFullScreen = true;

当然大家还足以让客商来切换全屏与窗口化,但是那行代码写在Update()中是不起功能的,然则XNA提供此外三个格局,便是graphics.ToggleFullScreen()。举例大家要求按F键举办全屏与窗口化的切换,能够编写如下的代码:

KeyboardState kbState = Keyboard.GetState();
if (kbState.IsKeyDown(Keys.F))
{
    graphics.ToggleFullScreen();
}

 

【相关链接】

  1. Model
    Class:http://msdn.microsoft.com/en-us/library/Microsoft.Xna.Framework.Graphics.Model.aspx
  2. Models, meshes, parts, and
    bones:http://blogs.msdn.com/b/shawnhar/archive/2006/11/20/models-meshes-parts-and-bones.aspx
  3. What Is a Model
    Bone?:http://msdn.microsoft.com/en-us/library/dd904249.aspx
  4. BasicEffect
    Lighting:http://rbwhitaker.wikidot.com/basic-effect-lighting
  5. BasicEffect Fog:http://rbwhitaker.wikidot.com/basic-effect-fog
  6. 同台学WP7 XNA游戏开拓(七.
    3d基本光源):http://www.cnblogs.com/randylee/archive/2011/03/09/1978312.html
  7. 【D3D11游戏编制程序】学习笔记十八:光照模型:http://blog.csdn.net/bonchoix/article/details/8430561

相关文章