Reputation: 16841
In a previous question I was looking to map a stereographic projection onto a sphere for the sake of live-streaming a virtual reality event.
I ultimately learned quite a bit about UV mapping and was able to construct a very accurate mapping that looks incredible. However there's one thing I don't like about this mapping method: there's a hack where the bottom of the sphere has to map to "nothing", so I map it to a corner of the texture.
In an effort to improve upon this solution, I tried creating only a partial sphere by adjusting the theta length per the Three.JS documentation on SphereGeometry.
While I got the shape of the sphere right, I noticed something odd about the UV mapping:
var fov = 270;
var geometry = new THREE.SphereGeometry(
1, // Radius
50, // Horizontal segments
50, // Vertical segments
0, // Phi start
2 * Math.PI, // Phi length
Math.acos((360 - fov) * Math.PI / 180 / 2), // Theta start
Math.PI - Math.acos((360 - fov) * Math.PI / 180 / 2) // Theta length
);
var minX, minY, minZ, maxX, maxY, maxZ;
var faceVertexUvs = geometry.faceVertexUvs[0];
for ( var i = 0; i < faceVertexUvs.length; i++ ) {
var face = geometry.faces[i];
for ( var j = 0; j < 3; j ++ ) {
var x = face.vertexNormals[j].x;
var y = face.vertexNormals[j].y;
var z = face.vertexNormals[j].z;
// Capture the upper and lower bounds for all points
if (!minX || x < minX) minX = x;
if (!maxX || x > maxX) maxX = x;
if (!minY || y < minY) minY = y;
if (!maxY || y > maxX) maxY = y;
if (!minZ || z < minZ) minZ = z;
if (!maxZ || z > maxZ) maxZ = z;
}
}
console.log("minX: " + minX + ", maxX: " + maxX);
console.log("minY: " + minY + ", maxY: " + maxY);
console.log("minZ: " + minZ + ", maxZ: " + maxZ);
I learned previously when performing UV mapping that the x
, y
, and z
values range from -1
to 1
- regardless of the actual size of the mesh. If the sphere had a radius of 1 or a radius of 100, an x
value of 1 means "the far right of the sphere" and a y
value of 1 means "the top of the sphere". However when I have an incomplete sphere like this (using thetaStart
and thetaLength
to cut a hole in the top of the sphere) suddenly maxY
was equal to about 0.7854.
Why is it that this mesh ends at 0.7854 instead of scaling from -1 to 1? I had hoped that by changing the shape of the sphere I could simplify my UV mapping logic (removing the scaledY
term from my previous question that I linked) however altering the shape of the sphere seems to have had no affect on the UV map.
Is there a way to tell Three.JS that this partial sphere is the full shape and its coordinates should range from -1 to 1?
Upvotes: 5
Views: 1710
Reputation: 28497
I believe you're confusing Normals with UVs in your description and code snippet. You're reading the value of Normals above in these lines:
var x = face.vertexNormals[j].x;
var y = face.vertexNormals[j].y;
var z = face.vertexNormals[j].z;
With your SphereGeometry attributes, the min and max y normals match the expected result:
What you want to do is look at the min and max UV values. I've updated the code to get UV values:
var fov = 270;
var geometry:THREE.SphereGeometry = new THREE.SphereGeometry(
2, // Radius
50, // Horizontal segments
50, // Vertical segments
0, // Phi start
2 * Math.PI, // Phi length
Math.acos((360 - fov) * Math.PI / 180 / 2), // Theta start
Math.PI - Math.acos((360 - fov) * Math.PI / 180 / 2) // Theta length
);
var minX, minY, minZ, maxX, maxY, maxZ;
var faceVertexUvs = geometry.faceVertexUvs[0];
for ( var i = 0; i < faceVertexUvs.length; i++ ) {
var vertUV = faceVertexUvs[i];
for ( var j = 0; j < 3; j ++ ) {
var x = vertUV[j].x;
var y = vertUV[j].y;
// Capture the upper and lower bounds for all points
if (!minX || x < minX) minX = x;
if (!maxX || x > maxX) maxX = x;
if (!minY || y < minY) minY = y;
if (!maxY || y > maxX) maxY = y;
}
}
console.log("minX: " + minX + ", maxX: " + maxX);
console.log("minY: " + minY + ", maxY: " + maxY);
When you run this code, you'll see that the range is always [0, 1]
, not [-1, 1]
. Additionally, keep in mind that UVs don't have a Z value; only X and Y, since they're used to map a 2-dimensional image.
Normals:
UVs:
You can see how ThreeJS builds sphere UVs in this code, specifically in lines 90, 94, and 111.
Upvotes: 3