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

Showcase your libraries, tools and other projects that help your fellow love users.
Post Reply
User avatar
UnixRoot
Citizen
Posts: 80
Joined: Mon Nov 08, 2021 8:10 am

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

Post 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 287 times
I know it's nothing fancy, but hey, maybe someone finds it useful.

Image
User avatar
darkfrei
Party member
Posts: 1168
Joined: Sat Feb 08, 2020 11:09 pm

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

Post 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
]]
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
UnixRoot
Citizen
Posts: 80
Joined: Mon Nov 08, 2021 8:10 am

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

Post 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.
User avatar
pgimeno
Party member
Posts: 3541
Joined: Sun Oct 18, 2015 2:58 pm

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

Post 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).
grump
Party member
Posts: 947
Joined: Sat Jul 22, 2017 7:43 pm

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

Post 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
User avatar
UnixRoot
Citizen
Posts: 80
Joined: Mon Nov 08, 2021 8:10 am

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

Post 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
grump
Party member
Posts: 947
Joined: Sat Jul 22, 2017 7:43 pm

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

Post 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.
User avatar
UnixRoot
Citizen
Posts: 80
Joined: Mon Nov 08, 2021 8:10 am

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

Post 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.
Post Reply

Who is online

Users browsing this forum: No registered users and 16 guests