XNA Texture2D Billboarding appears as a white block - c#

Very odd problem, when I try and draw my billboard sprite it always appears as a white block, changing the .draw color property still draws it as white, it also doesn't matter it I use a jpeg, or transparent png.
[EDIT]
So I'm now trying to use a Viewport instead of a basic effect to just get an x and y screen coordinate, I'll fix any scaling issue later, however now the image stays in the exact same spot (on the screen, it doesn't change position based on the camera) and doesn't get any bigger or smaller based on how far away it is
My new billboard rendering function:
public void Draw(Camera camera, GraphicsDevice device, SpriteBatch spriteBatch, Texture2D Texture)
{
Viewport viewport = new Viewport(new Rectangle(0, 0, 800, 480));
Vector3 viewSpaceTextPosition = viewport.Project(this.position, camera.Projection, camera.View, camera.World);
spriteBatch.Begin();
spriteBatch.Draw(Texture, new Vector2(viewSpaceTextPosition.X, viewSpaceTextPosition.Y), null, Color.White, 0, new Vector2(Texture.Bounds.Center.X, Texture.Bounds.Center.Y), this.Scale, SpriteEffects.None, viewSpaceTextPosition.Z);
spriteBatch.End();
device.RasterizerState = RasterizerState.CullCounterClockwise;
device.BlendState = BlendState.Opaque;
device.DepthStencilState = DepthStencilState.Default;
}
So is my use of Viewport wrong or do I just need to use it's information differently in spriteBatch.Draw()?

I think this should do the trick using viewport project... taking two projection points and calculating its distance you get a value affected by depth... so if it's deeper that value will be smaller.
public void Draw(Camera camera, GraphicsDevice device, SpriteBatch spriteBatch, Texture2D Texture)
{
Vector3 pos1= device.Viewport.Project(
this.position,
camera.Projection, camera.View, camera.World);
Vector3 pos2= device.Viewport.Project(
this.position+ Vactor3.UnitY*10,
camera.Projection, camera.View, camera.World);
Vector2 pos = new Vector2(pos1.X, pos1.Y);
Vector2 origin = new Vector2(Texture.Bounds.Center.X, Texture.Bounds.Center.Y);
float Scale = Vector3.Distance(pos1, pos2) * CustomRatio;
spriteBatch.Begin();
spriteBatch.Draw(Texture, pos, null, Color.White, 0,
origin, Scale, SpriteEffects.None, 0);
spriteBatch.End();
device.RasterizerState = RasterizerState.CullCounterClockwise;
device.BlendState = BlendState.Opaque;
device.DepthStencilState = DepthStencilState.Default;
}
In other hand... your previous code seems to be extracted from a source that drinks from this article made by the guy behind Xna that explain how to use basiceffect to draw billboards in 3D with spritebatch...
http://blogs.msdn.com/b/shawnhar/archive/2011/01/12/spritebatch-billboards-in-a-3d-world.aspx
I hope it helps you

Figured it out, you have to enable textures on the effect and then set effect.Texture to the Texture2D you want to use just before calling spriteBatch.Begin() in the draw function

Related

Smooth text, jittery sprites

with Monogame I am making a game that draws both graphics and text to the screen, with position modified by a camera matrix. If I set the position of text to the camera position, everything is fine, but when I set sprites to the camera position there is very noticeable jittering as the camera moves. I think this is because graphics are drawn with rectangles which require integer positional values. I guess text has no such requirement though.
How do I get my graphics to follow the camera movement smoothly like the text does?
If it's of use, this is my spriteBatch.Begin() call:
spriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.LinearClamp, null, null, null, camera.GetTransformation(graphics));
And this is my camera transformation:
public Matrix GetTransformation(GraphicsDeviceManager graphicsDevice)
{
Vector3 newVector = new Vector3(-GameInfo.info.cameraPosition.X, -GameInfo.info.cameraPosition.Y, 0);
cameraTransformMatrix = Matrix.CreateTranslation(newVector) *
Matrix.CreateRotationZ(rotation) *
Matrix.CreateScale(new Vector3(zoom, zoom, 1)) *
Matrix.CreateTranslation(new Vector3(GameInfo.info.resolutionWidth * 0.5f, GameInfo.info.resolutionHeight * 0.5f, 0));
return cameraTransformMatrix;
}
Thanks!
I have managed to fix the problem by using a different overload of SpriteBatch.Draw() which doesn't rely on a destination rectangle:
spriteBatch.Draw(texture, position, rSpriteSourceRectangle, Color.White);
For reference, this was my old one:
spriteBatch.Draw(texture, new Rectangle(drawX, drawY, frameWidth, frameHeight), rSpriteSourceRectangle, Color.White);

C# XNA - Start draw from bottom-center

Normally XNA start drawing sprite from top-left, but I would like to start draw object from bottom-center, how this could be done?
You want to specify a different origin in your SpriteBatch.Draw calls. The default is 0,0 (top-left). Note that the origin is relative to the sprite, not the screen.
So if your sprite is 64x64, you want to use an origin of 32x64 for bottom center.
e.g. using this override (MSDN)
spriteBatch.Draw (
texture,
position,
sourceRectangle,
color,
rotation,
new Vector2(32, 64), // origin
scale,
effects,
layerDepth
)
You can calculate these on the fly if you wish. e.g if you're using the full texture you could specify it as new Vector2(texture.Center.X, texture.Height). Or alternatively you could base it on the sourceRectangle if you're using a sprite sheet.
You need to specify a bunch of other arguments to use these Draw overrides but you can just pass in the defaults. The defaults are:
sourceRectangle: null = full texture
color: Color.White = default color (sprite colors will be used)
rotation: 0f = no rotation
scale: 1f = default scale
efects: SpriteEffects.None = no flipping
layerDepth: 0 = default layer
Lets say you are drawing an image WidthxHeight on position XxY.
spriteBatch.Draw(texture, position, Color.White);
First let's set the bottom of the image to those coordinates by subtracting images height from position's Y coordinate (subtracting because in XNA the Y-axis is inverted, not like in your math class)
spriteBatch.Draw(texture, position + new Vector2(0, -texture.Height), Color.White);
Second, let's set the image to the left by subtracting half of the image's width from position's X coordinate.
spriteBatch.Draw(texture, position + new Vector2(-texture.Width/2, -texture.Height), Color.White);
And there you have it.
Edit: Another thought: you can create new variable called DrawPosition and use that variable when needed, instead of always substracting. That would look something like this:
private Texture2D texture;
public Vector2 position;
public Vector2 DrawPosition
{ get { return position + new Vector2(-texture.Width/2, -texture.Height); } }
public void Draw(SpriteBatch spriteBatch)
{ spriteBatch.Draw(texture, DrawPosition, Color.White); }
Or, if this new variable doesn't make sense to you, create a function that will return the DrawPosition()
public Vector2 DrawPosition()
{ return position + new Vector2(-texture.Width/2, -texture.Height); }

Issues with drawing to alternative RenderTarget2D, seems to draw to backbuffer

So in order to get the Color[] data from a texture after it has been rotated in order to use this data for perpixel collisions, I use the following method to draw said texture (rotated) to a separate RenderTarget2D, then convert this back into a texture2D and get the color data from it:
public Color[] GetColorDataOf(SpriteBatch spriteBatch, Texture2D texture, float rotation)
{
// Get boundingBox of texture after rotation
Rectangle boundingBox = GetEnclosingBoundingBox(texture, rotation);
// Create new rendertarget of this size
RenderTarget2D buffer = new RenderTarget2D(GraphicsDevice, boundingBox.Width, boundingBox.Height);
// Change spritebatch to new rendertarget
GraphicsDevice.SetRenderTarget(buffer);
// Clear new rendertarget
GraphicsDevice.Clear(Color.Transparent);
// Draw sprite to new rendertarget
spriteBatch.Draw(texture, new Rectangle(boundingBox.Width / 2, boundingBox.Height / 2, texture.Width, texture.Height), null, Color.White, rotation, new Vector2(boundingBox.Center.X, boundingBox.Center.Y), SpriteEffects.None, 1f);
// Change rendertarget back to backbuffer
GraphicsDevice.SetRenderTarget(null);
// Get color data from the rendertarger
Color[] colorData = new Color[boundingBox.Width * boundingBox.Height];
Texture2D bufferTexture = (Texture2D)buffer;
bufferTexture.GetData(colorData);
return colorData;
}
Now I'm having two issues with that (I expect they are linked), firstly the texture gets drawn on screen, and all the Color[] data returned is empty (i.e all fields equal to 0).
** Edit **
Using Texture2D.SaveAsPng() I can see that bufferTexture is the correct size but just completely transparent indicating that the issue would lie in drawing to the buffer.
So I fixed it. Turns out I need to create another set of SpriteBatch.Begin() and SpriteBatch.End() calls around where I drew to the new rendertargets, otherwise it was just drawing to the backbuffer instead.

Drawing sprites to a permanent Texture2d using Monogame / XNA

(Cross post from Gamedevs)
I'm working with Monogame to do a 2d sprite engine. I've gotten it work pretty well where I can move lots of sprites around the screen with the effects and positions that I want.
Last night I tried to add a feature and I can't quite get it to work right.
I'm trying to create permanent trails that the moving sprites can leave behind. So I have a mostly transparent PNG with some white lines on it called "streak". The idea is that I set up a new Texture2D surface (called streakoverlay) and I draw the streaks on to it.
I switch back to the back buffer and draw: The background, the streakoverlay, and finally the sprite on top of it. The streaks should build up over time. It almost works, but the trouble I have is that streakOverlay seems to clear itself every time. How I'd like it to behave would be the same behaviour as having the graphics display without this line GraphicsDevice.Clear(Color.White); - everything would just pile up in it.
Instead it resets back to the Purple transparent color that is the default for that texture. Any suggestions? Here's the core piece of the rendering engine:
GraphicsDeviceManager graphics;
RenderTarget2D streakOverlay;
SpriteBatch spriteBatch;
private Texture2D bkg;
private Texture2D prototype;
private Texture2D streak;
//Initialize
graphics = new GraphicsDeviceManager(this);
GraphicsDevice.Clear(Color.Transparent);
streakOverlay = new RenderTarget2D(GraphicsDevice, 200,200);
//Load Content
bkg = Content.Load<Texture2D>("bkg"); //Background image
prototype = Content.Load<Texture2D>("prototype"); //Prototype sprite that moves around
streak = Content.Load<Texture2D>("blueStreak"); //Trails being left by Prototype sprite
graphics.GraphicsDevice.SetRenderTarget(streakOverlay);
GraphicsDevice.Clear(Color.Transparent); //Attempt to make the streakoverlay is fully transparent.
graphics.GraphicsDevice.SetRenderTarget(null);
//Draw
Random r = new Random();
graphics.GraphicsDevice.SetRenderTarget(streakOverlay); //Switch to drawing to the streakoverlay
spriteBatch.Begin();
//Draw some streaks that should accumulate
spriteBatch.Draw(streak, new Vector2(r.Next(0, 200), r.Next(0, 200)), null, Color.White, 0f, new Vector2(25, 25), 1f, SpriteEffects.None, 1f);
spriteBatch.End();
//Switch back to drawing on the back buffer.
graphics.GraphicsDevice.SetRenderTarget(null);
spriteBatch.Begin();
spriteBatch.Draw(bkg, new Rectangle(0, 0, 2000, 2000), Color.White); //Draw our background
spriteBatch.Draw(streakOverlay, new Vector2(0, 0), Color.White); //Put the overlay on top of it
spriteBatch.Draw(prototype, new Vector2(_spritePrototype.getX, _spritePrototype.getY), null, Color.White, DegreeToRadian(rotationSprite), new Vector2(25, 25), .5f, SpriteEffects.None, 0f); //Draw the sprite that's moving around.
spriteBatch.End();
base.Draw(gameTime);
You need to use the extended constructor for RenderTarget2D that takes 4 parameters and specify PreserveContents. The assumption is that render targets are often reused and so when it is set it gets cleared automatically unless this flag is set.

Rotate a Texture2D with the Draw method in XNA?

I have a problem with rotating. I know that I can rotate a Texture2D object with the draw method.
My goal is to rotate a texture by 180°. For example, if I make a picture of a human with the camera where the head is at the bottom, I want to be able to rotate it so that the head is at the top again.
Here is the code or the rotation:
spriteBatch.Draw(Texture, Position, null, Color.White, MathHelper.Pi, new Vector2(), 1.0f, SpriteEffects.None, 0f);
The rotation works fine, but I have another problem:
If I add the texture to position 0,0 after rotating it, it's not visible anymore.
How do I rotate or maybe reflect the object, so that the red point will be at the top-left corner again?
http://msdn.microsoft.com/en-us/library/ff433989.aspx
public void Draw (
Texture2D texture,
Vector2 position,
Nullable<Rectangle> sourceRectangle,
Color color,
float rotation,
Vector2 origin,
Vector2 scale,
SpriteEffects effects,
float layerDepth)
//Using:
var origin = new Vector2()
{
X = texture.Width / 2,
Y = texture.Height/ 2
};
spriteBatch.Draw(texture, Vector2.Zero, null, Color.White, MathHelper.Pi, origin, 1f, SpriteEffects.None, 0f)`

Categories

Resources