企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
在现实生活中,除了颜色以外,最重要的其实是光照,有了光照,才有了明暗、着色、高光等效果,在继上节的纹理之后,这节来为场景加入光照效果。 在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) ——