Page 1 of 1

Fast Perspective Correction of textured Trapezoids .. and Array Textures on a Mesh

Posted: Tue Nov 30, 2021 12:17 pm
by UnixRoot
Hi there, while developing my Pseudo3D racing game with polygonal 2D segments, I discovered someting. For Trapezoids with at least 2 parallel lines, you can get perspective correction on the GPU for free. Without fancy calculations or real 3D. No more affine texture mapping.

You can simply use the widths of the mesh as the W value for the vertex and pixelshader. In the Vertex shader you simply multiply the UV coords with W and in the Pixel shader you divide the UVs by W.

I've written a quick and dirty demo, with perspective correction and the use of an array texture on a mesh
trapezoid.love
(6.02 KiB) Downloaded 299 times
I know it's nothing fancy, but hey, maybe someone finds it useful.

Image

Re: Fast Perspective Correction of textured Trapezoids .. and Array Textures on a Mesh

Posted: Tue Nov 30, 2021 7:57 pm
by darkfrei
Very nice! But how it works?

Code: Select all

local perspective = love.graphics.newShader [[
  uniform ArrayImage MainTex;
  #ifdef VERTEX
    vec4 position( mat4 transform_projection, vec4 vertex_position )
    {
      VaryingTexCoord.xyz *= VaryingTexCoord.w; 
      return transform_projection * vertex_position;
    }
  #endif
  #ifdef PIXEL
    void effect() {
      love_PixelColor = Texel(MainTex, VaryingTexCoord.xyz / VaryingTexCoord.w);
    }
  #endif
]]

Re: Fast Perspective Correction of textured Trapezoids .. and Array Textures on a Mesh

Posted: Tue Nov 30, 2021 9:49 pm
by UnixRoot
darkfrei wrote: Tue Nov 30, 2021 7:57 pm Very nice! But how it works?
Actually, it works exactly like the perspective correction the GPU is calculating in real 3D scenes. We linearly interpolate the UV coordinates.

Unfortunately, in 2D we are missing the depth information.

But for a trapezoid with 2 parallel sides, the W values of the vertices are in the same ratio as the lengths of its parallel sides. So you can also send the side lengths directly to the shader as a fake W values, the ratio is correct.

Re: Fast Perspective Correction of textured Trapezoids .. and Array Textures on a Mesh

Posted: Wed Dec 01, 2021 1:07 pm
by pgimeno
Nice find! I guess it's a cheap version of https://love2d.org/forums/viewtopic.php?f=5&t=12483 (the latter has the problem that it's expensive to calculate).

Re: Fast Perspective Correction of textured Trapezoids .. and Array Textures on a Mesh

Posted: Wed Dec 01, 2021 1:40 pm
by grump
This can be simplified further for most use cases: use the builtin function texture2DProj. The code becomes simpler, and it's faster too because there's no dependent texture fetch in the fragment shader, which can be slow especially on mobile GPUs.

OP's solution is the way to go when using ArrayImages though, since texture2DProj can't be used with sampler2DArray. There is a general textureProj function that may work for this, but I'm not sure; haven't used it.

OP's modified code:

Code: Select all

local perspective = love.graphics.newShader [[
  uniform Image MainTex;
  void effect() {
      love_PixelColor = texture2DProj(MainTex, VaryingTexCoord.xyz);
  }
]]
local width_top, width_bottom = 300, 600
local height = 300
local vertexFormat = {
  {"VertexPosition", "float", 2},
  {"VertexTexCoord", "float", 3}
}

local ratio = width_bottom / width_top
local uv = {
    { u = 0, v = 0, z = 1 },
    { u = 1, v = 0, z = 1 },
    { u = 1 * ratio, v = 1 * ratio, z = 1 * ratio },
    { u = 0 * ratio, v = 1 * ratio, z = 1 * ratio }
}

local mesh = love.graphics.newMesh( vertexFormat, {
  --  X,                Y,        U,        V,        Z
    { -width_top/2,     0,        uv[1].u,  uv[1].v,  uv[1].z }, -- Top Left Corner
    {  width_top/2,     0,        uv[2].u,  uv[2].v,  uv[2].z }, -- Top Right Corner
    {  width_bottom/2,  height,   uv[3].u,  uv[3].v,  uv[3].z }, -- Bottom Right Corner
    { -width_bottom/2,  height,   uv[4].u,  uv[4].v,  uv[4].z }  -- Bottom Left Corner
    }, "fan", "static")


love.graphics.setDefaultFilter("nearest")
local texture = love.graphics.newImage("0.png")
mesh:setTexture(texture)

function love.draw()
  love.graphics.setShader(perspective)
  love.graphics.draw(mesh,400,150)
end

Re: Fast Perspective Correction of textured Trapezoids .. and Array Textures on a Mesh

Posted: Wed Dec 01, 2021 2:03 pm
by UnixRoot
pgimeno wrote: Wed Dec 01, 2021 1:07 pm Nice find! I guess it's a cheap version of https://love2d.org/forums/viewtopic.php?f=5&t=12483 (the latter has the problem that it's expensive to calculate).
As you can see, it's getting even cheaper, if you don't use array textures.
grump wrote: Wed Dec 01, 2021 1:40 pm This can be simplified further for most use cases: use the builtin function texture2DProj.
Nice addition Grump. Thanks

Re: Fast Perspective Correction of textured Trapezoids .. and Array Textures on a Mesh

Posted: Wed Dec 01, 2021 11:21 pm
by grump
UnixRoot wrote: Wed Dec 01, 2021 2:03 pm Nice addition Grump. Thanks
Thank you for making me think about the problem ;)

I hope you're going for this clean look in your game instead of the janky look from past screenshots. It looks so much better.

Re: Fast Perspective Correction of textured Trapezoids .. and Array Textures on a Mesh

Posted: Thu Dec 02, 2021 7:19 am
by UnixRoot
grump wrote: Wed Dec 01, 2021 11:21 pm I hope you're going for this clean look in your game instead of the janky look from past screenshots. It looks so much better.
Yes, I'm definitely aiming for a clean look, but with the possibility to play in lower, more retro like resolutions. But I'm not there yet, I'm still experimenting with the track construction and the pseudo 3D projection.

It's harder than I thought to get the exact driving feel of the old classics.