Jump to content

  • Log In with Google      Sign In   
  • Create Account

Modify normalmapping SpriteEffects sample from to use SamplerState.LinearClamp


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
No replies to this topic

#1 Kurdur   Members   -  Reputation: 104

Like
0Likes
Like

Posted 12 June 2012 - 03:50 AM

I'm using the NormalMapProcessor from the SpriteEffects sample in my current project. Recently I've been forced to use the "Reach" graphics profile because of end-user limitations. This graphics profile requires that all textures are resized to 'Power of two' or the SamplerState.LinearClamp is used. However, when setting the SamplerState I still get the error that XNA Graphics Profile Reach requires 'power of two'-textures. This error ONLY happens at the exact point where I use the normalmapping from the SpriteEffects sample.

How do I fix this???


Code for drawing the textures with normalmapping (the error occurs at spriteBatch_.End()):
// Draw Gold Chains
			normalmapEffect.Parameters["LightDirection"].SetValue(lightDirection);

			// Set the normalmap texture.
			graphics_.GraphicsDevice.Textures[1] = goldChainTextureNormalMap_;

			// Begin the sprite batch.
			spriteBatch_.Begin(0, null, SamplerState.LinearClamp, null, null, normalmapEffect);

			for (int n = 0; n < goldChains.Length; n++)
			{
				if (goldChains[n] != null)
				{
					if (goldChains[n].Enabled)
						goldChains[n].Draw(spriteBatch_, boardPosition, goldChainTexture_);
				}
			}

			spriteBatch_.End();


Code for the NormalMapProcessor:
#region Using Statements
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Graphics.PackedVector;
#endregion

namespace SpriteShaderPipeline
{
	/// <summary>
	/// Custom content processor converts greyscale displacement bitmaps into
	/// normalmap format. In the source image, use black for pixels that are
	/// further away and white for ones that are bumped upward. The output
	/// texture contains three-component normal vectors. This processor works
	/// best if the source bitmap is slightly blurred.
	/// </summary>
	[ContentProcessor]
	public class NormalMapProcessor : ContentProcessor<TextureContent, TextureContent>
	{
		// Controls how extreme the output normalmap should be.
		const float bumpSize = 8f;
		

		/// <summary>
		/// Converts a greyscale displacement bitmap into normalmap format.
		/// </summary>
		public override TextureContent Process(TextureContent input,
											   ContentProcessorContext context)
		{
			// Convert the input bitmap to Vector4 format, for ease of processing.
			input.ConvertBitmapType(typeof(PixelBitmapContent<Vector4>));

			PixelBitmapContent<Vector4> bitmap;
			bitmap = (PixelBitmapContent<Vector4>)input.Faces[0][0];
			
			// Calculate normalmap vectors.
			ConvertGreyToAlpha(bitmap);
			ConvertAlphaToNormals(bitmap);

			// Convert the result into NormalizedByte4 format.
			input.ConvertBitmapType(typeof(PixelBitmapContent<NormalizedByte4>));

			return input;
		}


		/// <summary>
		/// Copies greyscale color information into the alpha channel.
		/// </summary>
		static void ConvertGreyToAlpha(PixelBitmapContent<Vector4> bitmap)
		{
			for (int y = 0; y < bitmap.Height; y++)
			{
				for (int x = 0; x < bitmap.Width; x++)
				{
					Vector4 value = bitmap.GetPixel(x, y);

					// Copy a greyscale version of the RGB data into the alpha channel.
					float greyscale = (value.X + value.Y + value.Z) / 3;

					value.W = greyscale;

					bitmap.SetPixel(x, y, value);
				}
			}
		}


		/// <summary>
		/// Using height data stored in the alpha channel, computes normalmap
		/// vectors and stores them in the RGB portion of the bitmap.
		/// </summary>
		static void ConvertAlphaToNormals(PixelBitmapContent<Vector4> bitmap)
		{
			for (int y = 0; y < bitmap.Height; y++)
			{
				for (int x = 0; x < bitmap.Width; x++)
				{
					// Look up the heights to either side of this pixel.
					float left = GetHeight(bitmap, x - 1, y);
					float right = GetHeight(bitmap, x + 1, y);

					float top = GetHeight(bitmap, x, y - 1);
					float bottom = GetHeight(bitmap, x, y + 1);

					// Compute gradient vectors, then cross them to get the normal.
					Vector3 dx = new Vector3(1, 0, (right - left) * bumpSize);
					Vector3 dy = new Vector3(0, 1, (bottom - top) * bumpSize);

					Vector3 normal = Vector3.Cross(dx, dy);

					normal.Normalize();

					// Store the result.
					float alpha = GetHeight(bitmap, x, y);

					bitmap.SetPixel(x, y, new Vector4(normal, alpha));
				}
			}
		}


		/// <summary>
		/// Helper for looking up height values from the bitmap alpha channel,
		/// clamping if the specified position is off the edge of the bitmap.
		/// </summary>
		static float GetHeight(PixelBitmapContent<Vector4> bitmap, int x, int y)
		{
			if (x < 0)
			{
				x = 0;
			}
			else if (x >= bitmap.Width)
			{
				x = bitmap.Width - 1;
			}

			if (y < 0)
			{
				y = 0;
			}
			else if (y >= bitmap.Height)
			{
				y = bitmap.Height - 1;
			}

			return bitmap.GetPixel(x, y).W;
		}
	}
}


Sponsor:



Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS