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);
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.
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?
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.
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.
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With