XNA 天空盒子

今天终于做了个SkyBox,本来很简单,但是因为之前没有做过,所以做的候还是不是很顺利。

Skyboxr 原理很简单:

将6张图贴在个面上,图实为TextureCUBE。

首先为了省去每次写DEMO时都要重新写Camera的操作的方法,所有这次就做了个Camera操作的类,来封装Camera的常用操作方法:

 

Code
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace CameraLib
{
public class Camera
{
float Fov;
float aspectRatio;
float neer;
float far;

Vector3 mPosi;
public Vector3 mposi{get{return mPosi;}}
Vector3 mTarget;
public Vector3 mtarget { get { return mTarget; } }
Vector3 mUp;
public Vector3 mup { get { return mUp; } }


private Matrix view;
public Matrix View
{
get { return Matrix.CreateLookAt(mPosi, mTarget, mUp); }
}

private Matrix projection;
public Matrix Projection
{
get { return projection = Matrix.CreatePerspectiveFieldOfView(Fov, aspectRatio, neer, far); }
}

public Camera(float fov, float ar, float neer, float far,Vector3 pos,Vector3 targ,Vector3 up)
{
Fov
= fov;
this.aspectRatio = ar;
this.neer = neer;
this.far = far;

this.mPosi = pos;
this.mTarget = targ;
this.mUp = up;

UpdateMatrix();
}

Matrix tranMatrix
= Matrix.Identity;
public void UpdateMatrix()
{
KeyboardState ks
= Keyboard.GetState();

Vector3 movVec
= Vector3.Zero;
Vector3 rolVec
= Vector3.Zero;

#region 相机平移


if (ks.IsKeyDown(Keys.W))
{
movVec.Z
-= 1;
}
if (ks.IsKeyDown(Keys.S))
{
movVec.Z
+= 1;
}

if (ks.IsKeyDown(Keys.A))
{
movVec.X
-= 1;
}
if (ks.IsKeyDown(Keys.D))
{
movVec.X
+= 1;
}

if (ks.IsKeyDown(Keys.Q))
{
movVec.Y
-= 1;
}
if (ks.IsKeyDown(Keys.E))
{
movVec.Y
+= 1;
}

#endregion

#region 相机旋转

if (ks.IsKeyDown(Keys.Left))
{
rolVec.Y
+=0.1f;
}
if (ks.IsKeyDown(Keys.Right))
{
rolVec.Y
-=0.1f;
}
if (ks.IsKeyDown(Keys.Up))
{
rolVec.X
+=0.1f;
}
if (ks.IsKeyDown(Keys.Down))
{
rolVec.X
-=0.1f;
}

if (ks.IsKeyDown(Keys.PageUp))
{
rolVec.Z
+=0.1f;
}
if (ks.IsKeyDown(Keys.PageDown))
{
rolVec.Z
-=0.1f;
}

#endregion
tranMatrix
*= Matrix.CreateRotationX(rolVec.X) * Matrix.CreateRotationY(rolVec.Y) * Matrix.CreateRotationZ(rolVec.Z);
mUp
= Vector3.Transform(Vector3.Up, tranMatrix);
mPosi
+= Vector3.Transform(movVec, tranMatrix);

mTarget
= mPosi + Vector3.Transform(Vector3.Forward, tranMatrix);
}

private void cameraTransform(Matrix matrix)
{
view
*= matrix;
}
}
}

 

 

这个类现在可能还不完善,以后要用的时候再修改吧。

接下来是shader:

 

Code
float4x4 World;
float4x4 View;
float4x4 Projection;

float3 eyePosition:CameraPosition;

Texture textu;
samplerCUBE textuSampler
=sampler_state
{
texture
=<textu>;
};

struct vsin
{
float4 position:POSITION0;
//float3 normal:NORMAL0;
float2 texcoord:TEXCOORD0;
};

struct vsout
{
float4 Position : POSITION0;
float3 ViewDirection : TEXCOORD2;
};

vsout vs(vsin input)
{
vsout output;
output.Position
=mul(input.position,mul(mul(World,View),Projection));
output.ViewDirection
=eyePosition-mul(input.position,World);
return output;
}

struct psin
{
float3 ViewDirection:TEXCOORD2;
};

float4 ps(psin input):COLOR0
{
float3 vd=normalize(input.ViewDirection);
return texCUBE(textuSampler,-vd);
}


technique Technique1
{
pass Pass1
{
VertexShader = compile vs_3_0 vs();
PixelShader
= compile ps_3_0 ps();
}
}


 

 

注意:这里出来后,当你移动镜头时,可能看到skybox的移动方向可能和实际方向相反。

然后是主程序:

 

Code
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace SkyBox
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;

CameraLib.Camera camera;

Model skybox;
SpriteFont fnt;
TextureCube texture;
Effect effect;

Matrix modRow
=Matrix.Identity;

public Game1()
{
graphics
= new GraphicsDeviceManager(this);
Content.RootDirectory
= "Content";
}

protected override void Initialize()
{
camera
= new CameraLib.Camera(MathHelper.PiOver4, GraphicsDevice.Viewport.AspectRatio, 1, 1000,
new Vector3(0, 0, 50), Vector3.Forward, Vector3.Up);

base.Initialize();
}

protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);

skybox
= Content.Load<Model>("skybox");
fnt
= Content.Load<SpriteFont>("fnt");
texture
= Content.Load<TextureCube>("SkyboxTex");
effect
= Content.Load<Effect>("effect");
}

protected override void Update(GameTime gameTime)
{
KeyboardState ks
= Keyboard.GetState();

if (ks.IsKeyDown(Keys.Escape))
{
Exit();
}

if (ks.IsKeyDown(Keys.NumPad4))
{
modRow
*= Matrix.CreateRotationY(0.1f);
}
if (ks.IsKeyDown(Keys.NumPad6))
{
modRow
*= Matrix.CreateRotationY(-0.1f);
}
if (ks.IsKeyDown(Keys.NumPad8))
{
modRow
*= Matrix.CreateRotationZ(0.1f);
}
if (ks.IsKeyDown(Keys.NumPad5))
{
modRow
*= Matrix.CreateRotationZ(-0.1f);
}
if (ks.IsKeyDown(Keys.NumPad7))
{
modRow
*= Matrix.CreateRotationX(0.1f);
}
if (ks.IsKeyDown(Keys.NumPad9))
{
modRow
*= Matrix.CreateRotationX(-0.1f);
}

camera.UpdateMatrix();

base.Update(gameTime);
}

protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

effect.Parameters[
"World"].SetValue(modRow*Matrix.CreateScale(30f));
effect.Parameters[
"View"].SetValue(camera.View);
effect.Parameters[
"Projection"].SetValue(camera.Projection);

effect.Parameters[
"textu"].SetValue(texture);
effect.Parameters[
"eyePosition"].SetValue(camera.mposi);

foreach(ModelMesh mesh in skybox.Meshes)
{
foreach (ModelMeshPart part in mesh.MeshParts)
{
part.Effect
= effect;
}
mesh.Draw();
}

spriteBatch.Begin(SpriteBlendMode.AlphaBlend);

spriteBatch.DrawString(fnt,
"Position:" + camera.mposi.ToString() + "\n" +
"Target:" + camera.mtarget.ToString() + "\n" +
"up:" + camera.mup.ToString(), Vector2.Zero, Color.White);

spriteBatch.End();

base.Draw(gameTime);
}
}
}

 

 

好了,看下效果:

 

其实要实现天空效果也不只有一种方法,还可以通过一个"房顶"完成。

通过上面的模型也能实现天空效果。

posted @ 2008-09-26 03:26  齐.net  阅读(3501)  评论(12编辑  收藏  举报