Monday, October 14, 2019

textures - How can I draw a perspective-correct quad?


I'm trying to draw a quad in 2D (in SharpDX, but that is basically XNA). But texture correction is not working, and I'm getting only an affine textured quad.


enter image description here


I'm using BasicEffect to render it.


BasicTextureEffect = new BasicEffect(Device)
{
Alpha = 1.0f,

TextureEnabled = true,

LightingEnabled = false,
VertexColorEnabled = true,

Projection = Matrix.OrthoOffCenterLH(0.0f, ScreenWidth, ScreenHeight, 0.0f, 0.0f, 1.0f),
};

It is an 2D isometric game. I have pseudo-3D coordinates in isometric world (it's a shadow on the ground) converted to screen space, and then rendered using DrawQuad.


Do I need to set-up view (or projection?) somehow, to real 3D (emulate the isometric camera), and then draw this quad in 3D coordinates instead? How eventually? Or is there a way to correct this in 2D?


Update:


I've uploaded the actual partial screen-shot (Figure A), for you to see it's almost the same. (I cut it a bit, but it goes all to the corner)



Figure AFigure B
            Figure A                                         Figure B


Update 2:


I can confirm now, that plain SharpDX (XNA) BasicEffect does this with just plain UW mapping (4 corners of a square), and plain DrawQuad. I've temporarily changed it to include center point, and I do draw 4 triangles instead of 2 (Figure B), this reduces effect to minimum, but it's still there. It still needs to be solved, because I won't be using it only on shadow.



Answer



I've changed the shader according to the article suggested by Seth Battin. Now it performs perspectively correct quad texturing. Phew, bacon delivered:


enter image description here


For the future generations that may never happen. The input is in a form of the line vertexes A1/A2, B1/B2 that creates diagonals (rather then sequential vertexes):


public static Vector3 DrawPerspectiveCorrectQuad(VertexWithPerspective v1, VertexWithPerspective v2, VertexWithPerspective v3, VertexWithPerspective v4)
{

// detects intersection of two diagonal lines
Single divisor = (v4.Position.Y - v3.Position.Y) * (v2.Position.X - v1.Position.X) - (v4.Position.X - v3.Position.X) * (v2.Position.Y - v1.Position.Y);
Single ua = ((v4.Position.X - v3.Position.X) * (v1.Position.Y - v3.Position.Y) - (v4.Position.Y - v3.Position.Y) * (v1.Position.X - v3.Position.X)) / divisor;
Single ub = ((v2.Position.X - v1.Position.X) * (v1.Position.Y - v3.Position.Y) - (v2.Position.Y - v1.Position.Y) * (v1.Position.X - v3.Position.X)) / divisor;

// calculates the intersection point
Single centerX = v1.Position.X + ua * (v2.Position.X - v1.Position.X);
Single centerY = v1.Position.Y + ub * (v2.Position.Y - v1.Position.Y);
Vector3 center = new Vector3(centerX, centerY, 0.5f);


// determines distances to center for all vertexes
Single d1 = (v1.Position - center).Length();
Single d2 = (v2.Position - center).Length();
Single d3 = (v3.Position - center).Length();
Single d4 = (v4.Position - center).Length();

// calculates quotients used as w component in uvw texture mapping
v1.TextureCoordinate *= Single.IsNaN(d2) || d2 == 0.0f ? 1.0f : (d1 + d2)/d2;
v2.TextureCoordinate *= Single.IsNaN(d1) || d1 == 0.0f ? 1.0f : (d2 + d1)/d1;
v3.TextureCoordinate *= Single.IsNaN(d4) || d4 == 0.0f ? 1.0f : (d3 + d4)/d4;

v4.TextureCoordinate *= Single.IsNaN(d3) || d3 == 0.0f ? 1.0f : (d4 + d3)/d3;

// this is just PrimitiveBatch
// where VertexWithPerspective is basically VertexPositionTextureColor
// with Vector3 (uvw) instead of Vector2 (uv) for texture coordinates
// note: you need to create VertexWithPerspective yourself (decompilation ftw)
PerspectivePrimitives.DrawQuad(v1, v3, v2, v4);
}

No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...