بســم الله الـرحمــن الرحيــم
الدرس الثاني عشر
أهلا بكم في الدرس الثاني عشر من سلسلة دروس تعلم ال3D Xna السلسلة الأولى، في هذا الدرس سوف نقوم بإضافة المتجهات العمودية إلى التضاريس الخاصة بنا.
هنا سوف نقوم بإضافة بيانات المتجهات العمودية إلى كل الرؤوس في التضاريس، حيث سوف يصبح بإمكان بطاقة الرسوميات عمل بعض حسابات الإضاءة عليها. كما شاهدنا في الدرس السابق سوف نحتاج إلى إضافة متجهه عمودي لكل من الرؤوس الخاصة بنا.
هذا المتجه يجب أن يكون عمودي على المثلث الموجود عليه الرأس. في الحالة التي يكون فيها الرأس مشترك بين عدة مثلثات (كما في التضاريس الخاصة بنا)، يجب عليك أن تحسب العموديات لكل المثلثات التي تستخدم هذا الرأس، و تخزين معدل هذه العموديات في ذلك الرأس.
أولا علينا إعادة الكود الخاص بدرس إضافة الألوان (الدرس العاشر)، بعدها سوف نكون بحاجة إلى إضافة التركيب “Struct” (الذي يتيح لنا تخزين بيانات المجهات العموديه) إلى أعلى كود الصنف:
public struct VertexPositionNormalColored
{
public Vector3 Position;
public Color Color;
public Vector3 Normal;
public static int SizeInBytes = 7 * 4;
public static VertexElement[] VertexElements = new VertexElement[]
{
new VertexElement( 0, 0, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Position, 0 ),
new VertexElement( 0, sizeof(float) * 3, VertexElementFormat.Color, VertexElementMethod.Default, VertexElementUsage.Color, 0 ),
new VertexElement( 0, sizeof(float) * 4, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Normal, 0 ),
};
}لا تنسى أن تعدل تعريف مصفوفة الرؤوس:
VertexPositionNormalColored[] vertices;
كما لا تنسى تعديل ال VertexDeclaration في داخل الدالة SetUpVertices:
myVertexDeclaration = new VertexDeclaration(device, VertexPositionNormalColored.VertexElements);
قم بإضافة السطر الذي يقوم عمليا برسم المثلثات على الشاشة في الدالة Draw:
device.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, vertices, 0, vertices.Length, indices, 0, indices.Length / 3);
الآن نحن جاهزين لحساب المتجهات العمودية، الذي سوف يتم في داخل الدالة الجديدة CalculateNormals. إبدأ بمسح العموديات في كل رأس من الرؤوس:
private void CalculateNormals()
{
for (int i = 0; i < vertices.Length; i++)
vertices.Normal = new Vector3(0, 0, 0);
}بعد ذلك، نحن بحاجة للمرور على كل مثلث من المثلثات. لكل مثلث، سوف نقوم بحساب المتجه العمودي. في النهاية، سوف تقوم بإضافة هذا المتجه إلى المتجه العمودي الموجود في كل من الرؤوس الثلاثة المكونة للمثلث:
for (int i = 0; i < indices.Length / 3; i++)
{
int index1 = indices[i * 3];
int index2 = indices[i * 3 + 1];
int index3 = indices[i * 3 + 2];
Vector3 side1 = vertices[index1].Position - vertices[index3].Position;
Vector3 side2 = vertices[index1].Position - vertices[index2].Position;
Vector3 normal = Vector3.Cross(side1, side2);
vertices[index1].Normal += normal;
vertices[index2].Normal += normal;
vertices[index3].Normal += normal;
}هنا نقوم بالنظر إلى فهارس الرؤوس الثلاثه الخاصة بالمثلث. إذا كنت تعرف جانبين من المثلث، سيكون بإمكانك حساب العمودي من خلال حساب الضرب التقاطعي “Cross Product” لهذين الجانبين. في أي متجهين، عملية الضرب التقاطعي لهذين المتجهيين يعطينا متجه يمثل العمودي لكلا المتجهيين.
لذا أولا نقوم بحساب جانبين للمثلث، من خلال طرح موقع أحد الزوايا من موقع زاوية أخرى. في اللحظة التي نعرف فيها العمودي للمثلث، نقوم بإضافته إلى العمودي لكل من الرؤوس الثلاثة.
في هذه اللحظة، كل الرؤوس تحتوي متجهات عمودية ضخمة، بينما نحتاج لأن يكون طولهم موحد. لذا أنهي الدالة السابقة بعمل تسوية “Normalization” لجميع المتجهات العمودية:
for (int i = 0; i < vertices.Length; i++) vertices.Normal.Normalize();
هذا كل شيئ بالنسبة للمتجهات العمودية! لا تنسى أن تستدعي هذه الدالة في نهاية الدالة LoadContent:
CalculateNormals();
في داخل الدالة Draw، قم بتشغيل الضوء:
Vector3 lightDirection = new Vector3(1.0f, -1.0f, -1.0f); lightDirection.Normalize(); effect.Parameters["xLightDirection"].SetValue(lightDirection); effect.Parameters["xEnableLighting"].SetValue(true); effect.Parameters["xAmbient"].SetValue(0.1f);
السطر الأخير يقوم بتشغيل الإضاءة المحيطة “Ambient Lighting”، لذا حتى الأجزاء من التضاريس التي لا تصل إليها الإضاءة المتجهة “Directional Light” ما زالت تستقبل بعض الضوء. عندما تقوم بتشغيل الكود، يجب أن تشاهد الصورة التالية:
كما ترى، إستعمال الإضاءة الصحيحة تقوم بإضافة الشعور الثلاثي الأبعاد إلى المشهد بشكل دراماتيكي.
نسخة عن الدرس بصيغة PDF:
كود المشروع حتى الآن:
using System;
using System.[color= #202020;]Collections.[color= #202020;]Generic;
using Microsoft.[color= #202020;]Xna.[color= #202020;]Framework;
using Microsoft.[color= #202020;]Xna.[color= #202020;]Framework.[color= #202020;]Audio;
using Microsoft.[color= #202020;]Xna.[color= #202020;]Framework.[color= #202020;]Content;
using Microsoft.[color= #202020;]Xna.[color= #202020;]Framework.[color= #202020;]GamerServices;
using Microsoft.[color= #202020;]Xna.[color= #202020;]Framework.[color= #202020;]Graphics;
using Microsoft.[color= #202020;]Xna.[color= #202020;]Framework.[color= #202020;]Input;
using Microsoft.[color= #202020;]Xna.[color= #202020;]Framework.[color= #202020;]Net;
using Microsoft.[color= #202020;]Xna.[color= #202020;]Framework.[color= #202020;]Storage;
namespace XNAtutorial
[color= #009900;]{
public class Game1 [color= #339933;]: Microsoft.[color= #202020;]Xna.[color= #202020;]Framework.[color= #202020;]Game
[color= #009900;]{
public [color= #993333;]struct VertexPositionNormalColored
[color= #009900;]{
public Vector3 Position;
public Color Color;
public Vector3 Normal;
public [color= #993333;]static [color= #993333;]int SizeInBytes [color= #339933;]= [color= #cc66cc;]7 [color= #339933;]* [color= #cc66cc;]4;
public [color= #993333;]static VertexElement[color= #009900;][[color= #009900;]] VertexElements [color= #339933;]= new VertexElement[color= #009900;][[color= #009900;]]
[color= #009900;]{
new VertexElement[color= #009900;]( [color= #cc66cc;]0, [color= #cc66cc;]0, VertexElementFormat.[color= #202020;]Vector3, VertexElementMethod.[color= #202020;]Defa
ult, VertexElementUsage.[color= #202020;]Position, [color= #cc66cc;]0 [color= #009900;]),
new VertexElement[color= #009900;]( [color= #cc66cc;]0, [color= #993333;]sizeof[color= #009900;]([color= #993333;]float[color= #009900;]) [color= #339933;]* [color= #cc66cc;]3, VertexElementFormat.[color= #202020;]Color, VertexElem
entMethod.[color= #b1b100;]Default, VertexElementUsage.[color= #202020;]Color, [color= #cc66cc;]0 [color= #009900;]),
new VertexElement[color= #009900;]( [color= #cc66cc;]0, [color= #993333;]sizeof[color= #009900;]([color= #993333;]float[color= #009900;]) [color= #339933;]* [color= #cc66cc;]4, VertexElementFormat.[color= #202020;]Vector3, VertexEl
ementMethod.[color= #b1b100;]Default, VertexElementUsage.[color= #202020;]Normal, [color= #cc66cc;]0 [color= #009900;]),
[color= #009900;]};
[color= #009900;]}
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
GraphicsDevice device;
Effect effect;
VertexPositionNormalColored[color= #009900;][[color= #009900;]] vertices;
VertexDeclaration myVertexDeclaration;
[color= #993333;]int[color= #009900;][[color= #009900;]] indices;
Matrix viewMatrix;
Matrix projectionMatrix;
private [color= #993333;]int terrainWidth;
private [color= #993333;]int terrainHeight;
private [color= #993333;]float[color= #009900;][,[color= #009900;]] heightData;
[color= #993333;]float angle [color= #339933;]= [color= #cc66cc;]0;
public Game1[color= #009900;]([color= #009900;])
[color= #009900;]{
graphics [color= #339933;]= new GraphicsDeviceManager[color= #009900;](this[color= #009900;]);
Content.[color= #202020;]RootDirectory [color= #339933;]= [color= #ff0000;]"Content";
[color= #009900;]}
protected override [color= #993333;]void Initialize[color= #009900;]([color= #009900;])
[color= #009900;]{
graphics.[color= #202020;]PreferredBackBufferWidth [color= #339933;]= [color= #cc66cc;]500;
graphics.[color= #202020;]PreferredBackBufferHeight [color= #339933;]= [color= #cc66cc;]500;
graphics.[color= #202020;]IsFullScreen [color= #339933;]= [color= #000000; font-weight: bold;]false;
graphics.[color= #202020;]ApplyChanges[color= #009900;]([color= #009900;]);
Window.[color= #202020;]Title [color= #339933;]= [color= #ff0000;]"Riemer's XNA Tutorials -- Series 1";
base.[color= #202020;]Initialize[color= #009900;]([color= #009900;]);
[color= #009900;]}
protected override [color= #993333;]void LoadContent[color= #009900;]([color= #009900;])
[color= #009900;]{
device [color= #339933;]= graphics.[color= #202020;]GraphicsDevice;
spriteBatch [color= #339933;]= new SpriteBatch[color= #009900;](GraphicsDevice[color= #009900;]);
effect [color= #339933;]= Content.[color= #202020;]Load<Effect> [color= #009900;]([color= #ff0000;]"effects"[color= #009900;]);
Texture2D heightMap [color= #339933;]= Content.[color= #202020;]Load<Texture2D> [color= #009900;]([color= #ff0000;]"heightmap"[color= #009900;]); LoadHeightD
ata[color= #009900;](heightMap[color= #009900;]);
SetUpVertices[color= #009900;]([color= #009900;]);
SetUpCamera[color= #009900;]([color= #009900;]);
SetUpIndices[color= #009900;]([color= #009900;]);
CalculateNormals[color= #009900;]([color= #009900;]);
[color= #009900;]}
private [color= #993333;]void SetUpVertices[color= #009900;]([color= #009900;])
[color= #009900;]{
[color= #993333;]float minHeight [color= #339933;]= [color= #993333;]float.[color= #202020;]MaxValue;
[color= #993333;]float maxHeight [color= #339933;]= [color= #993333;]float.[color= #202020;]MinValue;
[color= #b1b100;]for [color= #009900;]([color= #993333;]int x [color= #339933;]= [color= #cc66cc;]0; x < terrainWidth; x[color= #339933;]++[color= #009900;])
[color= #009900;]{
[color= #b1b100;]for [color= #009900;]([color= #993333;]int y [color= #339933;]= [color= #cc66cc;]0; y < terrainHeight; y[color= #339933;]++[color= #009900;])
[color= #009900;]{
[color= #b1b100;]if [color= #009900;](heightData[color= #009900;][x, y[color= #009900;]] < minHeight[color= #009900;])
minHeight [color= #339933;]= heightData[color= #009900;][x, y[color= #009900;]];
[color= #b1b100;]if [color= #009900;](heightData[color= #009900;][x, y[color= #009900;]] > maxHeight[color= #009900;])
maxHeight [color= #339933;]= heightData[color= #009900;][x, y[color= #009900;]];
[color= #009900;]}
[color= #009900;]}
vertices [color= #339933;]= new VertexPositionNormalColored[color= #009900;][terrainWidth [color= #339933;]* terrainHeight[color= #009900;]];
[color= #b1b100;]for [color= #009900;]([color= #993333;]int x [color= #339933;]= [color= #cc66cc;]0; x < terrainWidth; x[color= #339933;]++[color= #009900;])
[color= #009900;]{
[color= #b1b100;]for [color= #009900;]([color= #993333;]int y [color= #339933;]= [color= #cc66cc;]0; y < terrainHeight; y[color= #339933;]++[color= #009900;])
[color= #009900;]{
vertices[color= #009900;][x [color= #339933;]+ y [color= #339933;]* terrainWidth[color= #009900;]].[color= #202020;]Position [color= #339933;]= new Vector3[color= #009900;](x, heightData[color= #009900;][x, y[color= #009900;]],
[color= #339933;]-y[color= #009900;]);
[color= #b1b100;]if [color= #009900;](heightData[color= #009900;][x, y[color= #009900;]] < minHeight [color= #339933;]+ [color= #009900;](maxHeight [color= #339933;]- minHeight[color= #009900;]) [color= #339933;]/ [color= #cc66cc;]4[color= #009900;])
vertices[color= #009900;][x [color= #339933;]+ y [color= #339933;]* terrainWidth[color= #009900;]].[color= #202020;]Color [color= #339933;]= Color.[color= #202020;]Blue;
[color= #b1b100;]else [color= #b1b100;]if [color= #009900;](heightData[color= #009900;][x, y[color= #009900;]] < minHeight [color= #339933;]+ [color= #009900;](maxHeight [color= #339933;]- minHeight[color= #009900;]) [color= #339933;]* [color= #cc66cc;]2 [color= #339933;]/ [color= #cc66cc;]4[color= #009900;])
vertices[color= #009900;][x [color= #339933;]+ y [color= #339933;]* terrainWidth[color= #009900;]].[color= #202020;]Color [color= #339933;]= Color.[color= #202020;]Green;
[color= #b1b100;]else [color= #b1b100;]if [color= #009900;](heightData[color= #009900;][x, y[color= #009900;]] < minHeight [color= #339933;]+ [color= #009900;](maxHeight [color= #339933;]- minHeight[color= #009900;]) [color= #339933;]* [color= #cc66cc;]3 [color= #339933;]/ [color= #cc66cc;]4[color= #009900;])
vertices[color= #009900;][x [color= #339933;]+ y [color= #339933;]* terrainWidth[color= #009900;]].[color= #202020;]Color [color= #339933;]= Color.[color= #202020;]Brown;
[color= #b1b100;]else
vertices[color= #009900;][x [color= #339933;]+ y [color= #339933;]* terrainWidth[color= #009900;]].[color= #202020;]Color [color= #339933;]= Color.[color= #202020;]White;
[color= #009900;]}
[color= #009900;]}
myVertexDeclaration [color= #339933;]= new VertexDeclaration[color= #009900;](device, VertexPositionNormalColored.[color= #202020;]Ve
rtexElements[color= #009900;]);
[color= #009900;]}
private [color= #993333;]void SetUpIndices[color= #009900;]([color= #009900;])
[color= #009900;]{
indices [color= #339933;]= new [color= #993333;]int[color= #009900;][[color= #009900;](terrainWidth [color= #339933;]- [color= #cc66cc;]1[color= #009900;]) [color= #339933;]* [color= #009900;](terrainHeight [color= #339933;]- [color= #cc66cc;]1[color= #009900;]) [color= #339933;]* [color= #cc66cc;]6[color= #009900;]];
[color= #993333;]int counter [color= #339933;]= [color= #cc66cc;]0;
[color= #b1b100;]for [color= #009900;]([color= #993333;]int y [color= #339933;]= [color= #cc66cc;]0; y < terrainHeight [color= #339933;]- [color= #cc66cc;]1; y[color= #339933;]++[color= #009900;])
[color= #009900;]{
[color= #b1b100;]for [color= #009900;]([color= #993333;]int x [color= #339933;]= [color= #cc66cc;]0; x < terrainWidth [color= #339933;]- [color= #cc66cc;]1; x[color= #339933;]++[color= #009900;])
[color= #009900;]{
[color= #993333;]int lowerLeft [color= #339933;]= x [color= #339933;]+ y[color= #339933;]*terrainWidth;
[color= #993333;]int lowerRight [color= #339933;]= [color= #009900;](x [color= #339933;]+ [color= #cc66cc;]1[color= #009900;]) [color= #339933;]+ y[color= #339933;]*terrainWidth;
[color= #993333;]int topLeft [color= #339933;]= x [color= #339933;]+ [color= #009900;](y [color= #339933;]+ [color= #cc66cc;]1[color= #009900;]) [color= #339933;]* terrainWidth;
[color= #993333;]int topRight [color= #339933;]= [color= #009900;](x [color= #339933;]+ [color= #cc66cc;]1[color= #009900;]) [color= #339933;]+ [color= #009900;](y [color= #339933;]+ [color= #cc66cc;]1[color= #009900;]) [color= #339933;]* terrainWidth;
indices[color= #009900;][counter[color= #339933;]++[color= #009900;]] [color= #339933;]= topLeft;
indices[color= #009900;][counter[color= #339933;]++[color= #009900;]] [color= #339933;]= lowerRight;
indices[color= #009900;][counter[color= #339933;]++[color= #009900;]] [color= #339933;]= lowerLeft;
indices[color= #009900;][counter[color= #339933;]++[color= #009900;]] [color= #339933;]= topLeft;
indices[color= #009900;][counter[color= #339933;]++[color= #009900;]] [color= #339933;]= topRight;
indices[color= #009900;][counter[color= #339933;]++[color= #009900;]] [color= #339933;]= lowerRight;
[color= #009900;]}
[color= #009900;]}
[color= #009900;]}
private [color= #993333;]void CalculateNormals[color= #009900;]([color= #009900;])
[color= #009900;]{
[color= #b1b100;]for [color= #009900;]([color= #993333;]int i [color= #339933;]= [color= #cc66cc;]0; i < vertices.[color= #202020;]Length; i[color= #339933;]++[color= #009900;])
vertices[color= #009900;][i[color= #009900;]].[color= #202020;]Normal [color= #339933;]= new Vector3[color= #009900;]([color= #cc66cc;]0, [color= #cc66cc;]0, [color= #cc66cc;]0[color= #009900;]);
[color= #b1b100;]for [color= #009900;]([color= #993333;]int i [color= #339933;]= [color= #cc66cc;]0; i < indices.[color= #202020;]Length [color= #339933;]/ [color= #cc66cc;]3; i[color= #339933;]++[color= #009900;])
[color= #009900;]{
[color= #993333;]int index1 [color= #339933;]= indices[color= #009900;][i [color= #339933;]* [color= #cc66cc;]3[color= #009900;]];
[color= #993333;]int index2 [color= #339933;]= indices[color= #009900;][i [color= #339933;]* [color= #cc66cc;]3 [color= #339933;]+ [color= #cc66cc;]1[color= #009900;]];
[color= #993333;]int index3 [color= #339933;]= indices[color= #009900;][i [color= #339933;]* [color= #cc66cc;]3 [color= #339933;]+ [color= #cc66cc;]2[color= #009900;]];
Vector3 side1 [color= #339933;]= vertices[color= #009900;][index1[color= #009900;]].[color= #202020;]Position [color= #339933;]- vertices[color= #009900;][index3[color= #009900;]].[color= #202020;]Position;
Vector3 side2 [color= #339933;]= vertices[color= #009900;][index1[color= #009900;]].[color= #202020;]Position [color= #339933;]- vertices[color= #009900;][index2[color= #009900;]].[color= #202020;]Position;
Vector3 normal [color= #339933;]= Vector3.[color= #202020;]Cross[color= #009900;](side1, side2[color= #009900;]);
vertices[color= #009900;][index1[color= #009900;]].[color= #202020;]Normal [color= #339933;]+= normal;
vertices[color= #009900;][index2[color= #009900;]].[color= #202020;]Normal [color= #339933;]+= normal;
vertices[color= #009900;][index3[color= #009900;]].[color= #202020;]Normal [color= #339933;]+= normal;
[color= #009900;]}
[color= #b1b100;]for [color= #009900;]([color= #993333;]int i [color= #339933;]= [color= #cc66cc;]0; i < vertices.[color= #202020;]Length; i[color= #339933;]++[color= #009900;])
vertices[color= #009900;][i[color= #009900;]].[color= #202020;]Normal.[color= #202020;]Normalize[color= #009900;]([color= #009900;]);
[color= #009900;]}
private [color= #993333;]void SetUpCamera[color= #009900;]([color= #009900;])
[color= #009900;]{
viewMatrix [color= #339933;]= Matrix.[color= #202020;]CreateLookAt[color= #009900;](new Vector3[color= #009900;]([color= #cc66cc;]0, [color= #cc66cc;]100, [color= #cc66cc;]100[color= #009900;]), new Vector3[color= #009900;]([color= #cc66cc;]0, [color= #cc66cc;]0, [color= #cc66cc;]0[color= #009900;]), n
ew Vector3[color= #009900;]([color= #cc66cc;]0, [color= #cc66cc;]1, [color= #cc66cc;]0[color= #009900;])[color= #009900;]);
projectionMatrix [color= #339933;]= Matrix.[color= #202020;]CreatePerspectiveFieldOfView[color= #009900;](MathHelper.[color= #202020;]PiOver4, device.[color= #202020;]
Viewport.[color= #202020;]AspectRatio, [color= #cc66cc;]1.0f, [color= #cc66cc;]300.0f[color= #009900;]);
[color= #009900;]}
private [color= #993333;]void LoadHeightData[color= #009900;](Texture2D heightMap[color= #009900;])
[color= #009900;]{
terrainWidth [color= #339933;]= heightMap.[color= #202020;]Width;
terrainHeight [color= #339933;]= heightMap.[color= #202020;]Height;
Color[color= #009900;][[color= #009900;]] heightMapColors [color= #339933;]= new Color[color= #009900;][terrainWidth [color= #339933;]* terrainHeight[color= #009900;]];
heightMap.[color= #202020;]GetData[color= #009900;](heightMapColors[color= #009900;]);
heightData [color= #339933;]= new [color= #993333;]float[color= #009900;][terrainWidth, terrainHeight[color= #009900;]];
[color= #b1b100;]for [color= #009900;]([color= #993333;]int x [color= #339933;]= [color= #cc66cc;]0; x < terrainWidth; x[color= #339933;]++[color= #009900;])
[color= #b1b100;]for [color= #009900;]([color= #993333;]int y [color= #339933;]= [color= #cc66cc;]0; y < terrainHeight; y[color= #339933;]++[color= #009900;])
heightData[color= #009900;][x, y[color= #009900;]] [color= #339933;]= heightMapColors[color= #009900;][x [color= #339933;]+ y [color= #339933;]* terrainWidth[color= #009900;]].[color= #202020;]R [color= #339933;]/ [color= #cc66cc;]5.0f;
[color= #009900;]}
protected override [color= #993333;]void UnloadContent[color= #009900;]([color= #009900;])
[color= #009900;]{
[color= #009900;]}
protected override [color= #993333;]void Update[color= #009900;](GameTime gameTime[color= #009900;])
[color= #009900;]{
[color= #b1b100;]if [color= #009900;](GamePad.[color= #202020;]GetState[color= #009900;](PlayerIndex.[color= #202020;]One[color= #009900;]).[color= #202020;]Buttons.[color= #202020;]Back [color= #339933;]== ButtonState.[color= #202020;]Pressed[color= #009900;])
this.[color= #202020;]Exit[color= #009900;]([color= #009900;]);
KeyboardState keyState [color= #339933;]= Keyboard.[color= #202020;]GetState[color= #009900;]([color= #009900;]);
[color= #b1b100;]if [color= #009900;](keyState.[color= #202020;]IsKeyDown[color= #009900;](Keys.[color= #202020;]Delete[color= #009900;])[color= #009900;])
angle [color= #339933;]+= [color= #cc66cc;]0.05f;
[color= #b1b100;]if [color= #009900;](keyState.[color= #202020;]IsKeyDown[color= #009900;](Keys.[color= #202020;]PageDown[color= #009900;])[color= #009900;])
angle [color= #339933;]-= [color= #cc66cc;]0.05f;
base.[color= #202020;]Update[color= #009900;](gameTime[color= #009900;]);
[color= #009900;]}
protected override [color= #993333;]void Draw[color= #009900;](GameTime gameTime[color= #009900;])
[color= #009900;]{
device.[color= #202020;]Clear[color= #009900;](ClearOptions.[color= #202020;]Target | ClearOptions.[color= #202020;]DepthBuffer, Color.[color= #202020;]Black, [color= #cc66cc;]1.0f, [color= #cc66cc;]0[color= #009900;])
;
device.[color= #202020;]RenderState.[color= #202020;]CullMode [color= #339933;]= CullMode.[color= #202020;]None;
Matrix worldMatrix [color= #339933;]= Matrix.[color= #202020;]CreateTranslation[color= #009900;]([color= #339933;]-terrainWidth [color= #339933;]/ [color= #cc66cc;]2.0f, [color= #cc66cc;]0, terrainHeig
ht [color= #339933;]/ [color= #cc66cc;]2.0f[color= #009900;]) [color= #339933;]* Matrix.[color= #202020;]CreateRotationY[color= #009900;](angle[color= #009900;]);
effect.[color= #202020;]CurrentTechnique [color= #339933;]= effect.[color= #202020;]Techniques[color= #009900;][[color= #ff0000;]"Colored"[color= #009900;]];
effect.[color= #202020;]Parameters[color= #009900;][[color= #ff0000;]"xView"[color= #009900;]].[color= #202020;]SetValue[color= #009900;](viewMatrix[color= #009900;]);
effect.[color= #202020;]Parameters[color= #009900;][[color= #ff0000;]"xProjection"[color= #009900;]].[color= #202020;]SetValue[color= #009900;](projectionMatrix[color= #009900;]);
effect.[color= #202020;]Parameters[color= #009900;][[color= #ff0000;]"xWorld"[color= #009900;]].[color= #202020;]SetValue[color= #009900;](worldMatrix[color= #009900;]);
effect.[color= #202020;]Parameters[color= #009900;][[color= #ff0000;]"xEnableLighting"[color= #009900;]].[color= #202020;]SetValue[color= #009900;]([color= #000000; font-weight: bold;]true[color= #009900;]);
Vector3 lightDirection [color= #339933;]= new Vector3[color= #009900;]([color= #cc66cc;]1.0f, [color= #cc66cc;]-1.0f, [color= #cc66cc;]-1.0f[color= #009900;]);
lightDirection.[color= #202020;]Normalize[color= #009900;]([color= #009900;]);
effect.[color= #202020;]Parameters[color= #009900;][[color= #ff0000;]"xLightDirection"[color= #009900;]].[color= #202020;]SetValue[color= #009900;](lightDirection[color= #009900;]);
effect.[color= #202020;]Parameters[color= #009900;][[color= #ff0000;]"xAmbient"[color= #009900;]].[color= #202020;]SetValue[color= #009900;]([color= #cc66cc;]0.1f[color= #009900;]);
effect.[color= #202020;]Begin[color= #009900;]([color= #009900;]);
foreach [color= #009900;](EffectPass pass in effect.[color= #202020;]CurrentTechnique.[color= #202020;]Passes[color= #009900;])
[color= #009900;]{
pass.[color= #202020;]Begin[color= #009900;]([color= #009900;]);
device.[color= #202020;]VertexDeclaration [color= #339933;]= myVertexDeclaration;
device.[color= #202020;]DrawUserIndexedPrimitives[color= #009900;](PrimitiveType.[color= #202020;]TriangleList, vertices, [color= #cc66cc;]0, vert
ices.[color= #202020;]Length, indices, [color= #cc66cc;]0, indices.[color= #202020;]Length [color= #339933;]/ [color= #cc66cc;]3[color= #009900;]);
pass.[color= #202020;]End[color= #009900;]([color= #009900;]);
[color= #009900;]}
effect.[color= #202020;]End[color= #009900;]([color= #009900;]);
base.[color= #202020;]Draw[color= #009900;](gameTime[color= #009900;]);
[color= #009900;]}
[color= #009900;]}
[color= #009900;]}