Sign in to follow this  
speciesUnknown

Rendering from a sprite map using textured quads

Recommended Posts

speciesUnknown    527
Hi,
I'm trying to make my own spritebatch, one which will let me use an arbitrary view matrix.

Unfortunately spritebatch does not allow one to pass it a view matrix, it does allow you to pass it a model matrix, but this is not the same thing at all.

Anyway, when I try to emulate the drawing behaviour of SpriteBatch for a single quad, I cant get the texture coordinates right. What happens is that I get texels from the surrounding sprites in the borders of the quad I render. I've tried various tweaks to the texture coordinates, including offsets of 1 0.5 -1 -0.5 and -1.5 and 1.5 and I still get the border issue, just differently each time. Ive also tried no offset.

I also tried messing with the sampler states by setting the mag filters in case thats the issue, but again this has failed; setting the mag filter to Point has no visible effect.

[code]
/// <summary>
/// Draw a sprite as a section of a texture (basic_effect.g. if the texture has several sub images in it)
/// This is nowhere near as performant as SpriteBatch - ideally i need to implement my own batching
/// </summary>
/// <param name="texture">the name of the texture to draw from</param>
/// <param name="position">the position to draw the sprite in</param>
/// <param name="size"> the size to scale the output up to</param>
/// <param name="section">the subsection of the texture to use; if null, use whole texture</param>
public void drawSprite(string texture, Position pos, Rectangle section)
{

// set up texture coordinates and sampling properties
Texture2D tex = this.resourceManager.textures.getResource(texture);
float xscale = 1f / (float)tex.Width;
float yscale = 1f / (float)tex.Height;

float w = section.Width;
float h = section.Height;

// d3d requires a bias of 0.5 in each dimension when texture sampling as it uses the top left of each texel and not the centre
float tex_xstart = section.X + 0.5f;
float tex_xend = tex_xstart + (float)section.Width;

float tex_ystart = section.Y + 0.5f;
float tex_yend = tex_ystart + (float)section.Height;

VertexPositionTexture[] quadPointList = new VertexPositionTexture[4];

Matrix local_rotation = Matrix.CreateRotationZ(pos.RadiansRot);
// Matrix local_rotation = Matrix.Identity;

Vector3 world_translation = new Vector3(pos.X, pos.Y, pos.Depth);

quadPointList[0] = new VertexPositionTexture(Vector3.Transform(new Vector3( -0.5f * w, -0.5f * h, 0), local_rotation) + world_translation, new Vector2(tex_xstart * xscale, tex_ystart * yscale));
quadPointList[1] = new VertexPositionTexture(Vector3.Transform(new Vector3( 0.5f * w, -0.5f * h, 0), local_rotation) + world_translation, new Vector2(tex_xend * xscale, tex_ystart * yscale));
quadPointList[2] = new VertexPositionTexture(Vector3.Transform(new Vector3( 0.5f * w, 0.5f * h, 0), local_rotation) + world_translation, new Vector2(tex_xend * xscale, tex_yend * yscale));
quadPointList[3] = new VertexPositionTexture(Vector3.Transform(new Vector3( -0.5f * w, 0.5f * h, 0), local_rotation) + world_translation, new Vector2(tex_xstart * xscale, tex_yend * yscale));

// Initialize the vertex buffer, allocating memory for each vertex.
VertexBuffer vertexBuffer = new VertexBuffer
(
this.graphics,
VertexPositionTexture.SizeInBytes * (quadPointList.Length),
BufferUsage.None
);

// Set the vertex buffer data to the array of vertices.
vertexBuffer.SetData<VertexPositionTexture>(quadPointList);

// tell graphics device to use that vertex buffer
this.graphics.Vertices[0].SetSource(vertexBuffer, 0, VertexPositionTexture.SizeInBytes);
this.graphics.VertexDeclaration = new VertexDeclaration(
this.graphics,
VertexPositionTexture.VertexElements
);

// use the default basic_effect shader
basic_effect.View = viewMatrix;
basic_effect.Projection = projectionMatrix;
basic_effect.World = worldMatrix;
basic_effect.TextureEnabled = true;
basic_effect.Texture = tex;
basic_effect.VertexColorEnabled = false;
basic_effect.LightingEnabled = false;


// apply the Depth buffer settings we need
this.graphics.RenderState.DepthBufferEnable = this.depthBufferEnable;
this.graphics.RenderState.DepthBufferWriteEnable = this.depthBufferWriteEnable;
this.graphics.RenderState.DepthBufferFunction = this.depthBufferFunction;

this.graphics.RenderState.CullMode = CullMode.None;

this.graphics.SamplerStates[0].MagFilter = TextureFilter.Point;

basic_effect.CommitChanges();

basic_effect.Begin();
foreach (EffectPass ep in basic_effect.CurrentTechnique.Passes)
{
ep.Begin();
this.graphics.DrawUserIndexedPrimitives<VertexPositionTexture>(
PrimitiveType.TriangleList,
quadPointList,
0, // vertex buffer offset to add to each element of the index buffer
4, // number of vertices in quadPointList
quadIndices, // the index buffer
0, // first index element to read
2 // number of primitives to draw
);
ep.End();
}
basic_effect.End();
}
[/code]

What I find most unusual is that which edge of the texture is bled into by the surrounding textures depends on how the quad is rotated, but this makes no sense, it should always be from the same direction as each point has the same texture coords regardless of its rotation.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this