Affine Texture Mapping in shader (PS1-style graphics)

Hi Everyone,

I want to write a GLSL shader which does NOT do perspective mapping for textures. I want to accomplish the vintage PS1 style graphics just because they look so damn cool.

I’m having trouble implementing this though, I hope anyone could help me. I need to know how to disable this perspecitve-correct sampling of the “texture2D(texture, uv)” process in the fragment shader.

Any help much appreciated.

That’s because you’re using uv to sample your texture. Try using gl_FragCoord.xy instead. It should give you screen-space coordinates in the [0, 1] range (actually, I’m not sure if it’s [-1, 1] range, I forget).

texture2D(texture, gl_FragCoord.xy);

Edit:

Actually, it gives you full pixel values, so to get a [0, 1] range, you’d have to divide by window.innerWidth & window.innerHeight, which you would pass to the shader as uniforms:

vec2 screenUVs = vec2(gl_FragCoord.x / 1920.0, gl_FragCoord.y / 1080.0);
texture2D(texture, screenUVs);
2 Likes

Thanks for the quick and informative reply!

I tried your code, but what I got is a kind of flat texturing of my 3D object viewed from my camera (because of screen-space). I think what I need is the the modelView coordinates (normalized) so before the projectionmatrix is applied - and so without any perspective correction applied to the texture. What do you think?

Thanks!

I’ll post my code just to be clear

script type=“x-shader/x-vertex” id=“vertexShader” >
void main()
{
vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0);
gl_Position = projectionMatrix * modelViewPosition;
}

script type=“x-shader/x-fragment” id=“fragmentShader” >
uniform sampler2D texture;
uniform float screen_width;
uniform float screen_height;
void main()
{
vec2 screenUVs = vec2(gl_FragCoord.x / screen_width, gl_FragCoord.y / screen_height);
gl_FragColor = texture2D(texture, screenUVs);
}

And here is the perspective-correct version (for comparison):

Hmm… you might need to apply these matrices to your UVs before passing them to the frag shader. Try something like this:

vShader:

attribute vec2 uv;
varying vec2 vUv;

void main() {
    // Apply transform to UVs
    vec4 modelViewUVs = modelViewMatrix * vec4(uv.x, uv.y, 1.0, 1.0);

    // Set UV varying to be sent to fShader
    vUv = modelViewUVs.xy; 

    vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0);
    gl_Position = projectionMatrix * modelViewPosition;
}

then you can use the transformed UVs in the fragShader

fShader:

uniform sampler2D texture;
varying vec2 vUv;

void main() {
    vec4 color = texture2D(texture, vUv);
    gl_FragColor = color;
}

To be honest, I’m not sure what kind of projection you’re trying to achieve, or even if this would work, but you have a few matrices to play with: modelMatrix, viewMatrix, modelViewMatrix, and projectionMatrix. Make sure you set your texture to repeat or mirror, in case you end up with a wild number range. I’d love to see what you end up with!

Edit:

Look into this tutorial to get a better understanding on how matrices work, maybe it can help you achieve the right transformation to your UVs.

1 Like

OK I did it!

I followed this lovely tutorial. => WebGL 3D Perspective Correct Texture Mapping

All you have to do is divide the gl_Position by the w value.

varying vec2 _uv;
void main()
{
_uv = uv;
vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0);
gl_Position = projectionMatrix * modelViewPosition;
//this line makes all the difference
gl_Position /= gl_Position.w ;
}

I’m not super sure yet why this does the job…

EDIT: actually the tutorial explains why this is perfectly - lol i’m stupid. Good day everyone! :slight_smile:

2 Likes

Hello everyone,

although I managed to implement the non-perspective texture mapping by dividing by w. I get a lot of unwanted (although really cool) glitches. Could anyone explain to me why these glitches are present?

you can experience it all here: http://webbb-dev.surge.sh/

Thank you.

EDIT: it seems those glitches only occur when certain vertexes are not within the camera’s viewport. When moving away from the 3D plane object so that it fits entirely in the camera’s canvas the glitches are gone.