Screen position in pixel shader

I’m trying to write a shader with logic dependent on fragment’s screen position.

Basically that’s what gl_Position is from vertex shader, which is usually a result of matrix_viewProjection * matrix_model * vertex_position.

In pixel shader screen position is expected to be calculated with something like this:
vec4 pos = matrix_viewProjection * vec4 (vPositionW, 1.0);

But that doesn’t produce the intended result. When testing it with code like this:
vec3 emission = pos.x > 0.5 ? vec3 (0.0, 1.0, 0.0) : vec3 (1.0, 0.0, 0.0);

I get colors split not in screen space, but with some virtual plane of sort:
bug

Here is the project:
https://playcanvas.com/editor/scene/779340

How do I achieve perfect screen space shader logic?

i have a solution. I only keep the gl_Position from vert to frag shader and make the “simple” calculation first in frag shader. getScreenPosition() return the screen position between vec2(0.0, 0.0) and vec2(1.0, 1.0), when you apply display width and height you could calculate exact screen pixel.

/* jshint esversion: 6 */
let ScreenSpace = pc.createScript('screenspace');

// initialize code called once per entity
ScreenSpace.prototype.initialize = function() {
    this.entity.model.meshInstances.forEach(inst => {
        const material = inst.material.clone();
        
        material.chunks.startVS = `
            varying vec4 screenPosition;

            void main(void) {
                gl_Position = getPosition();
                screenPosition = gl_Position;
        `;
        material.chunks.diffusePS = `
            varying vec4 screenPosition;
            uniform sampler2D texture_diffuseMap;

            vec2 getScreenPosition() {
                return (screenPosition.xy / screenPosition.w + 1.0) * 0.5;
            }

            void getAlbedo() {
                dAlbedo = texture2DSRGB(texture_diffuseMap, getScreenPosition()).$CH;
            }
        `;

        material.update();

        inst.material = material;
        
    });
};

// update code called every frame
ScreenSpace.prototype.update = function(dt) {
    
};

2 Likes