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
Related
I am drawing a hexagonal grid using javascript and svg. The grid needs to have a fixed width (let's say, of 1000px). The dimensions of the grid can differ, but I have that information (the columns and rows). I have written a function that given a hexagons 'bounding box' width (the height is a factor 0.8660254 of the width), will calculate all 6 points and draw a polygon between them. I am staggering the x coordinate such that the polygons neatly connect.
However, the part I am stuck on currently is: How do I figure out the width of the polygons such that they take up the most available space on the canvas? I cannot simply do width of the canvas / number of columns because that doesn't take into account the staggering (see the image below)
How can I figure out how to stretch the hexagons such that they all fit and take up as much space as they can?
If you have C columns and hexagon side size (unknown yet) is x, we can write inequality:
x/2 + C*x*3/2 <= width
x*(1+3*C)>=2*width
x <= 2*width / (1+3*C)
So calculate the right part and get floored integer (if you need integer side)
For height with R rows:
x*sqrt(3)/2 + R*x*sqrt(3)/2 <= height
x <= 2*height / (sqrt(3) + R*sqrt(3))
Get min value from calculated sizes to fit both width and height
You need some trigonometry
Each Hexigon neighbor is at an increment of 60 degrees (pi/3) angle. Use cos (pi/3) * radius for the x location adjustment, and +/- sin (pi/3) * radius for height adjustment.
I am new to css and learning different type of css styles. I want to learn how the effect used in official MongoDb website. The effect which tracks the mouse position and transforms the boxes. I know how to do the transform in css. But, how can it be done with the mouse position. Thanks for the help.
General overview of how to do it:
Register a mousemove-handler and track your mouse-screen location (see link)
translate mouse screenlocation, to mouse location relative to rectangle:
e.target in mousemove event gives you the rectangle (or some descendent which allows you to get to the rectangle.
given the target element get it's position (top + left using getBoundingClientRect) as well as width and height. These should be easy to lookup
Notice that the mouse at the center of the rectangle doesn't rotate the rectangle. Only when moving to the edges, the rotation starts to get going. This rotational rate-of-change seems to be linear. So:
determine the max rotation that seems nice to have in degrees. Simply test with different numbers in the chrome dev tools or similar: transform: rotateY(0.01deg) rotateX(0.01deg); Say you want to have a max rotation of 25 degrees.
say the rectangle is 100px in width. It's clear to see that each pixel movement from the center to the edge (50 px in total) adds 0.5 degree to the rotation due to the linear rate of change: 25 deg / 50px. So for example moving 20px to the left of the center translates to rotateY(10deg);. Moving 20px to the right results in the mirror rotation (rotateY(-10deg);). NOTE: the positive and negative may need to be flipped.
similarly, moving along the Y-axis changes the rotateX-property.
Once calculated, set the css-property and you're done
I believe this must be done with Javascript. The general idea is when the mouse enter/move on the element, you compare it's coordinate with the position and width/height of the element to decide the rotation values. When the mouse leave the element, you reset the values of the rotation back to normal.
You can get the coordinate of the mouse from event by using:
const mouseX = event.clientX; // Get the horizontal coordinate
const mouseY = event.clientY; // Get the vertical coordinate
And the position of the element:
const eleLoc = event.target.getBoundingClientRect();
From there you calculate the center and the width/height of the element:
const centerX = (eleLoc.right + eleLoc.left) / 2
const centerY = (eleLoc.bottom + eleLoc.top) / 2
const halfWidth = (eleLoc.right - eleLoc.left) / 2
const halfHeight = (eleLoc.bottom- eleLoc.top) / 2
Then you calculate the distance between the mouse and the center in percent. In the center, the distance is 0, at the border, it's 1 (or -1).
const percentX = (mouseX - centerX) / halfWidth
const percentY = (mouseY - centerY) / halfHeight
Now you only need to rotate X/Y based on the distance percent:
const degX = percentX * maxDegX
const defY = percentY * maxDegY
event.target.style.transform = `perspective(${yourPerspective}px) rotateX(${degX}deg) rotateY(${degY}deg)`
Remember to reset the transform when your mouse move out.
There are some libraries for this, ie: tilt.js
Given initial coordinates (the left and top css properties) of an absolutely positioned element on screen, and an angle of movement, how can I find out the values I should feed to transform: translate to animate the element? (The element would eventually fall off-screen, so one of the final coords will be 0 or window.innerWidth or window.innerHeight.)
For example, starting from left: 0 and top: 0, and given an angle of 90°, the destination point would be at left equal to window.innerWidth and top equal to 0. If the angle is 135°, the element would end up in the bottom right corner, etc. How can I calculate this for any angle?
(transform: translate takes deltas as parameters, not absolute positions; either is fine)
It is actually fairly simple trig. Based on the example you have given:
Your known quantities are initial coords { x: 0, y: 0 } and { angle: 90 /* in degrees*/ }
Find x-distance between initial x-coord and { window.innerWidth if angle is between 90-270 or 0 if angle between 0-90 & 270-360 }
Find the cosine of angle and multiply it with x-distance
Find y-distance between initial y-coord and { window.innerHeight if angle between 180-360 or 0 if angle between 0-180 }
Find the sine of angle and multiply it with y-distance
Add the initial x-coord with result of cosine * x-distance. This gives new x-coordinate
Add the initial y-coord with result of sine * y-distance. This gives new y-coordinate
Add some buffer to xnew and ynew so they fall off screen
For moving the element, you no longer require transform. You can simply add a transition CSS property and define new coords with new class added to that element. JSFiddle Demo
HTH
I set position and fov of my perspective camera manually in THREE.JS. It behaves as expected. However, once I try to interact with the scene later on, through the TrackBall Controls, it just displays a black screen, no errors.
JS Fiddle
Relevant code:
var bbox = new THREE.Box3().setFromObject(scene);
var center = bbox.getCenter();
var size = bbox.getSize();
// update some controls properties
controls.target.set(center.x, center.y, center.z);
// position the camera on the y axis
camera.position.set(center.x, center.y - size.y, center.z);
// fit FOV
var dist = size.y / 2;
var fov = 2 * Math.atan( size.z / ( 2 * dist ) ) * ( 180 / Math.PI );
camera.fov = fov;
camera.updateProjectionMatrix();
Which step am I missing in order to be able to then interact properly with the scene
Thanks
==== EDITS
Working fiddle based on accepted answer: Fiddle
I think that it is not possible to correctly project a case when the camera "up" position is parallel to the vector defined by the camera position and target. The camera up position should specify how to orient the view in a plane orthogonal to the vector from camera position to the target but if the component of camera.up along that plane is zero it cannot work. In your code:
the camera "up" position is the default (0,1,0)
the vector from camera position to camera target is (0,size.y,0)
The simplest fix is probably to specify a different camera "up", i.e.
camera.up = new THREE.Vector3(0,0,1.);
or any other vector not parallel to the y direction.
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