从零3D基础入门XNA 4.0(2)——模型和BasicEffect

作者: 游戏王朝  发布:2019-11-06

【题外话】

上豆蔻梢头篇文章介绍了3D开辟底工与XNA开采顺序的欧洲经济共同体布局,以至选用Model类的Draw方法将模型绘制到显示器上。本文接着上风流倜傥篇文章继续,介绍XNA中模型的结构、BasicEffect的施用以致客商输入和分界面显示的章程等,本文尽量把碰到的概念都剖判清楚,但又避开复杂的数学方面的文化,希望对从未接触过3D开荒的同校有所支持。

从零3D基础入门XNA 4.0(2)——模型和BasicEffect。 

【种类索引】

  1. 从零3D根基入门XNMagotan.0(1)——3D开采底子
  2. 从零3D基础入门XNA 4.0(2)——模型和BasicEffect。从零3D底子入门XNMARCH.0(2)——模型和BasicEffect

 

【文章索引】

  1. Model模型的协会
  2. BasicEffect效果的安装
  3. XNA的客户输入
  4. XNA分界面包车型大巴突显格局

 

【风流罗曼蒂克、Model模型的组织】

上风流浪漫篇文章使用Model自带的Draw方法达成了直白将载入的Model绘制到钦赐的职责上去,但是一时绘制出来的效果与利益并不适合大家的料想,比方下图(下图的模型是透过Maya创立的二个房间卡塔 尔(阿拉伯语:قطر‎:

图片 1

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

图片 2图片 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卡塔尔四个属性,其从零3D基础入门XNA 4.0(2)——模型和BasicEffect。结商谈事关如下:

图片 4

能够看来对于每一个ModelMesh,包蕴生龙活虎组ModelMeshPart与多少个ParentBone。在那之中,

  • ModelMesh表示单个能够独自运动的概况对象。举例,贰个car的Model能够包涵叁个车体(body卡塔 尔(阿拉伯语:قطر‎的ModelMesh、五个车轱辘(wheel卡塔 尔(阿拉伯语:قطر‎的ModelMesh与生龙活虎对门(door卡塔 尔(英语:State of Qatar)的ModelMesh。
  • ModelMeshPart表示单个从零3D基础入门XNA 4.0(2)——模型和BasicEffect。同生龙活虎材质的构件,其象征四个单独的绘图调用(draw call卡塔 尔(阿拉伯语:قطر‎。比如,上述车身能够包括着色的外界、使用碰到映射(environment mapping卡塔尔国效果的挡风玻璃甚至使用法线贴图(normalmap texture卡塔尔国效果的座椅等等。
  • 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(),启用后效果如下:

图片 5

这么的成效就直达了作者们的意料,按上述的不二诀要完毕的代码如下:

图片 6图片 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是那样写的:

图片 8图片 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的漫反射光的水彩如下,但其镜面反射光的颜料为中蓝卡塔尔国和倾向大约如下。

图片 10

下图第二个为启用了暗中认可光照后的模子(上黄金时代篇小说中的dude卡塔尔,第二、三、多少个为只启用暗中认可光照的情况光及0、1、2三束定向光彩的模子,第多少个为未有启用私下认可光照的模型(就像上大器晚成篇爆发的机能相像卡塔尔:

图片 11

当然,在不菲景观下(比方室外的日光等卡塔尔国,大家仅要求贰个光源,届时大家假若禁止使用(DirectionalLight*.Enabled = false卡塔 尔(阿拉伯语:قطر‎其余五个定向光就可以,当然我们兴许还须求改正光源的颜料等等。

除此之外利用EnableDefaultLighting,BasicEffect还提供了比较丰裕的参数能够设置。首先来看下上述例子中Effect私下认可的质量:

图片 12

里面与光线有关的:

  • LightingEnabled:是不是张开光照(默以为false卡塔尔。
  • PreferPerPixelLighting:是或不是张开逐像素的普照(默以为false,为逐极点光照卡塔 尔(英语:State of Qatar),逐像素光照相对于逐点光照效果更加好,但速度也越来越慢,同不经常候还须要显卡帮助Pixel Shader Model 2.0,若是显卡不帮忙的话会活动使用逐极点光照替代。
  • AmbientLightColor:情状光颜色(私下认可为Vector3.Zero卡塔 尔(英语:State of Qatar)。为了在生机勃勃部分光照模型(模型间的营口互不影响卡塔 尔(英语:State of Qatar)中巩固真实感,引进了遇到光的定义。景况光不依附任何光源,但其震慑全部物体。
  • DiffuseColor:漫反射颜色(默感到Vector3.One卡塔 尔(阿拉伯语:قطر‎。光线照到物体后,物体举行漫反射,其颜色与光线的自由化有关。
  • SpecularColor:镜面反射颜色。光线照到物体后,物体实行全反射,其颜色不止与光线的趋势有关,还与观看(相机卡塔尔的大势有关。
  • EmissiveColor:放射颜色(默认为Vector3.Zero卡塔 尔(阿拉伯语:قطر‎。放射光是指物体发出的玻璃体出血,但在有的光照模型中,实际上不会对别的实体爆发影响。
  • DirectionalLight0、DirectionalLight1、DirectionalLight2:三束定向光(每束都不外乎光线的趋向、漫反射颜色与镜面反射颜色卡塔 尔(英语:State of Qatar)。

中间供给注意的是,在XNA中,颜色的积累并非利用的Color(A瑞鹰GB或ABG凯雷德卡塔 尔(英语:State of Qatar),而是选拔的Vector3(或Vector4卡塔尔国。对于Vector3,其x、y、z三个轻重存款和储蓄的独家是LAND、G、B分别除以255的浮点值(Vector4的w分量存款和储蓄的是Alpha通道除以255的浮点值卡塔 尔(英语:State of Qatar),所以Vector3.Zero即为樱杏黄,而Vector3.One为青黑。当然XNA也提供了贰个Color类,并且Color也提供了提供了直白转变为Vector3(或Vector4卡塔 尔(英语:State of Qatar)的法子ToVector3()(或ToVector4()卡塔尔。

除了,BasicEffect还扶持设置雾的作用:

  • FogEnabled:是还是不是展开雾的效劳(默感觉false卡塔 尔(阿拉伯语:قطر‎。
  • FogColor:雾的水彩(暗许为Vector3.Zero卡塔尔。
  • FogStart:雾间隔相机的开始(前段时间卡塔尔国值(默感到0.0F卡塔 尔(阿拉伯语:قطر‎,那么些间距之内的事物不受雾的震慑。
  • FogEnd:雾间隔相机的结束(最远卡塔 尔(英语:State of Qatar)值(默感觉1.0F卡塔尔,那个间距之外的事物完全看不清。

也正是说,雾将会在间隔相机(FogStart - FogEnd)的地点时有产生,那几个间距需求依据物体所在的岗位决定。设Distance为实体间距相机的偏离,则Distance<FogStart<FogEnd时,物体不受雾的震慑,与未有雾时相符;当FogStart<FogEnd<Distance时,物体完全看不清(即物体全部为雾的颜色卡塔 尔(英语:State of Qatar);当FogStart<Distance<FogEnd时,物体受雾的震慑,物体离FogEnd越近则越看不清。

譬喻当人的模子在(0, 0, 0),相机在(120, 120, 120)处,雾的水彩为Gray。下图第多少个为未有加雾的意义,第3个为FogStart - FogEnd为200 - 300,第多个为1 - 300,第三个为1 - 100。

图片 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:
  2. Models, meshes, parts, and bones:
  3. What Is a Model Bone?:
  4. BasicEffect Lighting:
  5. BasicEffect Fog:
  6. 协同学WP7 XNA游戏开拓(七. 3d基本光源):
  7. 【D3D11玩耍编制程序】学习笔记十八:光照模型:

本文由6165金沙总站发布于游戏王朝,转载请注明出处:从零3D基础入门XNA 4.0(2)——模型和BasicEffect

关键词:

上一篇:〔校园〕新闻101(4)
下一篇:没有了