I have a camera that takes round images that claim to represent a 235 degree filed of view, like this one:
I have some experience with threejs and have used it to correctly render 360x360 images stored as equirectangular projections - plenty of samples on the web to do that.
But I want to use threejs to render my round image, probably as a texture inside a sphere. I have looked at some examples (https://threejs.org/examples/#webgl_panorama_dualfisheye and Mapping image onto a sphere in Three.js for example) that seem to be pointing me in the right direction, but I think I just don't know enough about how threejs works to put the pieces together.
The second one (the eyeball) seems to get me close, but following the eyeball code exactly means my image shows up twice (which I guess make sense since my images is square and the texture is has to cover the whole sphere.
So I tried using the long version of SphereGeometry's constructor to make a partial sphere (360 * 235) but changing phi gave me a thing that looks like an orange missing slices. Changing theta gave me the right shape, but the texture didn't lay on it correctly.
So my overall question is how to make this work, but I think the main things stumping me are:
what controls how the texture is painted onto the mesh? (so that I can paint the texture on one time only, and only onto the part of the sphere I need)
I see that setting the UVs is necessary (geometry.faceVertexUvs?) and I read https://en.wikipedia.org/wiki/UV_mapping so I sort of understand what that means, but I don't know where to start with figuring out the correct UVs for my image (and still, like number 1, how to stop it from being shown on the "back" of the sphere)
Okay, so I went and read up about UVs some more and did a lot of experimentation. Here's working code (just the relevant bit), which I mostly understand:
var geometry = new THREE.SphereGeometry( 30, 256, 128, 0, Math.PI * 2, 0, Math.PI );
geometry.scale( - 1, 1, 1 );//inside out
var imgWidth = 0.8;//I thought this should be 235/360, but used trial and error for less fisheye distortion
var faceVertexUvs = geometry.faceVertexUvs[ 0 ];
for ( i = 0; i < faceVertexUvs.length; i ++ ) {
var uvs = faceVertexUvs[ i ];
var face = geometry.faces[ i ];
//y is top to bottom
//z is in-out?
//x is side-side? positive x is front, negative is back
for ( var j = 0; j < 3; j ++ ) {
var fvNj = face.vertexNormals[j];
var yaw = Math.atan2(fvNj.z, fvNj.x)/(Math.PI); //around, -1 to 1
var pitch = Math.asin(fvNj.y)/Math.PI; //height, -0.5 to 0.5
pitch = pitch * -1 + 0.5;//flip and make zero to one
pitch *= imgWidth;
if(pitch < 0.5){
//how to do fisheye correction??
//var correction = (fvNj.x == 0 && fvNj.z == 0) ? 1 : (Math.acos(fvNj.y) / Math.sqrt(fvNj.x * fvNj.x + fvNj.z * fvNj.z)) * (2 / Math.PI);
var x = Math.cos(yaw * Math.PI);// -1 to 1
var y = Math.sin(yaw * Math.PI);// -1 to 1
var u = 0.5 + x*pitch;
var v = 0.5 + y*pitch;
uvs[ j ].x = u;
uvs[ j ].y = v;
}else{
uvs[j].x = 0;
uvs[j].y = 0;
}
}
}
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );