How to center a shader-only plane?

It is about shader in relation to Three.

To illustrate my problem, I have integrated the simplest example of “Books of shader” within Three.

Generally speaking, it seems that it works if a plane has the same dimensions as the screen.

But, I wonder that I cannot control the horizontal orientation and the dimensions of the plane (which is a shader-only square without texture in the example).

So, I also set the screen height for the plane’s width and center it horizontally which does not work.
Neither the plane is centered nor it is square.

Has anyone an idea what is happening here?

<!DOCTYPE html>

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style type="text/css">
        body {
            overflow: hidden;

        canvas {
            width: 100%;
            height: 100%;

    <script src=""></script>
        const vshader = `
            void main() {
                gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
        const fshader = `
        #ifdef GL_ES
            precision mediump float;

        void main() {
            gl_FragColor = vec4(1.0,0.0,1.0,1.0);


        const scene = new THREE.Scene();
        scene.background = new THREE.Color(0xffffff);

        const camera = new THREE.PerspectiveCamera(
            window.innerWidth / window.innerHeight,
        camera.position.z = 5;

        const renderer = new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth, window.innerHeight);

        const geometry = new THREE.PlaneGeometry(window.innerHeight, window.innerHeight);
        const uniforms = {
        const material = new THREE.ShaderMaterial({
            uniforms: uniforms,
            vertexShader: vshader,
            fragmentShader: fshader
        const plane = new THREE.Mesh(geometry, material);


        function animate() {

        function render() {
            renderer.render(scene, camera);


Does it work better with this code?

The idea is to render with an orthographic camera similar to webgl_shader.

1 Like

Idk what were you REALLY asking, but check this out

1 Like

I’ve done this :smiley:

That’s what happens when you don’t provide an expalanatory picture of the desired result :slight_smile: A stack of different solutions :smiley:

Thanks folks, but the problem is as mentioned :wink:

  • square plane without any texture
  • center plane horizontally (given a landscape screen)
  • the plane’s height is the height of the screen
  • coloration of the plane by shader

Could you provide an explanatory picture of what you want to achieve?
So users won’t waste their time, making fortune-telling with solutions. check this fiddle.
Do you want to have a coloured square or a rectangle that fills the screen?

As told, I want a coloured and horizontally centered square which is as high as the screen.

I’ve updated the last fiddle


Thank you very much @prisoner849.

This is what I have always wanted. :wink:

I will analyse why your example works.

Wow, I am always surprised how complicated the shaders are with the simplest problems.

May I ask you for a hint about the concepts behind your solution?

Behind my solution is pure trigonometry.
Having an angle (camera.fov / 2) and the adjacent cathetus (distance), you can find the opposed cathetus, multiplying the length of the adjacent cathetus with tangent of the angle (distance * tan(fov/2)).

verbose, not complicated. the effort to understand it is not that difficult, really.

1 Like

I don’t think i understood the request at all, but could this perhaps help?

Thanks for the useful explanations, @prisoner849.

I assume, that all these calculations are needed because of the lack of a texture of the plane? Right?

For the few ones who are really interested in the topic:
I made the @prisoner849’s vertex shader over for checking if it is fitting with other aspect ratios (e.g. 3:2 portrait):

const vshader = `
        uniform float uDistance;
        uniform float uFov;

        void main() {
            // e.g. 3:2 portrait (as high as window)
            float _y = uDistance * tan(uFov);
            float _ratio = 2.0 / 3.0 ;
            vec3 _xyz = vec3( _y * _ratio, _y, uDistance ) * sign(position);
            gl_Position = projectionMatrix * modelViewMatrix * vec4( _xyz, 1.0 );

            // e. g. square (as high as window)
            // vec3 _xyz = vec3( vec2( uDistance * tan(uFov) ), uDistance ) * sign(position);
            // gl_Position = projectionMatrix * modelViewMatrix * vec4( _xyz, 1.0 );

You can pass ratio in a uniform.

Thank you for your hint, @prisoner849.