I'm sure there is something simple, yet critical missing in my three.js fundamentals.
I have an eyeball always looking at the user's mouse cursor. I have it working based on a post by mr. doob, but I'm not exactly sure why/how it's working. Can someone please explain to me the math behind converting the screen coords to a scene space position. Below is my working example. I understand normalizing the mouse position, but then why do we (* 2-1), and -(* 2 + 1)?
window.addEventListener('mousemove', function(e){
var mouse3D = new THREE.Vector3(
( event.clientX / window.innerWidth ) * 2 - 1,
- ( event.clientY / window.innerHeight ) * 2 + 1,
0.5 );
pupil.lookAt(mouse3D);
})
TIA for your explanations! I really appreciate it.
The default 3D space runs from -1 to 1 along X, Y, and Z, and is centered at (0,0,0).
That code:
Converts X to the range [0,1], meaning the left edge corresponds to 0 and the right edge corresponds to 1 (( event.clientX / window.innerWidth ))
Then scales X to [0,2] (* 2)
Then shifts it to the range [-1,1] (- 1)
Converts Y to the range [-1,0], meaning the top edge corresponds to 0 and the bottom edge corresponds to -1 (-( event.clientY / window.innerHeight ))
Then scales Y to [-2,0] (* 2)
Then shifts it to the range [-1,1] (+ 1)
Uses a constant Z of 0.5 (within the range [-1,1]), since this is a 2D function.
Related
I was doing one of the examples on the p5.js website - https://p5js.org/examples/form-regular-polygon.html. I got really confused by the way rotate function worked in that code . IN the below function if I just pass rotate(frameCount) , in the browser it shows me rotating two triangles intersected within forming a star , but as soon as I divide the frameCount it disappears. Also the equation used in the code - can some one give the mathematical intuition on how we reached to this point.
let sx = x + cos(a) * radius;
let sy = y + sin(a) * radius;
push();
translate(width * 0.2, height * 0.5);
rotate(frameCount / 50);
polygon(0,0,82,3);
pop();
Regarding "two triangles intersected within forming a star":
By default, the rotate function takes radians. When you do rotate(frameCount), you are increasing the angle by 1 radian at each frame. One radian equals about 57 degrees, so your triangle would rotate about 57 degrees at each frame. At frame 3, the triangle would have rotated about 120 degrees, and it would roughly overlap with the triangle at frame 1. Similarly, the triangle at frame 4 would roughly overlap with the triangle at frame 2.
The "two triangles" you are seeing is just two groups of triangles, one group being triangles at frame 1, 3, 5... and another group being triangles at frame 2, 4, 6...
That is why you should divide frameCount by some number if you would like to obtain a rather continuous rotation. Alternatively, you could also set angleMode to DEGREES. In that case, you don't have to divide frameCount anymore because at each frame the triangle would only rotate 1 degree instead of 1 radian.
Regarding the math formula:
In fact, the function used in that example should be called regularPolygon instead of polygon because it only draws regular polygons.
Now, how do you draw a regular polygon? You know the distance from each vertex to the center is a constant number. In this example, that number is the radius variable. And you know if you use polar coordinates with the center of the polygon as the origin point, the angle difference between every two adjacent vertices is also a constant number. In this example, that number is the angle variable.
More precisely, the polar coordinates of the vertices should take the form of:
v1 = (radius, 0)
v2 = (radius, angle)
v3 = (radius, angle*2)
...
Convert them to cartesian coordinates, you would obtain something like:
v1 = (cos(0) * radius, sin(0) * radius)
v2 = (cos(angle) * radius, sin(angle) * radius)
v3 = (cos(angle*2) * radius, sin(angle*2) * radius)
...
But what if the center of the polygon is not the origin point, but point (x, y), as in the example? Now the cartesian coordinates of the vertices become:
v1 = (x + cos(0) * radius, y + sin(0) * radius)
v2 = (x + cos(angle) * radius, y + sin(angle) * radius)
v3 = (x + cos(angle*2) * radius, y + sin(angle*2) * radius)
So when you do:
for (let a = 0; a < TWO_PI; a += angle) {
let sx = x + cos(a) * radius;
let sy = y + sin(a) * radius;
vertex(sx, sy);
}
You are really drawing the vertices v1, v2, v3....
How can I calculate y in this curve ? t is the variable. Origin is (0|0) of course.
the tangents at t=0, t=0,5 and t=1 must be perfectly horizontal (incline = 0)
only basic mathematical operators are available (Java / Actionscript 3)
I have to calculate this a few hundred times each frame in Actionscript 3. So calculation needs good performance. Right now I'm actually failing at correctness of calculation (I'm not a mathematician).
Not sure about performance, but
-0.5 * cos(x * 2pi) + 0.5
AS3:
y = -0.5 * Math.cos(x * 2 * Math.PI) + 0.5;
seems to be the curve you are looking for.
You can view or edit the curve here:
wolfram alfa curve
The function suggested by bjornson (-0.5*cos(x) + 0.5) looks good.
One idea to improve performance is that you at the start of your application create a table of the values of that function at different times.
If you use fix timesteps, then the table is all you'll need. If you have variable time steps, then you can just do linear interpolation between the two closest times to the time you're calculating.
y(t) = 16 * t * t * (t - 1) * (t - 1)
I reckon that one satisfies your requirements
I tried my own way and I came up with a polynomial:
y = 16 * (t - 0.5)^4 - 8 * (t - 0.5)^2 + 1
y = 16 * Math.pow((t - 0.5), 4) - 8 * Math.pow((t - 0.5), 2) + 1;
// forgot to shift the curve 0.5 to the right, corrected
I want to understand how ray projection works. Almost where ever I see, I get a code like this:
new THREE.Vector3(mouseX, mouseY, 0.5);
I'm confused about the 0.5 in the z position. As per my understanding we are projecting on to z=1 plane (not z=0.5 plane). So shouldn't we be using it like this instead?
new THREE.Vector3(mouseX, mouseY, 1.0);
The pattern often used is like this:
var vector = new THREE.Vector3(
( event.clientX / window.innerWidth ) * 2 - 1,
- ( event.clientY / window.innerHeight ) * 2 + 1,
0.5,
);
This is a point in Normalized Device Coordinate (NDC) Space.
The function
projector.unprojectVector( vector, camera );
is mapping from NDC space to world space.
The value 0.5 for vector.z can be set to any value between -1 and 1.
Why? Because these points are all on a line parallel to the z-axis in NDC space, and will all map to the same ray emanating from the camera in world space.
Setting z = -1 will map to a point on the near plane; z = 1 the far plane.
So the short answer is, it doesn't matter what the value of z is, as long as it is between -1 and 1. For numerical reasons, we stay away from the endpoints, and 0.5 is often used.
I am aware that there are other solutions to this problem, but I am learning and for that purpose would like to understand why my algorithm doesn't work
Here is how my solution works:
It gets the coordinates for the 4 vertices of each rectangle, translates them so they are relative to 0, 0 rather than the rectangles' origins, and rotates them respectively using these formulas:
rotatedX = unrotatedX * cos( radiansOfCounterClockwiseRotation ) -
unrotatedY * sin( radians );
and
rotatedY = unrotatedX * sin( radians ) + y * cos( radians );
and translates them so they are relative to their rectangles' origins
Then it calculates x and y values of the axis to compare separation on by subtracting the upper left, and lower right vertices' coordinates from those of the upper right vertice, for a total of 4 axis (1 for each pair of parallel edges of the 2 rectangles)
Then it calculates an x value for each of the rotated vertices, which lies on the axis, using this formula:
x = -( -( axis.x / axis.y ) * vertice.x - vertice.y ) /
( axis[i].y / axis[i].x + axis[i].x / axis[i].y );
which is derived from getting the point of intersection between the axis line and the line perpendicular to the axis that passes through the vertice
It compares these values for each axis and checks whether:
maxXValueForRect0 >= minXValueForRect1 AND minXValueForRect0 <= maxXValueForRect1;
if that is true for every axis, then there is a collision
However, during debugging I discovered that the min x values area always lower than the max x values, regardless of positions and sizes of the rectangles
Can anyone tell me what is wrong here?
This works perfectly and I made an intensely minor error in my code itself that caused both groups of vertices to be translated relative to the first rectangle after their rotation. So the logic presented here is solid and will work provided you don't make a silly mistake like I did :D
I'm trying to figure out an algorithm for finding a random point a set distance away from a base point. So for example:
This could just be basic maths and my brain not working yet (forgive me, haven't had my coffee yet :) ), but I've been trying to work this out on paper and I'm not getting anywhere.
coordinate of point on circle with radius R and center (xc, yc):
x = xc + R*cos(a);
y = yc + R*sin(a);
changing value of angle a from 0 to 2*PI you can find any point on circumference.
Use the angle from the verticle as your random input.
Pseudocode:
angle = rand(0,1)
x = cos(angle * 2 * pi) * Radius + x_centre
y = sin(angle * 2 * pi) * Radius + y_centre
Basic Pythagoras.
Pick random number between 0 and 50 and solve h^2 = a^2 + b^2
Add a few random descisions on direction.