3D系列4.1 开始代码
我们已经在第一个系列教材中学习了创建地形的基础知识,所以开始的代码是基于第一个系列教程的。
因为我不想在LoadContent方法中写太长的代码,所以这个方法中会调用LoadVertices方法初始化顶点和索引。
现在,LoadVertices方法生成了地形的顶点和索引这些顶点包含位置和颜色信息。然后,将它们传递到CalculateNormals方法,这个方法生成正确的法线并添加到顶点中。最后,顶点和索引都存储到顶点缓冲和索引缓冲中优化性能。
在Draw方法中,它们被传递到Colored technique中,这是在Series4Effects.fx文件中定义的,这个文件包含HLSL代码,我们会在后面的章节中扩展这个代码。
我们还要使用一个高度图。
创建一个新项目将下面的代码粘贴到Game1.cs文件中。确保Game1.cs和Program.cs文件的命名空间是相同的!然后创建一个叫做Series4Effects.fx的文件,将下面的HLSL代码粘贴其中。
下面是Game1.cs的代码:
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.Net;
using Microsoft.Xna.Framework.Storage;
![]()
namespace XNAseries4
{
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 ),
};
}
![]()
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
GraphicsDevice device;
![]()
int terrainWidth;
int terrainLength;
float[,] heightData;
![]()
VertexBuffer terrainVertexBuffer;
IndexBuffer terrainIndexBuffer;
VertexDeclaration terrainVertexDeclaration;
![]()
Effect effect;
Matrix viewMatrix;
Matrix projectionMatrix;
![]()
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
![]()
protected override void Initialize()
{
graphics.PreferredBackBufferWidth = 500;
graphics.PreferredBackBufferHeight = 500;
![]()
graphics.ApplyChanges();
Window.Title = "Riemer's XNA Tutorials -- Series 4";
![]()
base.Initialize();
}
![]()
protected override void LoadContent()
{
device = GraphicsDevice;
![]()
effect = Content.Load<Effect> ("Series4Effects");
viewMatrix = Matrix.CreateLookAt(new Vector3(130, 30, -50), new Vector3(0,0,-40), new Vector3(0, 1, 0));
projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, device.Viewport.AspectRatio, 0.3f, 1000.0f);
![]()
LoadVertices();
}
![]()
private void LoadVertices()
{
![]()
Texture2D heightMap = Content.Load<Texture2D> ("heightmap"); LoadHeightData(heightMap);
![]()
VertexPositionNormalColored[] terrainVertices = SetUpTerrainVertices();
int[] terrainIndices = SetUpTerrainIndices();
terrainVertices = CalculateNormals(terrainVertices, terrainIndices);
CopyToTerrainBuffers(terrainVertices, terrainIndices);
terrainVertexDeclaration = new VertexDeclaration(device, VertexPositionNormalColored.VertexElements);
}
![]()
private void LoadHeightData(Texture2D heightMap)
{
float minimumHeight = float.MaxValue;
float maximumHeight = float.MinValue;
![]()
terrainWidth = heightMap.Width;
terrainLength = heightMap.Height;
![]()
Color[] heightMapColors = new Color[terrainWidth * terrainLength];
heightMap.GetData(heightMapColors);
![]()
heightData = new float[terrainWidth, terrainLength];
for (int x = 0; x < terrainWidth; x++)
for (int y = 0; y < terrainLength; y++)
{
heightData[x, y] = heightMapColors[x + y * terrainWidth].R;
if (heightData[x, y] < minimumHeight) minimumHeight = heightData[x, y];
if (heightData[x, y] > maximumHeight) maximumHeight = heightData[x, y];
}
![]()
for (int x = 0; x < terrainWidth; x++)
for (int y = 0; y < terrainLength; y++)
heightData[x, y] = (heightData[x, y] - minimumHeight) / (maximumHeight - minimumHeight) * 30.0f;
}
![]()
private VertexPositionNormalColored[] SetUpTerrainVertices()
{
VertexPositionNormalColored[] terrainVertices = new VertexPositionNormalColored[terrainWidth * terrainLength];
![]()
for (int x = 0; x < terrainWidth; x++)
{
for (int y = 0; y < terrainLength; y++)
{
terrainVertices[x + y * terrainWidth].Position = new Vector3(x, heightData[x, y], -y);
![]()
if (heightData[x, y] < 6)
terrainVertices[x + y * terrainWidth].Color = Color.Blue;
else if (heightData[x, y] < 15)
terrainVertices[x + y * terrainWidth].Color = Color.Green;
else if (heightData[x, y] < 25)
terrainVertices[x + y * terrainWidth].Color = Color.Brown;
else
terrainVertices[x + y * terrainWidth].Color = Color.White;
}
}
![]()
return terrainVertices;
}
![]()
private int[] SetUpTerrainIndices()
{
int[] indices = new int[(terrainWidth - 1) * (terrainLength - 1) * 6];
int counter = 0;
for (int y = 0; y < terrainLength - 1; y++)
{
for (int x = 0; x < terrainWidth - 1; x++)
{
int lowerLeft = x + y * terrainWidth;
int lowerRight = (x + 1) + y * terrainWidth;
int topLeft = x + (y + 1) * terrainWidth;
int topRight = (x + 1) + (y + 1) * terrainWidth;
![]()
indices[counter++] = topLeft;
indices[counter++] = lowerRight;
indices[counter++] = lowerLeft;
![]()
indices[counter++] = topLeft;
indices[counter++] = topRight;
indices[counter++] = lowerRight;
}
}
![]()
return indices;
}
![]()
private VertexPositionNormalColored[] CalculateNormals(VertexPositionNormalColored[] vertices, int[] indices)
{
for (int i = 0; i < vertices.Length; i++)
vertices[i].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;
}
![]()
for (int i = 0; i < vertices.Length; i++)
vertices[i].Normal.Normalize();
![]()
return vertices;
}
![]()
private void CopyToTerrainBuffers(VertexPositionNormalColored[] vertices, int[] indices)
{
terrainVertexBuffer = new VertexBuffer(device, vertices.Length * VertexPositionNormalColored.SizeInBytes, BufferUsage.WriteOnly);
terrainVertexBuffer.SetData(vertices);
![]()
terrainIndexBuffer = new IndexBuffer(device, typeof(int), indices.Length, BufferUsage.WriteOnly);
terrainIndexBuffer.SetData(indices);
}
![]()
protected override void UnloadContent()
{
}
![]()
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
![]()
base.Update(gameTime);
}
![]()
protected override void Draw(GameTime gameTime)
{
float time = (float)gameTime.TotalGameTime.TotalMilliseconds / 100.0f;
device.RenderState.CullMode = CullMode.None;
![]()
device.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1.0f, 0);
DrawTerrain(viewMatrix);
![]()
base.Draw(gameTime);
}
![]()
private void DrawTerrain(Matrix currentViewMatrix)
{
effect.CurrentTechnique = effect.Techniques["Colored"];
Matrix worldMatrix = Matrix.Identity;
effect.Parameters["xWorld"].SetValue(worldMatrix);
effect.Parameters["xView"].SetValue(currentViewMatrix);
effect.Parameters["xProjection"].SetValue(projectionMatrix);
![]()
effect.Parameters["xEnableLighting"].SetValue(true);
effect.Parameters["xAmbient"].SetValue(0.4f);
effect.Parameters["xLightDirection"].SetValue(new Vector3(-0.5f, -1, -0.5f));
![]()
effect.Begin();
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Begin();
![]()
device.Vertices[0].SetSource(terrainVertexBuffer, 0, VertexPositionNormalColored.SizeInBytes);
device.Indices = terrainIndexBuffer;
device.VertexDeclaration = terrainVertexDeclaration;
![]()
int noVertices = terrainVertexBuffer.SizeInBytes / VertexPositionNormalColored.SizeInBytes;
int noTriangles = terrainIndexBuffer.SizeInBytes / sizeof(int)/3;
device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, noVertices, 0, noTriangles);
![]()
pass.End();
}
effect.End();
}
}
}
下面是Series4Effects.fx文件的代码:
//----------------------------------------------------
//-- --
//-- www.riemers.net --
//-- Series 4: Advanced terrain --
//-- Shader code --
//-- --
//----------------------------------------------------
![]()
//------- Constants --------
float4x4 xView;
float4x4 xProjection;
float4x4 xWorld;
float3 xLightDirection;
float xAmbient;
bool xEnableLighting;
![]()
//------- Texture Samplers --------
![]()
Texture xTexture;
![]()
sampler TextureSampler = sampler_state { texture = <xTexture> ; magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR; AddressU = mirror; AddressV = mirror;};
//------- Technique: Colored --------
struct ColVertexToPixel
{
float4 Position : POSITION;
float4 Color : COLOR0;
float LightingFactor: TEXCOORD0;
};
![]()
struct ColPixelToFrame
{
float4 Color : COLOR0;
};
![]()
ColVertexToPixel ColoredVS( float4 inPos : POSITION, float4 inColor: COLOR, float3 inNormal: NORMAL)
{
ColVertexToPixel Output = (ColVertexToPixel)0;
float4x4 preViewProjection = mul (xView, xProjection);
float4x4 preWorldViewProjection = mul (xWorld, preViewProjection);
![]()
Output.Position = mul(inPos, preWorldViewProjection);
Output.Color = inColor;
![]()
float3 Normal = normalize(mul(normalize(inNormal), xWorld));
Output.LightingFactor = 1;
if (xEnableLighting)
Output.LightingFactor = saturate(dot(Normal, -xLightDirection));
![]()
return Output;
}
![]()
ColPixelToFrame ColoredPS(ColVertexToPixel PSIn)
{
ColPixelToFrame Output = (ColPixelToFrame)0;
![]()
Output.Color = PSIn.Color;
Output.Color.rgb *= saturate(PSIn.LightingFactor + xAmbient);
![]()
return Output;
}
![]()
technique Colored
{
pass Pass0
{
VertexShader = compile vs_1_1 ColoredVS();
PixelShader = compile ps_1_1 ColoredPS();
}
}
![]()
//------- Technique: Textured --------
struct TexVertexToPixel
{
float4 Position : POSITION;
float4 Color : COLOR0;
float LightingFactor: TEXCOORD0;
float2 TextureCoords: TEXCOORD1;
};
![]()
struct TexPixelToFrame
{
float4 Color : COLOR0;
};
![]()
TexVertexToPixel TexturedVS( float4 inPos : POSITION, float3 inNormal: NORMAL, float2 inTexCoords: TEXCOORD0)
{
TexVertexToPixel Output = (TexVertexToPixel)0;
float4x4 preViewProjection = mul (xView, xProjection);
float4x4 preWorldViewProjection = mul (xWorld, preViewProjection);
![]()
Output.Position = mul(inPos, preWorldViewProjection);
Output.TextureCoords = inTexCoords;
![]()
float3 Normal = normalize(mul(normalize(inNormal), xWorld));
Output.LightingFactor = 1;
if (xEnableLighting)
Output.LightingFactor = saturate(dot(Normal, -xLightDirection));
![]()
return Output;
}
![]()
TexPixelToFrame TexturedPS(TexVertexToPixel PSIn)
{
TexPixelToFrame Output = (TexPixelToFrame)0;
![]()
Output.Color = tex2D(TextureSampler, PSIn.TextureCoords);
Output.Color.rgb *= saturate(PSIn.LightingFactor + xAmbient);
![]()
return Output;
}
![]()
technique Textured
{
pass Pass0
{
VertexShader = compile vs_1_1 TexturedVS();
PixelShader = compile ps_1_1 TexturedPS();
}
}
发布时间:2009/12/8 下午1:45:23 阅读次数:8765