Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Three.js - Scaling a plane to full screen

Tags:

I am adding a plane to the scene like this:

// Camera
this.three.camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 60);
// Plane
const planeGeometry = new THREE.PlaneBufferGeometry(1,1,this.options.planeSegments,this.options.planeSegments);
const planeMat = new THREE.ShaderMaterial( ... )
this.three.plane = new THREE.Mesh(planeGeometry,planeMat);
this.three.scene.add(this.three.plane);

Pretty basic. I am than trying to find out how I have to move the plane in the Z axis for it to fill the browser-viewport. For that,

// See attachment "solving for this" is closeZ
const closeZ = 0.5 / Math.tan((this.three.camera.fov/2.0) * Math.PI / 180.0);
this.uniforms.uZMax = new THREE.Uniform(this.three.camera.position.z - closeZ);

enter image description here

So now I know in my shader how much I can add to Z to make the plane fill the viewport. Vertex Shader looks like this:

uniform float uZMax;

void main() {   
    vec3 pos = (position.xy, uZMax);
    gl_Position = projectionMatrix * modelViewMatrix * vec4( pos, 1 );
}

This actually zoom the plane to fill the viewport, but in Y-Axis, not in X-Axis.

enter image description here

I would like to discover why my math is referring to the Y-Axis and how I need to transform it, so the plane will fill the viewport width instead of it's height?

Edit:

I'm trying to achieve something like this https://tympanus.net/Tutorials/GridToFullscreenAnimations/index4.html - But in the given example they're just scaling the x- and y-pixels to fill the screen and therefore no actual 3d - and therefore again no lighting is going on.

I want to actually move the plane towards the camera using different z-values so I can calculate surface normals to then again calculate lighting in the fragment shader by how aligned the normal is with the light direction - like it's done in raymarching.

like image 542
marks Avatar asked Sep 13 '20 15:09

marks


2 Answers

You can easily achieve such a fullscreen effect by using the following setup:

const camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );

const geometry = new THREE.PlaneBufferGeometry( 2, 2 );

When creating a mesh with this geometry and a custom shader material, the orthographic camera will ensure the intended fullscreen effect. This approach is used in all post-processing example where the entire viewport has to be filled with a single quad.

like image 165
Mugen87 Avatar answered Sep 30 '22 21:09

Mugen87


I figured it out, and as suspected it has to do with the aspect ratio passed to the camera. For anyone looking for a solution after me, here is how it works:

I wrongly assumed that the field-of-value for the camera is the same in all directions. But the FOV is referring to the Y-Axis FOV, so we have to convert the camera-fov to the x-axis also:

function getXFOV() {
        // Convert angle to radiant
        const FOV = this.three.camera.fov;
        let yFovRadiant = FOV * Math.PI/180;
        // Calculate X-FOV Radiant
        let xFovRadiant = 2 * Math.atan( Math.tan(yFovRadiant/2) * (window.innerWidth / window.innerHeight));
        // Convert back to angle
        let xFovAngle = xFovRadiant * 180/Math.PI;
        return xFovAngle;

}

And then we simply use that angle in in the closeZ-calculation instead of the camera's fov. Now it snaps to the window-width.

const closeZ = 0.5 / Math.tan((this.getXFOV()) * Math.PI / 180.0);
this.uniforms.uZMax = new THREE.Uniform(this.three.camera.position.z - closeZ);
like image 34
marks Avatar answered Sep 30 '22 20:09

marks