使用深度图像进行照明有什么问题
我想使用深度图像来照亮 RawColor 图像,但看起来不太好 我想知道我的代码出了什么问题,或者它的全深度图像可以做什么:| 输出图像形状像圆锥体而不是圆形,并且上面有很多噪音,我想知道是我的代码错误还是它的方法不正确?! 为此,我对每个像素进行法线处理,并将其添加到纹理中,然后将其发送到像素着色器以用于照明。结果图像和代码添加在这里
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D depth;
Texture2D image;
Texture2D texNormal;
Vector3 cameraPos = new Vector3(0.5f, 0.5f, -0.0999f);
Effect mEffect;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
// TODO: Add your initialization logic here
graphics.PreferredBackBufferWidth = 1000;
graphics.PreferredBackBufferHeight = 1000;
graphics.ApplyChanges();
base.Initialize();
}
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
depth = Content.Load<Texture2D>("depth");
image = Content.Load<Texture2D>("image");
texNormal = getNormalFromDepth(depth);
mEffect = Content.Load<Effect>("depthEffect");
// TODO: use this.Content to load your game content here
}
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
if (Keyboard.GetState().IsKeyDown(Keys.W))
{
cameraPos.Y += 0.01f;
}
if (Keyboard.GetState().IsKeyDown(Keys.S))
{
cameraPos.Y -= 0.01f;
}
if (Keyboard.GetState().IsKeyDown(Keys.A))
{
cameraPos.X -= 0.01f;
}
if (Keyboard.GetState().IsKeyDown(Keys.D))
{
cameraPos.X += 0.01f;
}
if (Keyboard.GetState().IsKeyDown(Keys.Up))
{
cameraPos.Z += 0.01f;
}
if (Keyboard.GetState().IsKeyDown(Keys.Down))
{
cameraPos.Z -= 0.01f;
}
// TODO: Add your update logic here
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
GraphicsDevice.Textures[1] = texNormal;
mEffect.Parameters["LightPos"].SetValue(cameraPos);
// TODO: Add your drawing code here
spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, mEffect);
spriteBatch.Draw(image, new Rectangle(0, 0, 500, 500), Color.White);
spriteBatch.End();
spriteBatch.Begin();
spriteBatch.Draw(texNormal, new Rectangle(500, 0, 500, 500), Color.White);
spriteBatch.Draw(image, new Rectangle(500, 500, 500, 500), Color.White);
spriteBatch.Draw(depth, new Rectangle(0, 500, 500, 500), Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
Texture2D getNormalFromDepth(Texture2D depth)
{
Texture2D output = new Texture2D(GraphicsDevice, depth.Width, depth.Height);
Color[] outbyte = new Color[depth.Width * depth.Height];
Color[] colors1D = new Color[depth.Width * depth.Height];
depth.GetData(colors1D);
Color[,] colors2D = new Color[depth.Width, depth.Height];
for (int x = 0; x < depth.Width; x++)
{
for (int y = 0; y < depth.Height; y++)
{
colors2D[x, y] = colors1D[x + y * depth.Width];
}
}
for (int x = 0; x < depth.Width; x++)
{
for (int y = 0; y < depth.Height; y++)
{
float left = GetHeight(colors2D, ref depth, x - 1, y);
float right = GetHeight(colors2D, ref depth, x + 1, y);
float top = GetHeight(colors2D, ref depth, x, y - 1);
float bottom = GetHeight(colors2D, ref depth, x, y + 1);
// Compute gradient vectors, then cross them to get the normal.
Vector3 dx = new Vector3(1, 0, (right - left) * 1);
Vector3 dy = new Vector3(0, 1, (bottom - top) * 1);
Vector3 normal = Vector3.Cross(dx, dy);
normal.Normalize();
// Store the result.
float alpha = colors2D[x, y].A;
outbyte[y * depth.Width + x] = new Color(new Vector4(normal, alpha));
}
}
output.SetData(outbyte);
return output;
}
float GetHeight(Color[,] depth, ref Texture2D depthImage, int x, int y)
{
if (x < 0)
{
x = 0;
}
else if (x >= depthImage.Width)
{
x = depthImage.Width - 1;
}
if (y < 0)
{
y = 0;
}
else if (y >= depthImage.Height)
{
y = depthImage.Height - 1;
}
Color mColor = (depth[x, y]);
float output = (mColor.R + mColor.G + mColor.B) / 3;
return output;
}
}
着色器代码在这里
sampler normalSampler : register(s1);
sampler imageSampler : register(s0);
float3 LightPos = (1,0,-0.5);
float3 AmbientColor = (0.1,0.1,0.1);
float3 LightColor = (0.9,0.9,0.9);
float4 main(float4 color : COLOR0 ,float2 texCoord : TEXCOORD0):COLOR0
{
float4 output = float4(1,1,1,1);
float4 normal = tex2D(normalSampler,texCoord);
float4 imageColor = tex2D(imageSampler,texCoord);
float3 tex3DCoord = float3(texCoord.x,texCoord.y,0);
float3 lighting = AmbientColor;
float3 lightDir = (LightPos - tex3DCoord);
lighting += ( LightColor* max(dot(normal.xyz, lightDir), 0));
output = float4 (imageColor*lighting,1);
return output;
}
technique Technique1
{
pass Pass1
{
PixelShader = compile ps_2_0 main();
}
}
I want use a depth image to lighting a RawColor image but it not seems good
i want know whats wrong with my code , or its all depth image can do :|
the output image shape like Cone instead of circle and there are many noise on it , what i want to know is my code wrong or its not right way to do this?!
for that i get normal for each pixel and add it to a texture and send it to pixel shader to use for lighting. result image and code are added here
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D depth;
Texture2D image;
Texture2D texNormal;
Vector3 cameraPos = new Vector3(0.5f, 0.5f, -0.0999f);
Effect mEffect;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
// TODO: Add your initialization logic here
graphics.PreferredBackBufferWidth = 1000;
graphics.PreferredBackBufferHeight = 1000;
graphics.ApplyChanges();
base.Initialize();
}
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
depth = Content.Load<Texture2D>("depth");
image = Content.Load<Texture2D>("image");
texNormal = getNormalFromDepth(depth);
mEffect = Content.Load<Effect>("depthEffect");
// TODO: use this.Content to load your game content here
}
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
if (Keyboard.GetState().IsKeyDown(Keys.W))
{
cameraPos.Y += 0.01f;
}
if (Keyboard.GetState().IsKeyDown(Keys.S))
{
cameraPos.Y -= 0.01f;
}
if (Keyboard.GetState().IsKeyDown(Keys.A))
{
cameraPos.X -= 0.01f;
}
if (Keyboard.GetState().IsKeyDown(Keys.D))
{
cameraPos.X += 0.01f;
}
if (Keyboard.GetState().IsKeyDown(Keys.Up))
{
cameraPos.Z += 0.01f;
}
if (Keyboard.GetState().IsKeyDown(Keys.Down))
{
cameraPos.Z -= 0.01f;
}
// TODO: Add your update logic here
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
GraphicsDevice.Textures[1] = texNormal;
mEffect.Parameters["LightPos"].SetValue(cameraPos);
// TODO: Add your drawing code here
spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, mEffect);
spriteBatch.Draw(image, new Rectangle(0, 0, 500, 500), Color.White);
spriteBatch.End();
spriteBatch.Begin();
spriteBatch.Draw(texNormal, new Rectangle(500, 0, 500, 500), Color.White);
spriteBatch.Draw(image, new Rectangle(500, 500, 500, 500), Color.White);
spriteBatch.Draw(depth, new Rectangle(0, 500, 500, 500), Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
Texture2D getNormalFromDepth(Texture2D depth)
{
Texture2D output = new Texture2D(GraphicsDevice, depth.Width, depth.Height);
Color[] outbyte = new Color[depth.Width * depth.Height];
Color[] colors1D = new Color[depth.Width * depth.Height];
depth.GetData(colors1D);
Color[,] colors2D = new Color[depth.Width, depth.Height];
for (int x = 0; x < depth.Width; x++)
{
for (int y = 0; y < depth.Height; y++)
{
colors2D[x, y] = colors1D[x + y * depth.Width];
}
}
for (int x = 0; x < depth.Width; x++)
{
for (int y = 0; y < depth.Height; y++)
{
float left = GetHeight(colors2D, ref depth, x - 1, y);
float right = GetHeight(colors2D, ref depth, x + 1, y);
float top = GetHeight(colors2D, ref depth, x, y - 1);
float bottom = GetHeight(colors2D, ref depth, x, y + 1);
// Compute gradient vectors, then cross them to get the normal.
Vector3 dx = new Vector3(1, 0, (right - left) * 1);
Vector3 dy = new Vector3(0, 1, (bottom - top) * 1);
Vector3 normal = Vector3.Cross(dx, dy);
normal.Normalize();
// Store the result.
float alpha = colors2D[x, y].A;
outbyte[y * depth.Width + x] = new Color(new Vector4(normal, alpha));
}
}
output.SetData(outbyte);
return output;
}
float GetHeight(Color[,] depth, ref Texture2D depthImage, int x, int y)
{
if (x < 0)
{
x = 0;
}
else if (x >= depthImage.Width)
{
x = depthImage.Width - 1;
}
if (y < 0)
{
y = 0;
}
else if (y >= depthImage.Height)
{
y = depthImage.Height - 1;
}
Color mColor = (depth[x, y]);
float output = (mColor.R + mColor.G + mColor.B) / 3;
return output;
}
}
and shader Code is here
sampler normalSampler : register(s1);
sampler imageSampler : register(s0);
float3 LightPos = (1,0,-0.5);
float3 AmbientColor = (0.1,0.1,0.1);
float3 LightColor = (0.9,0.9,0.9);
float4 main(float4 color : COLOR0 ,float2 texCoord : TEXCOORD0):COLOR0
{
float4 output = float4(1,1,1,1);
float4 normal = tex2D(normalSampler,texCoord);
float4 imageColor = tex2D(imageSampler,texCoord);
float3 tex3DCoord = float3(texCoord.x,texCoord.y,0);
float3 lighting = AmbientColor;
float3 lightDir = (LightPos - tex3DCoord);
lighting += ( LightColor* max(dot(normal.xyz, lightDir), 0));
output = float4 (imageColor*lighting,1);
return output;
}
technique Technique1
{
pass Pass1
{
PixelShader = compile ps_2_0 main();
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论