Jump to content
  • Advertisement
Sign in to follow this  
firlionel

Sprite Rendering

This topic is 4114 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey, I'm currently trying to implement pixel-exact 2d sprite rendering. But now I'm stuck with a strange bug. I will just post first all the information that I think is needed to find the bug and then explain whats wrong (if it's not obvious). First some screenshots and a PIXrun-file with which you can watch the whole frame: http://rimproject.dyndns.org/das.png http://rimproject.dyndns.org/sprite_screenshot2.png http://rimproject.dyndns.org/sprite_run.pixrun Source to render a sprite:
float_t zn = 0.1f;
float_t zf = 10000.0f;
Matrix4x4f mat;
mat.ToIdentity();
Rectf r(0, 800, 0, 600);
mat._11 = 2 / (r.right - r.left);//2 / 799.0f;
mat._14 = (r.left + r.right) / (r.left - r.right);//-1.0f - 1.0f/799.0f;
mat._22 = 2 / (r.top - r.bottom);//-2 / 599.0f;
mat._24 = (r.top + r.bottom) / (r.bottom - r.top);//1.0f + 1.0f/599.0f;
mat._33 = 1 / (zf - zn); 
mat._34 = zn / (zn - zf); 
mat._44 = 1.0f;
vshader_constants_->SetFloatMatrix(constant_mat_orthogonal_, mat);

Vertex* v = vstream_->Lock<Vertex>(0, 0, LockDiscard);

Rectf texrect1 = texrect;
if (texrect1.right == 0)	texrect1.right = texture->GetWidth();
if (texrect1.bottom == 0)	texrect1.bottom = texture->GetHeight();

v[0].x = (float_t)position.left - 0.5f;
v[0].y = (float_t)position.top - 0.5f;
v[0].z = 0.5f;
v[0].rhw = 1.0f;
v[0].tu = texrect1.left / (float_t)texture->GetWidth();
v[0].tv = texrect1.top / (float_t)texture->GetHeight();

v[1].x = (float_t)position.right - 0.5f;
v[1].y = (float_t)position.top - 0.5f;
v[1].z = 0.5f;
v[1].rhw = 1.0f;
v[1].tu = texrect1.right / (float_t)texture->GetWidth();
v[1].tv = texrect1.top / (float_t)texture->GetHeight();

v[2].x = (float_t)position.left - 0.5f;
v[2].y = (float_t)position.bottom - 0.5f;
v[2].z = 0.5f;
v[2].rhw = 1.0f;
v[2].tu = texrect1.left / (float_t)texture->GetWidth();
v[2].tv = texrect1.bottom / (float_t)texture->GetHeight();

v[3].x = (float_t)position.right - 0.5f;
v[3].y = (float_t)position.bottom - 0.5f;
v[3].z = 0.5f;
v[3].rhw = 1.0f;
v[3].tu = texrect1.right / (float_t)texture->GetWidth();
v[3].tv = texrect1.bottom / (float_t)texture->GetHeight();

vstream_->Unlock();

graphicsdriver_->GetBlendState()->Enable();
graphicsdriver_->GetBlendState()->SetColorBlendOp(AlphablendOpAdd);
graphicsdriver_->GetBlendState()->SetColorSrcBlend(AlphablendSrcAlpha);
graphicsdriver_->GetBlendState()->SetColorDestBlend(AlphablendInvSrcAlpha);

pshader_constants_->SetFloatVector(constant_color_, Vector4f(modulation_color.r, modulation_color.g, modulation_color.b, modulation_color.a));
graphicsdriver_->GetVertexProcessingState()->SetVertexDeclaration(vertex_declaration_);
graphicsdriver_->GetVertexProcessingState()->SetVertexStream(0, vstream_, sizeof(Vertex));
graphicsdriver_->GetVertexProcessingState()->SetVertexShader(vshader_);
graphicsdriver_->GetVertexProcessingState()->SetConstantBuffer(vshader_constants_);
graphicsdriver_->GetPixelProcessingState()->SetPixelShader(pshader_);
graphicsdriver_->GetPixelProcessingState()->SetConstantBuffer(pshader_constants_);
graphicsdriver_->GetSamplerState(0)->SetTexture(texture);
graphicsdriver_->GetSamplerState(0)->SetMinFilter(TexFilterPoint);
graphicsdriver_->GetSamplerState(0)->SetMagFilter(TexFilterPoint);
graphicsdriver_->DrawPrimitive(PrimitiveTriangleStrip, 0, 2);

graphicsdriver_->GetBlendState()->Disable();

Source which calls the sprite-rendering:
sprite_->Render(test_texture_b_, Rect(0, 799, 0, 599), Rectf(0, 0, 0, 0), Colorf::WHITE());
// top left
sprite_->Render(test_texture_v_, Rect(5, 14, 5, 14), Rectf(0, 0, 0, 0), Colorf::WHITE());
sprite_->Render(test_texture_h_, Rect(5, 14, 15, 24), Rectf(0, 0, 0, 0), Colorf::WHITE());
// bottom left
sprite_->Render(test_texture_v_, Rect(5, 14, 575, 584), Rectf(0, 0, 0, 0), Colorf::WHITE());
sprite_->Render(test_texture_h_, Rect(5, 14, 585, 594), Rectf(0, 0, 0, 0), Colorf::WHITE());
// top right
sprite_->Render(test_texture_v_, Rect(785, 794, 5, 14), Rectf(0, 0, 0, 0), Colorf::WHITE());
sprite_->Render(test_texture_h_, Rect(785, 794, 15, 24), Rectf(0, 0, 0, 0), Colorf::WHITE());
// bottom right
sprite_->Render(test_texture_v_, Rect(785, 794, 575, 584), Rectf(0, 0, 0, 0), Colorf::WHITE());
sprite_->Render(test_texture_h_, Rect(785, 794, 585, 594), Rectf(0, 0, 0, 0), Colorf::WHITE());

The HLSL-Source:
sampler texSampler;

void vs_main(
  float4 inPosition : POSITION,
  float2 inTexCoord : TEXCOORD0,
  out float4 outPosition : POSITION,
  out float2 outTexCoord : TEXCOORD0,
  uniform float4x4 orthogonalProjection
)
{
  outPosition = mul(orthogonalProjection, inPosition);
  outTexCoord = inTexCoord;
}

void ps_main(
  float2 inTexCoord : TEXCOORD0,
  out float4 outColor : COLOR,
  uniform float4 modulationColor : float4
)
{
  outColor =
    tex2D(texSampler, inTexCoord) *
    modulationColor
  ;
}

The problem is that it doesn't render the images pixel-exact. As you may see in 'das.png' the colors are wrong. when you look at 'sprite_screenshot2.png' you can see that the row in the middle of the picture is white instead of black (every second row/column is black on the texture). I'd be very grateful if anyone could point me into a direction to solve the problem! Thanks, Chris

Share this post


Link to post
Share on other sites
Advertisement
Right, sorry, didn't see you were modifying the position.

While I don't think this would fix it, I think offsetting the texcoords would be a better idea than offsetting the position. In addition, I believe a factor of around 0.4 might be more accurate.

Hope this helps.

Share this post


Link to post
Share on other sites
(-0.5 / texmap_width) and (-0.5 / texmap_height). It is common to pass the texmap dimensions as a shader constant.

Share this post


Link to post
Share on other sites
Well I tried to offset texture coordinates instead of positions which resulted in the same picture as when offsetting positions.

I also noticed that in both configurations (when offseting positions and when offsetting texture coordinates) the rendering differs between reference rasterizer and hardware-device. Although when offsetting texture coordinates the difference between them isn't as big. Additionaly neither ref-rast nor the hardware-device create the expected output.

Do you have an idea why?

I also had a look into Crazy Eddies Gui (he's offsetting positions by -0.5 as I did) and irrlicht (uses completly another procedure with calculating vertices on the cpu) and I'm wondering if their results are pixel-exact...

Thanks for ideas!
Chris

Share this post


Link to post
Share on other sites
Thinking about it, I think I should've suggested a positive offset in tex coords of 0.5/w and 0.5/h - sorry.

Share this post


Link to post
Share on other sites
Now that you mention it and I look again at my code I see that I've coded it by intuition (or mistake...) the right way around yesterday. I just tried with negative offsets which (logically) results in textures wrapping around so I think I would have noticed that.

Chris

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!