Threejs orthographic camera viewport - javascript

I use orthographic camera and i struggle with correct viewport calculation.
I want to push camera to the left for 100px to render something else in extra area.
In the following example there's a rendered green cube (for which i want to fix my viewport) and red square (expecting result made with css).
I can't change canvas size - it has to be 100% width and 100% height.
Best solution so far was to add extra value to camera left like:
camera.left = - frustumSize * correctionAspect + 10;
But of course it doesn't scale. Other solution was to calculate camera.left with different aspectRatio like in the commented code:
correctionAspect = (width + 200) / height;
But it doesn't work well either.
Example code: https://stackblitz.com/edit/js-nydhjw

Related

Three.js - Take up all available space with plane geometry (emulate background-size:cover property)

I would like to build a three.js scene containing a large plane geometry that should take up all the available space, regardless of the aspect ratio of the viewport.
I have made a rough fiddle to highlight the issue: https://jsfiddle.net/nq2oy9ca/1/
Using the following resize function:
window.addEventListener('resize', function() {
camera.aspect = window.innerWidth/window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth,window.innerHeight);
});
the image is only scaled if there are changes to the y axis of the viewport - it doesn't react to changes on the x axis.
This means that it will take up all space only if the viewport has a narrow aspect ratio: if the aspect ratio becomes wide enough, the background will become visible to the the left and the right.
Removing the function prevents the image from being resized at all.
I reckon the result could be achieved by dynamically updating the camera distance ( camera.position.z ) whenever the viewport is resized, but i don't know how that value correlates to the viewport \ canvas size.
Any feedback would be appreciated, thanks in advance!

Resize canvas without enlarge the elements WEBGL

I m new in WebGl and i wish resize the canvas without enlarge all the elements.
i try to edit in the HTML file this line of code:
<canvas id="gl-canvas" width="512"" height="512">
with the new one
<canvas id="gl-canvas" width="1024"" height="1024">
but the figure inside the html will be more big and i dont want. I want just resize the space that contain the elements.
i tried to do this one too:
In the JS file i tried to edit
gl.viewport( 0, 0, canvas.width, canvas.height );
with
gl.viewport( 0, 0, 0.5*canvas.width, 0.5*canvas.height );
the figure will be half smaller, but the space remain the same. I need more space for the animation because now at some point the animation exits the screen even if I have a lot of space still available (which is white).
I want upload some photos for explain better my point
My Canvas
Details of the Web Inspector
thanks.
WebGL requires you to draw the items yourself to match the size. WebGL takes normalized coordinates in (called clip space). They always go from -1 to +1 across the canvas and -1 to +1 up the canvas regardless of size. To draw anything you supply math via JavaScript and/or GLSL shaders that take whatever data you supply and convert that data to clip space. That means if you want the items to stay the same size you need to adjust the math you're using to draw the things you are drawing. Without seeing your math we can't really know what to suggest.
The most common way to draw things in WebGL is to multiply 2D or 3D data by 1 or more matrices. You can read about that here. You may need to read the articles before that one to understand that one. You may also wish to read the articles after that one as they continue from 2D to 3D
So, then there is no easy answer except to say it's up to you to decide on a solution to fix your math. Without knowing what math you're using we can't suggest a way to keep the size the same.
If you were using clip space coordinates directly then you could just pass in an X and Y scale. if the canvas gets twice as large then scale by half as much and the objects would stay the same size.
gl_Position = someClipspaceCoordinates * vec4(scaleX, scaleY, 1, 1);
If you were using an orthographic projection then you'd choose some number of units per pixel and adjust the values you pass into your orthographic projection matrix making function
const pixelsPerUnit = ???;
const unitsAcross = gl.canvas.clientWidth / pixelsPerUnit;
const unitsDown = gl.canvas.clientHeight / pixelsPerUnit;
// assuming you want 0,0 at the center
const left = -unitsAcross / 2;
const right = unitsAcross / 2;
const bottom = -unitsDown / 2;
const top = unitsDown / 2;
const near = ???;
const far = ???;
const projectionMatrix = someOrthographicProjectionMatrixFunction(
left, right, bottom, top, near, far);
If you were drawing in 3D using a perspective projection then you'd have to either calculate a field of view based on the width or height of the canvas to keep objects the same size, OR, move the camera closer to or further away from the objects.
To adjust by field of view you'd do something like
const fovPerPixel = 0.1 * Math.PI / 180;
const fov = gl.canvas.clientHeight * fovPerPixel;
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const near = 0.5;
const far = 1000;
const projectionMatrix = somePerspectiveProjectionMatrixFunction(
fov, aspect, near, far);
Note that this method has the issue that as the canvas gets larger the things drawn toward the edges of the canvas will get more and more distorted as the field of view gets wider and wider to keep everything the same size. When the field of view hits 180 degrees or wider the perspective math will break and things won't display.
To adjust by moving the camera see this answer as a starting point.

Craftyjs scene size

I'm working with crafty on a game with an open world and i want to use the full window screen.
But when i start the game, the scene is not the full width.
I have tried:
Crafty.init(window.innerWidth, window.innerHeight);
Crafty.viewport.init(window.innerWidth, window.innerHeight);
It seems that it takes the biggest sprite width & height and uses that.
But when i try to create a bigger rectangle so it would use that, it still uses that sprites' height & width
Crafty.canvas.init(..) seems to create a new canvas.
How do i create a full size canvas-scene in crafty?
In crafty 0.5.4 in the Crafty.viewport.init() function, the width and height of crafty is initialized as:
this.width = (!w ? w : Crafty.DOM.width (something like that))
same for height
Change Crafty.DOM.width to window.innerWidth and it is fixed
PS. Crafty 0.6(beta) solves this too.

Three.js - Width of view

Is there a way to find out the width of a rendered portion of the scene?
For example, if we have a mesh of width 100, but rendered with a certain level of zoom...how can I calculate the width of the portion of the mesh that is being rendered in the screen?
You have to be precise here.
You can calculate the visible rectangular region given the camera's field-of-view, camera.fov, and a given distance, dist, from the camera.
Since the object presumably has depth, you have to pick one plane through the mesh, and do the calculation at that distance.
Here is how to calculate the visible height and width for a given distance dist from the camera.
var vFOV = THREE.MathUtils.degToRad( camera.fov ); // convert vertical fov to radians
var height = 2 * Math.tan( vFOV / 2 ) * dist; // visible height
var width = height * camera.aspect; // visible width
three.js r.117
For a (perfect) spherical object, it will cover more of the view close up as you need to take the tangent into account i.e. you can't see the 'poles'.
Use the following for a spherical object:
// we're using the following triangle: camera - tangent point on sphere - centre of sphere
var targetAngle = 2 * Math.asin(objectRadius / distanceToCamera);
var vFOV = THREE.Math.degToRad(this.fov);
var normalizedHeight = targetAngle / vFOV;
Multiply this with your viewport width to get screen height. For width you need to apply hFOV - see: 90 degree field of view without distortion in THREE.PerspectiveCamera

Camera arguments in Three.js

This is how a camera is instantiated:
var camera = new THREE.PerspectiveCamera(
VIEW_ANGLE,
ASPECT,
NEAR,
FAR
);
What do these values mean?
I was wondering the same thing so I looked it up, it is a view "frustum".
I'll paste here a code comment I wrote in a recent project because it sums it up nicely IMHO.
// "What the f*** is a frustum?" you ask. Well I did.
// Think about it as a truncated pyramid. The tip is the camera. From a certain
// point "down" the pyramid (the "near plane"), stuff can be seen on-screen.
// After the "base" of the pyramid (the "far plane"), stuff is too far to be
// seen. Stuff outside the pyramid is off-screen too. There is also the "aspect
// ratio" (the rectangle that makes up the pyramid's base, so this value is
// width/height) and the "field of view" (think of it as a lens or something,
// it distorts the pyramid so there's more objects on screen - it is set in
// degrees and 45° is more-or-less a "natural" perspective. The bigger the
// number, the more "perspective" there is).
I found this tutorial very useful for understanding all the camera parameters, and the difference between PerspectiveCamera and OrthographicCamera.
PerspectiveCamera
Fov (Field of view) - This is part of scene that can be seen from the position of the camera. As you probably know, we, humans, have almost 180-degree field of view, while some birds might even have a complete 360-degree field of view. However, for computers, we usually use the field of view between 60 and 90 degrees.
Aspect - The aspect ratio is ratio between the horizontal and vertical size of the area where we render the output. As we usually use the entire window, we will just use that ratio. The aspect ratio determines the difference between the horizontal field of view and the vertical field of view as you can see in the figure on the following page. Ordinary value is window.innerWidth / window.innerHeight.
Near - This property defines a min distance from the camera the Three.js renders the scene. Usually, this is a very small value, e.g. 0.1.
Far - This property defines a max distance we see the scene from the position of the camera. If we set this as too low, a part of our scene might not be rendered; if we set it as too high, in some cases, it might affect the rendering performance. Normal value is between 500 and 2000.
OrthographicCamera
Left (Camera frustum left plane) - You should see this as what is the left border of what will be rendered. If we set this value to -100, you won’t see any objects that are farther to the left.
Right (Camera frustum right plane) - Anything farther to the right won't be rendered.
Top (Camera frustum top plane) - The maximum top position to be rendered.
Bottom (Camera frustum bottom plane) The bottom position to be rendered.
Near (Camera frustum near plane) - From this point on, based on the position of the camera, the scene will be rendered.
Far (Camera frustum far plane) - The furthest point, based on the position of the camera, to which the scene will be rendered.
The following picture should be very illustrative:
The main difference between the two camera modes is that in the OrthographicCamera distance plays no role, so all the elements are of the same size, as you can see in the case of the red and yellow ball.
Finally here is some code you can use to switch from one camera to the other:
this.switchCamera = function(SCENE_WIDTH, SCENE_HEIGHT) {
if (camera instanceof THREE.PerspectiveCamera) {
camera = new THREE.OrthographicCamera( SCENE_WIDTH / - 2, SCENE_WIDTH / 2, SCENE_HEIGHT / 2, SCENE_HEIGHT / - 2, 0.1, 1000 );
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = -1;
camera.lookAt(scene.position);
this.perspective = "Orthographic";
} else {
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = -1;
camera.lookAt(scene.position);
this.perspective = "Perspective";
}
};
Notes:
The function camera.lookAt(scene.position) orients the camera to where the scene is located, so it is visible.
Units in three.js are SI units, so the values of left,right,top,bottom should not assumed to be pixels.
The aspect ratio of the camera's frustum should normally match the canvas' aspect ratio.
SCENE_WIDTH, SCENE_HEIGHT, can be determined through the geometries that are added in the scene. The orthographic frustum could be much larger than the scene but it wouldn't be very parsimonious.
Useful links:
http://www.glprogramming.com/red/chapter03.html
Three.js - Orthographic camera
The first param is FOV means field of view, imagine a camera on a tripod, if you change lens to wide angle you get a higher FOV. Try to imagine a cone coming out from the camera, it can only see objects in that area.
ASPECT means aspect ratio, a widescreen TV is 16/9 and old ones were 4/3, usually just give it the screen width/height or the dims of a DIV you would like three.js to use.
fov: Camera frustum vertical field of view.
aspect: Camera frustum aspect ratio.
near: Camera frustum near plane.
far: Camera frustum far plane.
On these pages there some image for the FOV, NEAR plane, anmd FAR plane.
https://threejsfundamentals.org/threejs/lessons/resources/frustum-3d.svg
https://upload.wikimedia.org/wikipedia/commons/thumb/0/02/ViewFrustum.svg/440px-ViewFrustum.svg.png
https://threejsfundamentals.org/threejs/lessons/threejs-cameras.html
https://en.wikipedia.org/wiki/Viewing_frustum
This is the aspect ratio.
https://en.wikipedia.org/wiki/Aspect_ratio_(image)
This is the official docs.
https://threejs.org/docs/#api/en/cameras/PerspectiveCamera

Categories

Resources