Retrieve center point the viewer is looking at from view/perspective matrix - gl-matrix

I use the glMatrix's method: mat4.lookAt(out, eye, center, up) to set a camera view when a WebGL model is rendering.
After the model is rendered, I need to retrieve the center attribute from view/perspective matrix. I know how to retrieve the eye attribute, but I have no idea how to get the center one. How can I do that?
This is the mat4.lookAt method I use:
http://glmatrix.net/docs/mat4.js.html#line1366

you can't get the actual center since it was normalized. You can get a center position that will generate the same look at. I think it would be this.
camera = mat4.inverse(mat4.create(), view);
up = camera.slice(4, 7);
eye = camera.slice(12, 15);
negativeZ = camera.slice(8, 11);
center = vec3.scaleAndAdd(vec3.create(), eye, negativeZ, -1);
That center will be one unit in front of the eye. Change the -1 to -1 * units to make it further away from the eye. In other words -2 would be two units in front, -3 would be 3 units in front etc.
Here's a test
const eye = [1, 2, 3];
const center = [4, 5, 6];
const up = [0, 1, 0];
const view = mat4.lookAt(mat4.create(), eye, center, up);
const camera = mat4.invert(mat4.create(), view);
const newUp = camera.slice(4, 7);
const newEye = camera.slice(12, 15);
const negativeZ = camera.slice(8, 11);
const newCenter = vec3.scaleAndAdd(vec3.create(), newEye, negativeZ, -1);
const newView = mat4.lookAt(mat4.create(), newEye, newCenter, newUp);
// show difference between view and newView
console.log(view.map((v, i) => (v - newView[i]).toFixed(6)));
<script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.4.0/gl-matrix-min.js"></script>
This article explains the parts of a camera matrix and what a view matrix is.

Related

How to make hexagon shape image in react native?

I want to make hexagon shape image like as below image but didn't find any perticular way to make it customized.
Here is the image:
Suggest any library to make it possible in react-native.
So I thought that the usage of a hexagon path was so common that finding an existing one online would be a simple task, but searches proved to be fruitless so I decided to make a function that would make a regular hexagon Skia Path. I found a really cool quora answer on how to get the points any size hexagon(regular hexagon), and then I just connect the points:
import {Skia} from "#shopify/react-native-skia";
function makeHexagonPath(size, offset) {
const path = Skia.Path.Make();
let [xOffset, yOffset] = offset || [0, 0];
if (!size) size = 10;
// https://www.quora.com/How-can-you-find-the-coordinates-in-a-hexagon
const halfed = size / 2;
const sqrt = (Math.sqrt(3) * size) / 2;
const points = [
[size, 0], //a
[halfed, sqrt], //b
[-halfed, sqrt], //c
[-size, 0], //d
[-halfed, -sqrt], //e
[halfed, -sqrt], //f
].map(([x, y]) => [x + xOffset, y + yOffset]);
console.log(points);
path.moveTo(...points[0]);
points.forEach((point) => path.lineTo(...point));
path.close();
return path;
}
With the makeHexagonPath function you draw a clipping of any size and use the offset parameter to move the hexagon to desired location:
const imageSize = 200
export default function ClipImage({imageSrc}) {
const image = useImage(imageSrc);
const hexagonSize = imageSize / 2;
const path = makeHexagonPath(hexagonSize, [hexagonSize, hexagonSize]);
if (!image) return null;
return (
<Group clip={path}>
/*<Path path={path} color="lightblue" />*/
<Image
image={image}
fit="cover"
x={0}
y={0}
width={imageSize}
height={imageSize}
/>
</Group>
);
}
I would post an expo snack demoing it but react-native-skia wasnt working for me on expo but in the default react-native environment it worked like a charm

Three.js, Camera rotation around a point

I'm trying to make a camera rotation and zoom around a point.
I don't want to use THREE.TrackBallControls because as i see, it only modify the fov when zooming, it is not what i want.
I'm using this simple equation : http://en.wikipedia.org/wiki/Sphere#Equations_in. To compute a point on the sphere, this point will be the position of the camera.
In three.js
var point = new THREE.Vector3(
radius * Math.cos(theta) * Math.sin(phi),
radius * Math.sin(theta) * Math.sin(phi),
radius * Math.cos(phi)
);
point.add(center);
To manipulate it, i use :
left mouse, for rotation : x coord === theta and y coord === phi
middle mouse, for zooming : zoom in/out === radius
It doesn't work well, especially for 'phi' rotation, maybe because it's define between 0 and PI.
Maybe there is a better solution using Quaternion.Slerp ?
edit :
My camera :
aspectRatio = container.offsetWidth / container.offsetHeight;
camera = new THREE.OrthographicCamera( -aspectRatio * viewSize / 2, aspectRatio * viewSize / 2, viewSize / 2, -viewSize / 2, -10, 10 );
camera.position.x = 0.004;
camera.position.y = 0.004;
camera.position.z = 0.004;
camera.lookAt(new THREE.Vector3(0, 0, 0))
scene.add(camera);
My OrbitControls :
controls = new THREE.OrbitControls ( camera );
controls.rotateSpeed = 1.0;
controls.zoomSpeed = 1.2;
controls.keyPanSpeed = 0.8;
controls.noZoom = false;
controls.noPan = false;
when using left mouse (rotation) the camera.position change.
when using middle mouse (zoom) the camera.position is still the same.
check made in the render function :
function render() {
// update camera controls
controls.update();
console.log(camera.position);
// actually render the scene
renderer.render( scene, camera );
}

DirectXMath Unproject on the wrong axis

EDIT: Solved the issue, see my own answer
Recently I've been working on a 3D world editor that will be using picking to raise or lower terrain. I'm using camera unprojection and ray casting to find the world position of the mouse screen coordinates.
However, it seems like the ray is on the wrong axis. As I remember, the ray that is supposed to come out of unproject should be coming straight from the camera.
Here's an example of what it currently looks like.
My question is, why is the ray over the Y-axis when it's supposed to be over the Z-axis?
XMFLOAT3 D3D11Camera::Unproject(const float& px, const float& py, const float& pz)
{
const XMFLOAT2& res = D3D11RenderSettings::Instance()->resolution();
XMVECTOR coords = XMVector3Unproject(XMVectorSet(px, res.y - py, pz, 0.0f), 0.0f, 0.0f, res.x, res.y, near_plane_, far_plane_, projection_, view_, XMMatrixIdentity());
XMFLOAT3 to_ret;
XMStoreFloat3(&to_ret, coords);
return to_ret;
}
This is the unprojection code..
And this is how I'm using it
projectRay: function()
{
var p = Mouse.position(MousePosition.Relative);
p.x = (p.x + RenderSettings.resolution().w / 2);
p.y = (p.y + RenderSettings.resolution().h / 2);
var unprojA = this._camera.unproject(p.x, p.y, 0);
var unprojB = this._camera.unproject(p.x, p.y, 1);
var dir = Vector3D.normalise(Vector3D.sub(unprojB, unprojA));
var ray = Ray.construct(unprojA, dir);
var p1 = ray.origin;
var p2 = Vector3D.add(ray.origin, Vector3D.mul(ray.direction, 1000));
RenderTargets.ui.drawLine(p1.x, p1.y, p1.z, 1, 0, 0, p2.x, p2.y, p2.z, 1, 0, 0);
return ray;
}
Cheers!
Stupidity aside, I'm working with both an inverted Y-axis coordinate system and a default -- non inverted -- one. It seemed like it was a ray oriented vertically, but in fact it was a ray that was oriented in the direction of '/' while it was supposed to be oriented like '\'. Multiplying the Y component of the result by -1 solved the issue.

Rotating camera around the X-axis (three.js)

I am trying to rotate the camera around to X-axis of the scene.
At this point my code is like this:
rotation += 0.05;
camera.position.y = Math.sin(rotation) * 500;
camera.position.z = Math.cos(rotation) * 500;
This makes the camera move around but during the rotation something weird happens and either the camera flips, or it skips some part of the imaginary circle it's following.
You have only provided a snippet of code, so I have to make some assumptions about what you are doing.
This code:
rotation += 0.05;
camera.position.x = 0;
camera.position.y = Math.sin(rotation) * 500;
camera.position.z = Math.cos(rotation) * 500;
camera.lookAt( scene.position ); // the origin
will cause the "flipping" you refer to because the camera is trying to remain "right side up", and it will quickly change orientation as it passes over the "north pole."
If you offset the camera's x-coordinate like so,
camera.position.x = 200;
the camera behavior will appear more natural to you.
Three.js tries to keep the camera facing up. When you pass 0 along the z-axis, it'll "fix" the camera's rotation. You can just check and reset the camera's angle manually.
camera.lookAt( scene.position ); // the origin
if (camera.position.z < 0) {
camera.rotation.z = 0;
}
I'm sure this is not the best solution, but if anyone else runs across this question while playing with three.js (like I just did), it'll give one step further.
This works for me, I hope it helps.
Rotating around X-Axis:
var x_axis = new THREE.Vector3( 1, 0, 0 );
var quaternion = new THREE.Quaternion;
camera.position.applyQuaternion(quaternion.setFromAxisAngle(x_axis, rotation_speed));
camera.up.applyQuaternion(quaternion.setFromAxisAngle(x_axis, rotation_speed));
Rotating around Y-Axis:
var y_axis = new THREE.Vector3( 0, 1, 0 );
camera.position.applyQuaternion(quaternion.setFromAxisAngle(y_axis, angle));
Rotating around Z-Axis:
var z_axis = new THREE.Vector3( 0, 0, 1 );
camera.up.applyQuaternion(quaternion.setFromAxisAngle(z_axis, angle));
I wanted to move my camera to a new location while having the camera look at a particular object, and this is what I came up with [make sure to load tween.js]:
/**
* Helper to move camera
* #param loc Vec3 - where to move the camera; has x, y, z attrs
* #param lookAt Vec3 - where the camera should look; has x, y, z attrs
* #param duration int - duration of transition in ms
**/
function flyTo(loc, lookAt, duration) {
// Use initial camera quaternion as the slerp starting point
var startQuaternion = camera.quaternion.clone();
// Use dummy camera focused on target as the slerp ending point
var dummyCamera = camera.clone();
dummyCamera.position.set(loc.x, loc.y, loc.z);
// set the dummy camera quaternion
var rotObjectMatrix = new THREE.Matrix4();
rotObjectMatrix.makeRotationFromQuaternion(startQuaternion);
dummyCamera.quaternion.setFromRotationMatrix(rotObjectMatrix);
dummyCamera.up.set(camera)
console.log(camera.quaternion, dummyCamera.quaternion);
// create dummy controls to avoid mutating main controls
var dummyControls = new THREE.TrackballControls(dummyCamera);
dummyControls.target.set(loc.x, loc.y, loc.z);
dummyControls.update();
// Animate between the start and end quaternions
new TWEEN.Tween(camera.position)
.to(loc, duration)
.onUpdate(function(timestamp) {
// Slerp the camera quaternion for smooth transition.
// `timestamp` is the eased time value from the tween.
THREE.Quaternion.slerp(startQuaternion, dummyCamera.quaternion, camera.quaternion, timestamp);
camera.lookAt(lookAt);
})
.onComplete(function() {
controls.target = new THREE.Vector3(scene.children[1].position-0.001);
camera.lookAt(lookAt);
}).start();
}
Example usage:
var pos = {
x: -4.3,
y: 1.7,
z: 7.3,
};
var lookAt = scene.children[1].position;
flyTo(pos, lookAt, 60000);
Then in your update()/render() function, call TWEEN.update();
Full example

Raphael -- How to fit the paper size to the browser's window size?

I want to change the paper(objects base) size of Raphael to fit the window resizing. [ using Firefox_13.0, Raphael_2.1.0, WindowsXP ]
If it is available, I would like to fit full-screen-mode.
==================================================
(steps)
I created the paper : paper = Raphael(0, 50, 800, 600); // initial width and height are 800 and 600.
I placed objects on the paper.
The window size of browser is checked by windowW = window.innerWidth and winnowH = window.innerHeight (on Firefox).
Scaling value is calculated by sv = windowW/800;
And scaling the paper by paper.scale(sv, sv);
==================================================
(the script)
window.onload = function () {
paper = Raphael(0, 50, 800, 600);
var background = paper.rect(0, 0, 800, 600).attr({fill:'#669999'});
// placing the objects
var circle = ...;
var rect = ...;
var ellipse = ...;
winowW = window.innerWidth;
winowH = window.innerHeight;
sv = winowW/800.
paper.scale(sv, sv);
}
==================================================
(result)
Though circle.scale(sv), rect.scale(sv, sv) and ellipse.scale(sv, sv) are valid, paper.scale(sv, sv) and background.scale(sv, sv) are not.
Why this case is happen ? I can get the window size by window.onresize = function() {...} on real-time. If there are better methods, please tell me.
Thanks,
I've succeeded by following two points:
1) "paper" itself is not manipulative object. I think we should look it as billboard.
2) use st = paper.set() and put the objects(circle, rect, ...) in it. And use st.scale(sv, sv, 0, 0);
* third and fourth parameter (0, 0) are very impotent.
(caution)
Serial resizing operation is not good for the function "scale()". Because each of resizing coefficient is piled as the
power of a number. So when one have done 1.1 times resizing operation 5 times, the scale will be 1.1^5.
Use setViewBox()
It should do the work
http://raphaeljs.com/reference.html#Paper.setViewBox