在现实生活中,除了颜色以外,最重要的其实是光照,有了光照,才有了明暗、着色、高光等效果,在继上节的纹理之后,这节来为场景加入光照效果。
在XNA中,可以简单地把光照分为两种,一种是环境光,一种是有向光。
环境光是不来自任何特殊方向的光,它有光源,但是被周围环境的多次反射变得没有确定的方向,物体各表面都均等受光。在使用时主要用环境光改变场景的基本光线颜色。
有向光是来自某个方向被物体表面反射的光,比如射灯的光等。在描述这种光线时,除了描述方向以外,还要描述散射光的颜色和物体表面高光区的颜色等其他属性。
在使用光线的时候,还有一个额外的参数需要指定,那就是法线方向。不妨作这样的思考,对于任意一个平面,渲染引擎是如何计算入射光和反射光的夹角呢?是如何确定该平面哪个方向为正方向的呢?其实,这些问题的答案就是依靠法线。
回顾一下法线的定义,简单的说就是垂直于平面的垂线,对于曲面来说,就是垂直于曲面某点切线的线。法线在3D空间的重要作用就是确定面的正方向,通常定义由内部指向外部的方向为正方向,有了这个方向,渲染引擎在做光线运算和纹理贴图时才能正确处理方向,从而达到预期的效果。
在场景中如果需要光照效果,就不能简单的用VertexPositionTexture类了,XNA提供了VertexPositionNormalTexture类,这个类提供了对法线的表示方法。下面,我们在前面的三角形定义的基础上,改用这个新的类,代码如下:
~~~
triangle = new VertexPositionNormalTexture[]{
new VertexPositionNormalTexture(new Vector3(0, 1, 0),new Vector3(0,0,1),new Vector2(0.5f,0)),
new VertexPositionNormalTexture(new Vector3(1, -1, 0),newVector3(0,0,1), new Vector2(1,1)),
new VertexPositionNormalTexture(new Vector3(-1,-1, 0),newVector3(0,0,1), new Vector2(0,1))
};
~~~
注意到每个点的法线方向都用了(0,0,1),即全部指向z轴的正方向,从而确定了整个三角形的正方向是从手机屏幕向外指向用户。
有了这个数据定义,就可以通过BasicEffect对象添加光照效果了。代码如下:
~~~
basicEffect.LightingEnabled = true;
basicEffect.AmbientLightColor = new Vector3(0.1f, 0.1f, 0.1f);
basicEffect.DirectionalLight0.DiffuseColor = Color.Red.ToVector3();
basicEffect.DirectionalLight0.Direction = Vector3.Normalize(newVector3(-0.5f, 0.5f, -1));
basicEffect.DirectionalLight0.SpecularColor = Color.White.ToVector3();
basicEffect.DirectionalLight0.Enabled = true;
~~~
通过LightingEnabled=true可以启动光照效果,只有该变量的值为true,后续语句中设置的光照才会得到渲染。
AmbientLightColor指定的是环境光的颜色。
通过BasicEffect可以设置环境光、漫反射光、高光以及3个有向光的效果。在上述的代码中,通过对DirectionalLight0的设置,就是确定了一个有向光的属性。这些属性中,DiffuseColor是其漫反射光的颜色,Direction是一个归一化的三维向量,用于指定光线的方向,SpecularColor是定义高光的颜色,Enabled是启用该有向光的效果渲染。
最终的运行结果如图所示。光源的方向是从右下角到左上角并指向屏幕内部,因此右下角的高光效果较明显。而且整个物体被漫反射光映成了红色,像是被夕阳照射的一样。
![](https://box.kancloud.cn/2016-04-08_570727fb2cd58.gif)
其余的光照效果需要在实践中不断的积累,相信有了上述的学习,在运用时能够达到目标效果。
附本节Game1类的完整源码:
~~~
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
Camera camera;
Matrix world = Matrix.Identity;
BasicEffect basicEffect;
VertexPositionNormalTexture[] triangle;
Matrix translateMatrix=Matrix.Identity;
Matrix scaleMatrix = Matrix.Identity;
Matrix rotateMatrix = Matrix.Identity;
Texture2D texture;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
// Frame rate is 30 fps by default for Windows Phone.
TargetElapsedTime = TimeSpan.FromTicks(333333);
// Extend battery life under lock.
InactiveSleepTime = TimeSpan.FromSeconds(1);
graphics.IsFullScreen = true;
}
/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
}
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
camera = new Camera(this, new Vector3(0, 0, 5), Vector3.Zero, Vector3.Up, MathHelper.PiOver4, GraphicsDevice.Viewport.AspectRatio, 1.0f, 50.0f);
Components.Add(camera);
basicEffect = new BasicEffect(GraphicsDevice);
triangle = new VertexPositionNormalTexture[]{
new VertexPositionNormalTexture(new Vector3(0, 1, 0),new Vector3(0,0,1), new Vector2(0.5f,0)),
new VertexPositionNormalTexture(new Vector3(1, -1, 0),new Vector3(0,0,1), new Vector2(1,1)),
new VertexPositionNormalTexture(new Vector3(-1,-1, 0),new Vector3(0,0,1), new Vector2(0,1))
};
texture = Content.Load<Texture2D>(@"Tulips");
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// all content.
/// </summary>
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
TouchPanel.EnabledGestures = GestureType.Tap;
if (TouchPanel.IsGestureAvailable)
{
GestureSample gestureSample = TouchPanel.ReadGesture();
if (gestureSample.GestureType == GestureType.Tap)
{
translateMatrix *= Matrix.CreateTranslation(0.3f, 0, 0);
//scaleMatrix = Matrix.CreateScale(0.9f);
rotateMatrix *= Matrix.CreateRotationY(MathHelper.ToRadians(10));
}
}
base.Update(gameTime);
}
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
RasterizerState rasterizerState = new RasterizerState();
rasterizerState.CullMode = CullMode.None;
GraphicsDevice.RasterizerState = rasterizerState;
basicEffect.World = scaleMatrix * translateMatrix * rotateMatrix;
basicEffect.View = camera.view;
basicEffect.Projection = camera.projection;
basicEffect.TextureEnabled = true;
basicEffect.Texture = texture;
GraphicsDevice.SamplerStates[0] = SamplerState.PointClamp;
basicEffect.LightingEnabled = true;
basicEffect.AmbientLightColor = new Vector3(0.1f, 0.1f, 0.1f);
basicEffect.DirectionalLight0.DiffuseColor = Color.Red.ToVector3();
basicEffect.DirectionalLight0.Direction = Vector3.Normalize(new Vector3(-0.5f, 0.5f, -1));
basicEffect.DirectionalLight0.SpecularColor = Color.White.ToVector3();
basicEffect.DirectionalLight0.Enabled = true;
foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.DrawUserPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleStrip, triangle, 0, 1);
}
base.Draw(gameTime);
}
}
~~~
——欢迎转载,请注明出处 [http://blog.csdn.net/caowenbin](http://blog.csdn.net/caowenbin) ——
- 前言
- Windows Phone 7开发环境初体验
- Windows Phone 7 3D开发中使用纹理贴图
- 在Windows Phone中进行3D开发之一坐标系
- 在Windows Phone中进行3D开发之二摄像机
- 在Windows Phone中进行3D开发之三空间
- 在Windows Phone中进行3D开发之四三角形
- 在Windows Phone中进行3D开发之五平移缩放
- 在Windows Phone中进行3D开发之六旋转
- 在Windows Phone中进行3D开发之七纹理
- 在Windows Phone中进行3D开发之八光照
- 在Windows Phone中进行3D开发之九模型
- 在Windows Phone中进行3D开发之十组件
- 在Windows Phone中进行3D开发之十一天空
- 在Windows Phone中进行3D开发之十二飞行
- 在Windows Phone中进行3D开发之十三阳光
- 在Windows Phone中进行3D开发之后记(附源码)