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

那么接下去就按照那么些思路去落实,同时在设置每一个Effect时,使用Effect提供的应用默认光照的方法EnableDefaultLighting(),启用后效果如下:

 

this.IsMouseVisible = true;

有趣味的朋友可以遵照斗地主的平整接轨支付下去,做成一个概括的斗地主游戏

 

效果:

对此判断键盘的按键,能够通过如下的法子获取是否按下了指定按键:

葡京游戏网址 1

View Code

规则:

能够见到在启用默认光照里实际是给环境光AmbientLightColor以及三束定向光(包括光线的势头、漫反射颜色及镜面反射颜色)设置了先期定义好的颜料,并启用了这多少个光源,这三束定向光的颜色(Light1的漫反射光的颜色如下,但其镜面反射光的水彩为肉色)和可行性大约如下。

2.梯次打乱,一人一张依次发牌,一人17张,留三张作为背景

葡京游戏网址 2

示例:

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

葡京游戏网址 3

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

3.看牌:按大小王2A….43的序排列打印

其中this.light0-2为BasicEffect的DirectionalLight0-2,即BasicEffect可以时候的六个光源。而EffectHelpers的EnableDefaultLighting是那样写的:

package demo;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;

public class DouDiZhu {
    public static void main(String[] args) {
        // 创建Map集合,键是编号,值是牌
        HashMap<Integer, String> pooker = new HashMap<Integer, String>();
        // List集合存储编号
        // 用List集合原因:可以调用排序方法
        ArrayList<Integer> pookerNumber = new ArrayList<Integer>();
        // 由于13个点数恒定,定义数组
        String[] numbers = { "2", "A", "K", "Q", "J", "10", "9", "8", "7", "6", "5", "4", "3" };
        // 花色恒定,定义数组
        String[] colors = { "♠", "♥", "♣", "♦" };
        // 定义整数变量,作为键,0和1留给大小王
        int index = 2;
        // 遍历数组,存入Map集合
        for (String number : numbers) {
            for (String color : colors) {
                pooker.put(index, color + number);
                pookerNumber.add(index);
                index++;
            }
        }
        // 单独存储大小王
        pooker.put(0, "大王");
        pookerNumber.add(0);
        pooker.put(1, "小王");
        pookerNumber.add(1);

        // 洗牌,将牌的编号打乱
        Collections.shuffle(pookerNumber);

        // 发牌
        // 三个玩家和底牌
        ArrayList<Integer> player1 = new ArrayList<Integer>();
        ArrayList<Integer> player2 = new ArrayList<Integer>();
        ArrayList<Integer> player3 = new ArrayList<Integer>();
        ArrayList<Integer> dipai = new ArrayList<Integer>();
        // 每张依次发到三个玩家
        for (int i = 0; i < pookerNumber.size(); i++) {
            // 先将底牌做好
            if (i < 3) {
                dipai.add(pookerNumber.get(i));
            }
            // 依次给每个玩家发牌
            else if (i % 3 == 0) {
                player1.add(pookerNumber.get(i));
            } else if (i % 3 == 1) {
                player2.add(pookerNumber.get(i));
            } else if (i % 3 == 2) {
                player3.add(pookerNumber.get(i));
            }
        }
        // 对玩家手中的牌排序
        Collections.sort(player1);
        Collections.sort(player2);
        Collections.sort(player3);
        // 看牌,根据键找值
        look("玩家1", player1, pooker);
        look("玩家2", player2, pooker);
        look("玩家3", player3, pooker);
        look("底牌", dipai, pooker);
    }

    public static void look(String name, ArrayList<Integer> player, HashMap<Integer, String> pooker) {
        System.out.print(name + ":");
        for (Integer key : player) {
            String value = pooker.get(key);
            System.out.print("    " + value);
        }
        System.out.println();
    }
}

比如说当人的模型在(0, 0, 0),相机在(120, 120,
120)处,雾的颜料为格雷(Gray)。下图第一个为没有加雾的功效,第二个为FogStart –
FogEnd为200 – 300,第五个为1 – 300,第多少个为1 – 100。

1.54张扑克牌,有品种

  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

 

【题外话】

每一次的结果都不等同:

葡京游戏网址 4

 

【相关链接】

里头需要小心的是,在XNA中,颜色的仓储并不是运用的Color(ARGB或ABGR),而是使用的Vector3(或Vector4)。对于Vector3,其x、y、z五个轻重存储的分级是R、G、B分别除以255的浮点值(Vector4的w分量存储的是Alpha通道除以255的浮点值),所以Vector3.Zero即为粉红色,而Vector3.One为白色。当然XNA也提供了一个Color类,并且Color也提供了提供了向来转换为Vector3(或Vector4)的措施ToVector3()(或ToVector4())。

  1. Model模型的构造
  2. BasicEffect效果的装置
  3. XNA的用户输入
  4. XNA界面的突显情势

为了精通Model的渲染,咱们先是需要了然Model的结构。实际上,在一个Model对象中,包含Bone集合(model.Bones)、Mesh集合(model.Meshes)以及根Bone(model.Root)多个特性,其社团和关联如下

  • LightingEnabled:是否开启光照(默认为false)。
  • PreferPerPixelLighting:是否打开逐像素的普照(默认为false,为逐顶点光照),逐像素光照相对于逐点光照效果更好,但速度也更慢,同时还需要显卡帮助Pixel
    Shader Model 2.0,假使显卡不协理的话会活动使用逐顶点光照代替。
  • AmbientLightColor:环境光颜色(默认为Vector3.Zero)。为了在有的光照模型(模型间的光照互不影响)中加强真实感,引入了环境光的定义。环境光不借助任何光源,但其震慑所有物体。
  • DiffuseColor:漫反射颜色(默认为Vector3.One)。光线照到物体后,物体进行漫反射,其颜色与光线的来头有关。
  • SpecularColor:镜面反射颜色。光线照到物体后,物体举办全反射,其颜色不仅与光线的矛头有关,还与阅览(相机)的可行性有关。
  • EmissiveColor:放射颜色(默认为Vector3.Zero)。放射光是指物体发出的光柱,但在有些光照模型中,实际上不会对其它物体爆发震慑。
  • DirectionalLight0、DirectionalLight1、DirectionalLight2:三束定向光(每束都囊括光线的势头、漫反射颜色与镜面反射颜色)。

上一篇作品使用Model自带的Draw方法实现了第一手将载入的Model绘制到指定的职务上去,不过有时绘制出来的功能并不符合我们的预想,比如下图(下图的模子是经过Maya创设的一个房间):

  • ModelMesh代表单个能够独自运动的物理对象。例如,一个car的Model可以分包一个车体(body)的ModelMesh、五个轮子(wheel)的ModelMesh与一对门(door)的ModelMesh。
  • ModelMeshPart表示单个同等材料的预制构件,其代表一个单独的绘图调用(draw
    call)。例如,上述车身可以分包着色的外表、使用环境映射(environment
    mapping)效果的挡风玻璃以及利用法线贴图(normalmap
    texture)效果的座椅等等。
  • ModelBone表示了相应的ModelMesh如何变换,其富含一个Transform的转移矩阵。ModelBone是以树形存储的,每个ModelBone都有一个父节点以及若干个子节点。上述的各类ModelMesh都有一个ParentBone,ModelMesh可以依据ModelBone的转换到规定最终显示的岗位等。例如,上述车门的ModelBone与车轮的ModelBone是车身的子节点等等。

葡京游戏网址, 

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

除此之外使用EnableDefaultLighting,BasicEffect还提供了相比丰裕的参数可以设置。首先来看下上述例子中Effect默认的性能:

诸如此类的效率就高达了俺们的预想,按上述的艺术实现的代码如下:

graphics.IsFullScreen = true;

除此之外,BasicEffect还襄助设置雾的功能:

除却,固然要一口咬定鼠标是否在程序区域内,可以经过如下的点子判断

【三、XNA的用户输入】

只是对于每个ModelMeshPart,其实际渲染的功能都留存Effect的习性中,对于默认来说,Effect均为BasicEffect。其余,对于ModelBone,其转移矩阵都是对峙其自我的Parent来的,不过Model类也提供了一个艺术,即CopyAbsoluteBoneTransformsTo(),即可将每个Bone相对于RootBone的变换矩阵复制到一个矩阵数组中,然后将其使用到Effect中即可。这种措施与上述提到的Model.Draw类似,可是自己写的话就可以自定义每个ModelMeshPart渲染的效果,当然也可以设置每个ModelMeshPart的渲染地点。

 

只是这与刚刚见到的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 (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 }

理所当然大家还足以让用户来切换全屏与窗口化,不过这行代码写在Update()中是不起效率的,但是XNA提供此外一个主意,就是graphics.ToggleFullScreen()。例如大家需要按F键进行全屏与窗口化的切换,可以编制如下的代码:

之所以遍历一个Model中颇具的ModelMesh,然后遍历其中具有的ModelMeshPart,并且依据ModelMesh的ParentBone来将每一个ModelMeshPart绘制到指定的地方上就可以绘制出一体化的Model。

  • FogEnabled:是否打开雾的职能(默认为false)。
  • FogColor:雾的水彩(默认为Vector3.Zero)。
  • FogStart:雾距离相机的先导(近来)值(默认为0.0F),那多少个距离之内的事物不受雾的熏陶。
  • FogEnd:雾距离相机的扫尾(最远)值(默认为1.0F),这些距离之外的东西完全看不清。

也就是说,雾将会在距离相机(FogStart –
FogEnd)的地点时有爆发,这多少个距离需要基于物体所在的岗位决定。设Distance为实体距离相机的偏离,则Distance<FogStart<FogEnd时,物体不受雾的震慑,与没有雾时一样;当FogStart<FogEnd<Distance时,物体完全看不清(即物体全体为雾的颜色);当FogStart<Distance<FogEnd时,物体受雾的震慑,物体离FogEnd越近则越看不清。

 

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

View Code

在默认生成XNA程序中的Update方法里,有一个到手GamePad的情景,当用户1的GamePad按下了“Back”键后将会退出程序。微软对用户输入的帮忙都在Microsoft.Xna.Framework.Input中,除了GamePad之外,微软还帮忙获取Keyboard、Mouse这三种的景观。另外在Microsoft.Xna.Framework.Input.Touch中,还有TouchPanel可以得到触摸的图景。与GamePad相同,其他的这多少个情况也都是通过微软提供给类中的GetState()方法开展获取。

葡京游戏网址 5

当然,在无数情形下(比如户外的日光等),我们仅需要一个光源,届时大家假如禁用(DirectionalLight*.Enabled
= false)其他两个定向光即可,当然大家也许还亟需修改光源的水彩等等。

能够看看对于每个ModelMesh,包含一组ModelMeshPart与一个ParentBone。其中,

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

葡京游戏网址 6

【二、BasicEffect效果的装置】

里头可见,Draw方法通过遍历模型的Mesh,然后再遍历每个Mesh的Effect,并对每个Effect举办设置,最终动用Mesh的Draw方法将其绘制到屏幕上。

葡京游戏网址 7葡京游戏网址 8

下图第一个为启用了默认光照后的模子(上一篇作品中的dude),第二、三、五个为只启用默认光照的环境光及0、1、2三束定向光后的模子,第四个为没有启用默认光照的模型(如同上一篇暴发的效劳同样):

而对此鼠标的按键,则需要看清按键的ButtonState才可以,例如判断鼠标左键是否按下:

 

【四、XNA界面的呈现形式】

葡京游戏网址 9

上一篇作品介绍了3D开发基础与XNA开发顺序的共同体结构,以及使用Model类的Draw方法将模型绘制到屏幕上。本文接着上一篇作品继续,介绍XNA中模型的社团、BasicEffect的行使以及用户输入和界面呈现的艺术等,本文尽量把碰到的定义都分析清楚,但又避开复杂的数学方面的学问,希望对从未接触过3D开发的同桌有所辅助。

【一、Model模型的构造】

View Code

 

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

【小说索引】

葡京游戏网址 10葡京游戏网址 11

 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 }

葡京游戏网址 12葡京游戏网址 13

【连串索引】

 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 }

譬如要博取键盘和鼠标的气象,我们得以经过如下格局:

葡京游戏网址 14

个中与光线有关的:

 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 }
if (this.GraphicsDevice.Viewport.Bounds.Contains(mouseState.X, mouseState.Y))
{
    //TODO
}

这么XNA的程序就能按照大家设定的分辨率显示了。除此之外,假若我们期待XNA的先后能全屏显示,我们还是可以加上如下的代码:

虽说在大部分意况下,假设让用户操作鼠标的话会在程序内展现一个自定义的指针。但有时候写个小程序,为了简单希望直接使用系统的指针,大家得以在先后的肆意地方(构造方法、Initialize甚至Update也可)写如下的代码,就足以显示鼠标指针了,反之则可以隐藏:

默认情形下,运行XNA的次第会活动以800*480的分辨率显示,若要修改展现的分辨率,其实非凡简单,仅需要在Game的构造方法中添加如下代码即可:

通过ILSpy查看Microsoft.Xna.Framework.Graphics.Model,可以看来其Draw方法的代码如下:

public void EnableDefaultLighting()
{
    this.LightingEnabled = true;
    this.AmbientLightColor = EffectHelpers.EnableDefaultLighting(this.light0, this.light1, this.light2);
}
KeyboardState kbState = Keyboard.GetState();
MouseState mouseState = Mouse.GetState();

葡京游戏网址 15