Reputation: 3606
I'm currently using Three.js to try and create something. I've got a sphere, and I'm trying to map the eyeball image here onto it.
The problem I have is that the result looks like this:
How can I get it to map properly without looking stretched?
My code for creating the sphere and mapping the texture is below:
var geometry = new THREE.SphereGeometry(0.5,100,100);
var material = new THREE.MeshPhongMaterial( { map: THREE.ImageUtils.loadTexture('eyeballmap.jpg',THREE.SphericalRefractionMapping) } );
var eyeball = new THREE.Mesh( geometry, material );
eyeball.overdraw = true;
eyeball.castShadow = true;
scene.add( eyeball );
Upvotes: 19
Views: 23907
Reputation: 104843
The key to the answer to your question is the image you linked to.
That image is similar to a MatCap image used in spherical environment mapping.
The appropriate shader for such an environment map is one that uses (a function of) the sphere's normal as the UV index into the texture map.
<script id="vertex_shader" type="x-shader/x-vertex">
varying vec3 vNormal;
void main() {
vNormal = normal;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
</script>
<script id="fragment_shader" type="x-shader/x-fragment">
uniform sampler2D tex;
varying vec3 vNormal;
void main() {
vec2 uv = normalize( vNormal ).xy * 0.5 + 0.5;
vec3 color = texture2D( tex, uv ).rgb;
if ( vNormal.z < - 0.85 ) color = vec3( 0.777, 0.74, 0.74 ); // back of eye
gl_FragColor = vec4( color, 1.0 );
}
</script>
const uniforms = {
"tex": { value: texture }
};
const material = new THREE.ShaderMaterial( {
uniforms : uniforms,
vertexShader : document.getElementById( 'vertex_shader' ).textContent,
fragmentShader : document.getElementById( 'fragment_shader' ).textContent
} );
scene.add( new THREE.Mesh( new THREE.SphereGeometry( 30, 32, 16 ), material ) );
three.js r.147
Upvotes: 45
Reputation: 990
Without changing one line of code, the solution is in using a proper image, sized 1024x512 rather than 512x512:
But actually the original squared images represents a little more than half a sphere: half a sphere is just the circle at center, 256 pixel in radius:
Upvotes: 1
Reputation: 12642
The texture that you have represents only the visible part of the eye which is not the entire sphere. You need to add white space around your existing texture to allow for the part of the sphere that is not visible.
Upvotes: 1