XNA BUMP MAPPING
终于把这个效果做出来了。
看了N久别人写的shader才明白,写的时候更是恼火。看来真的是验证了看shader容易,写shader复杂。
先看下纹理资源:
然后是普通贴图的效果:
从图中可以看出,这里是没有高低不平的感觉。以下是通过bump mapping的效果。
以下图作为bump:
shader效果图:
接着看代码,程序代码:
Code
using CameraLib;
namespace bumpmapping
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Model sphere;
Texture2D textureColor;
Texture2D textureBump;
Effect effect;
Camera camera;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
IsMouseVisible = true;
camera = new Camera(MathHelper.PiOver4, GraphicsDevice.Viewport.AspectRatio, 1, 1000,
new Vector3(0, 0, 100), Vector3.Forward, Vector3.Up,this.Window.ClientBounds);
base.Initialize();
}
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
sphere = Content.Load<Model>("bsphere");
textureColor = Content.Load<Texture2D>("earth");
textureBump = Content.Load<Texture2D>("earthbump");
effect = Content.Load<Effect>("bump");
}
Matrix rollMatrix = Matrix.Identity;
protected override void Update(GameTime gameTime)
{
#region 控制地球可以旋转
KeyboardState ks = Keyboard.GetState();
Vector2 roll = Vector2.Zero;
if (ks.IsKeyDown(Keys.NumPad4))
{
roll.X += 0.1f;
}
if (ks.IsKeyDown(Keys.NumPad6))
{
roll.X -= 0.1f;
}
if (ks.IsKeyDown(Keys.NumPad8))
{
roll.Y += 0.1f;
}
if (ks.IsKeyDown(Keys.NumPad5))
{
roll.Y -= 0.1f;
}
rollMatrix *= Matrix.CreateFromYawPitchRoll(roll.X,roll.Y,0);
#endregion
camera.UpdateMatrix();
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)
{
effect.CurrentTechnique = effect.Techniques[0];
effect.Parameters["matWorldViewProj"].SetValue(rollMatrix*camera.View * camera.Projection);
effect.Parameters["matWorld"].SetValue(rollMatrix);
effect.Parameters["vecLightDir"].SetValue(new Vector3(-100, -100,-100));
effect.Parameters["vecEye"].SetValue(camera.mposi);
effect.Parameters["ColorMap"].SetValue(textureColor);
effect.Parameters["BumpMap"].SetValue(textureBump);
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
foreach(ModelMesh mesh in sphere.Meshes)
{
foreach (ModelMeshPart part in mesh.MeshParts)
{
part.Effect = effect;
}
mesh.Draw();
}
base.Draw(gameTime);
}
}
}
HLSL顶点渲染器输出结构:
Code
// HLSL顶点渲染器输出结构
struct VS_OUTPUT
{
float4 Pos : POSITION;
float2 Tex : TEXCOORD0;
float3 Light: TEXCOORD1; //纹理空间中灯光方向
float3 View : TEXCOORD2; //纹理空间中法线方向
};
// 顶点渲染器主函数
VS_OUTPUT VS(float4 Pos : POSITION, float2 Tex : TEXCOORD, float3 Normal : NORMAL, float3 Tangent : TANGENT )
{
VS_OUTPUT Out = (VS_OUTPUT)0;
//顶点坐标变换
Out.Pos = mul(Pos, matWorldViewProj);
//构建一个x3变换矩阵用于完成从世界空间到纹理空间的变换
float3x3 worldToTangentSpace;
worldToTangentSpace[0] = mul(Tangent, matWorld);
worldToTangentSpace[1] = mul(cross(Tangent,Normal), matWorld);
worldToTangentSpace[2] = mul(Normal, matWorld);
Out.Tex = Tex.xy;
//顶点在世界空间中的坐标
float3 PosWorld = normalize(mul(Pos, matWorld));
//计算纹理空间中灯光方向向量
float3 Light = vecLightDir - PosWorld;
Out.Light.xyz = mul(worldToTangentSpace, Light);
//计算纹理空间中的观察方向
float3 Viewer = vecEye - PosWorld;
Out.View = mul(worldToTangentSpace, Viewer);
return Out;
}
HLSL像素渲染器输出结构
Code
struct PS_OUTPUT
{
float4 Color : COLOR;
};
// 像素渲染器主函数
PS_OUTPUT PS(float2 Tex: TEXCOORD0, float3 Light : TEXCOORD1, float3 View : TEXCOORD2, float3 Att : TEXCOORD3)
{
PS_OUTPUT Out_ps = (PS_OUTPUT)0;
//颜色纹理采样
float4 color = tex2D(ColorMapSampler, Tex);
//凹凸纹理采样, 得到的是法线向量, 用于代替顶点法线进行光照计算
float3 bumpNormal = 2 * (tex2D(BumpMapSampler, Tex) - 0.5);
//标准化纹理空间中的灯光方向和观察方向
float3 LightDir = normalize(Light);
float3 ViewDir = normalize(View);
//根据凹凸贴图的发线进行漫反射光照计算
float4 diff = saturate(dot(bumpNormal, LightDir));
//计算自身遮蔽阴影项
float shadow = saturate(4 * diff);
//计算镜面反射强度
float3 Reflect = normalize(2 * diff * bumpNormal - LightDir);
float4 spec = min(pow(saturate(dot(Reflect, ViewDir)), 15), color.a);
//混合纹理颜色和光照颜色, 得到每个像素的最终颜色
Out_ps.Color = 0.2 * color + (shadow * (color * diff + spec) );
return Out_ps;
}