Convert 3d point on sphere to UV coordinate - javascript

I have a 3d point on a sphere and want to convert from that, to a UV point on the sphere's texture.
Could someone point in the right direction for the please? I can take a pure math solution.
Edit:
I currently have this, which does not return the correct UV coordinate.
p is the 3d point on the sphere
mesh.position is the position of the sphere
var x = (p.x-mesh.position.x)/500;
var y = (p.y-mesh.position.y)/500;
var z = (p.z-mesh.position.z)/500;
var u = Math.atan2(x, z) / (2 * Math.PI) + 0.5;
var v = Math.asin(y) / Math.PI + .5;

The Wikipedia about uv-mapping is correct however you need to compute the uv coordinate for each vertex of the mesh. Then you need to transform the uv coordinate to pixel coordinate: Perfect (3D) texture mapping in opengl. Here is an other example: http://www.cse.msu.edu/~cse872/tutorial4.html. You can also try three.js. You also need to physically copy the uv triangle.

I found this wiki article - http://en.wikipedia.org/wiki/UV_mapping - they seem to use a sphere as their example.
Hope it helps.

Related

How to get the y angle between 2 vectors in Three.js?

In Three.js I have 2 3d vectors and I want to find the x-axis and y-axis angle between them.
For the x-axis I found this
toDegrees(atan2(A.z, A.y) - atan2(B.z, B.y))
from
The X angle between two 3D vectors?
which works, but for y-axis, I am trying
toDegrees(atan2(A.z, A.x) - atan2(B.z, B.x))
but it gives me the wrong value. How can I fix this?
Thanks
You can use Vector3.angleTo directly, it will give you the angle in radians, as usual to math functions, here I printing it in degrees (multiplying by 180 degrees/pi rad= 1)
// notice that v1 is pointing to the x-axis direction.
const v1 = new THREE.Vector3(10,0,0);
const v2 = new THREE.Vector3(3,3,0);
const v3 = new THREE.Vector3(0, 50, 23);
// Alngle between v1 and v2
console.log(v1.angleTo(v2)*180/Math.PI)
// The operation is comutative
console.log(v2.angleTo(v1)*180/Math.PI)
// An example at 90 degree
console.log(v1.angleTo(v3)*180/Math.PI)
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
This makes it possible to find angles to any direction, if you want angle to a plane for instance, it is given by ans(a - 90) where a is the angle in degrees to the normal vector of the plane.

How to project only part of a texture to a face threejs?

I want to make portals with threejs by drawing an ellipse and then texture mapping a WebGlRenderTarget to its face. I have that function sort of working, but it tries to stretch the large rectangular buffer from the render target to the ellipse. What I want is to project the texture in its original dimensions onto the ellipse and just cut out anything that doesn't hit the ellipse like so:
Before Projection:
After projection:
How can this be done with threejs?
I've looked into texture coordinates, but don't understand how to use them, and even saw a projection light PR in threejs that might work?
Edit: I also watched a Sebastian Lague video on portals and saw he does this with “screen space coordinates”. Any advice on using those?
Thanks for your help!
Made a codepen available here:
https://codepen.io/cdeep/pen/JjyjOqY
UV mapping lets us specify which parts of the texture correspond to which vertices of the geometry. More details here: https://www.spiria.com/en/blog/desktop-software/understanding-uv-mapping-and-textures/
You could loop through the vertices and set the corresponding UV value.
const vertices = ellipseGeometry.attributes.position.array;
for(let i = 0; i < numPoints; i++) {
const [x, y] = [vertices[3*i], vertices[3*i + 1]];
uvPositions.push(0.5 + x * imageHeight / ((2 * yRadius) * imageWidth));
uvPositions.push(0.5 + y / (2 * yRadius));
}
ellipseGeometry.setAttribute("uv", new THREE.Float32BufferAttribute(uvPositions, 2 ));
UV coordinates increase from (0, 0) to (1, 1) from bottom left to top right.
The above code works because the ellipse is on the x-y plane. Or else, you'll need to get the x,y values in the plane of the ellipse.
More info on texture mapping in three.js here:
https://discoverthreejs.com/book/first-steps/textures-intro/
Edit: Do note that the demo doesn't really look like a portal. For that, you'll need to move the texture based on the camera view which isn't that simple

How can I do a 2D morphing circle in three.js that moves in a liquid way?

I have a mesh which is a circle geometry. I would like to animate it like in this example from two.js, a 2D library:
https://two.js.org/examples/physics.html
For now I look at this example and put the camera on the top of the shape but I'm sure there's a more simple way for my needs: https://threejs.org/examples/#webgl_gpgpu_water
Does anyone know how I can do that?
You simply need to shift the vertices positions according some sin() or cos() value according X and Y coordinates and a incremental phase (time) to animate.
your vertex shader could include something like this, where phase is incrementing with time (typically, a clock).
glPosition.x = vertex.x + sin((phase*frequency) + vertex.y) * amplitude;
glPosition.y = vertex.y + sin((phase*frequency) + vertex.x) * amplitude;
The basic concept is here, but you have to adapt the components yourself by testing the result. You probably should adjust frequency, amplitude, adding some more factors to add asymetry and randomness.

Get new point Coordinate by Current Point and Angle and Distance in arcgis js

I'm developing a Web GIS Application using arcgis javascript Api and I need to drawing line from point1 by distance and angle. first step calculate point2 by this formula
point2X = point1.x + distance * Math.cos(angle)
point2Y = point1.y + distance * Math.sin(angle)
Distance unit 'Meter' and angle in 'radians'
Second Step: Draw line with point1 and point2. If the input distance is 1000 meters, the drawn line shows the length as 866 meters, when measured with arcgis measurement tool. Is coordinate system in this formula an impact?
Function:
function GetNewPoint(x, y, distance, angle) {
var alpha = ToRadian(angle);
var cos = Math.cos(alpha);
var sin = Math.sin(alpha);
var x2 = (cos * distance)+x ;
var y2 = (sin * distance)+y ;
return esri.geometry.xyToLngLat(x2, y2);
}
function ToRadian(angle) {
return (Math.PI / 180) * angle;
}
The map projection (the thing that is defined by your coordinate system) will absolutely impact the result of the measure.
"Every map projection causes distortion of shapes, areas, directions, and/or distances. Some projections such as Robinson or Winkel Tripel attempt to minimize distortion across the world through some compromise of all those factors. Other projections (such as UTM and State Plane) are designed for focused areas of the globe in order to keep the distortion minimal."
source: https://blogs.esri.com/esri/arcgis/2010/03/05/measuring-distances-and-areas-when-your-map-uses-the-mercator-projection/
Fortunately, the Web API that you are using has some methods to re-project your data before you do any measurement.
If you are interested in re-project a specific feature of your map, you can use something like this:
var sr = new esri.SpatialReference({wkid:32610})
// assuming you already referenced geometryService
geometryService.project([graphic], sr, function(projectedGraphic){
geometryService.areasAndLengths(projectedGraphic, function(result){
var perimeter = result.lengths[0];
var area = result.areas[0];
});
});
The previous example assumes the usage of a geometry service (you can find this at ArcGIS Online or at your ArcGIS for Server Instance) and is remotely processed.
You can find more information about Geometry Service at this link.
Let me know if this information helps to solve your problem.
Check this website he put all the equation you need to work with coordiantes and HERE is my solution to get the coordiantes of the new point.

apply heightmap to SphereGeometry in three.js

[EDIT: see this jsfiddle for a live example plus accompanying code]
Using three.js I'm trying to render out some celestial bodies with prominent features.
Unfortunately no examples are provided on how to apply spherical heightmaps with threejs but they do have an example where a heightmap is applied to a plane.
I took said example and modified it to use a SphereGeometry(); instead of a PlaneGeometry();
Obviously the geometry of a sphere is critically different from that of a plane, and when rendering out the results the sphere shows as a flat piece of texture.
The heightmap code for planes:
var plane = new THREE.PlaneGeometry( 2000, 2000, quality - 1, quality - 1 );
plane.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) );
for ( var i = 0, l = plane.vertices.length; i < l; i ++ ) {
var x = i % quality, y = ~~ ( i / quality );
plane.vertices[ i ].y = data[ ( x * step ) + ( y * step ) * 1024 ] * 2 - 128;
}
Now I'm guessing the solution is relatively simple: instead of mapping to the plane's 2d coordinate in the for loop, it has to find the surface coordinate of the sphere in 3d space. Unfortunately I'm not really a pro at 3d maths so I'm pretty much stuck at this point.
An example of the heightmap applied to the sphere and all code is put together in this jsfiddle. An updated jsfiddle shows an altered sphere but with random data instead of the height map data.
I know for a fact you can distort the sphere's 3d points to generate these surface details, but I'd like to do so using a heightmap. This JSFiddle is as far as I got- it'll randomly alter points to give a rocky appearance to the sphere, but obviously doesnt look very natural.
EDIT: The following is the logic required I wish to implement that maps heightmap data to a sphere.
In order to map the data to a sphere, we will need to map coordinates from a simple spherical coordinate system (longitude φ, latitude θ, radius r) to Cartesian coordinates (x, y, z). Just as in normal height-mapping the data value at (x, y) is mapped to z, we will map the value at (φ, θ) to r. This transformation comes down to:
x = r × cos φ × sin θ
y = r × sin φ × sin θ
z = r × cos θ
r = Rdefault + Rscale × d(φ, θ)
The parameters Rdefault and Rscale can be used to control the size of the sphere and the height map on it.
Uses vector3 to move each vertices:
var vector = new THREE.Vector3()
vector.set(geometry.vertices[i].x, geometry.vertices[i].y, geometry.vertices[i].z);
vector.setLength(h);
geometry.vertices[i].x = vector.x;
geometry.vertices[i].y = vector.y;
geometry.vertices[i].z = vector.z;
Example: http://jsfiddle.net/damienlabat/b3or4up3/
If you want to apply a 2D map onto the 3D sphere surface, you will need to use UVs of the sphere. Fortunately, UVs come with THREE.SphereGeometry by default.
The UVs are stored per-face though, so you will need to iterate through the faces array.
For each face in the geometry:
Read the corresponding UV value in the FaceVertexUvs array for each associated vertex.
Read the height map value using that UV location.
Shift the vertex along the vertex normal by that value. The faces array gives the vertex index, which you can use to index into the vertices array to get/set the vertex position.
After this is all done, set verticesNeedUpdate to true to update the vertices.

Categories