Images on extrudeGeometry Mesh Faces Appear Tiny and Not Stretched

I’m trying to create a 3D playing card with a little thickness by using extrudeGeometry, but the images for the card face and back appear tiny and at the center of the card rather than stretched to the edges of the selected faces. Oddly, the colors seem to be stretched, but not the image.

(That tiny dot at the center of the card is the actual image)

Screen Shot 2020-10-14 at 7.03.50 PM

I’ve tried using an image with dimensions of power of 2, but same result.

In the past I’ve used pretty much the same approach with cylinderGeometry, and it’s worked fine:

Here’s my current code. I’ve tested to ensure I’ve assigned the right materials to the right faces.

/// RENDERER

let renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize( window.innerWidth*2, window.innerHeight*2 );  //sets the canvas at double-size for higher resolution
let canvasDiv = document.getElementById("canvas_div");
canvasDiv.appendChild( renderer.domElement );
let canvas = document.getElementsByTagName('canvas')[0];
canvas.style.width = window.innerWidth + "px";  //shrinks the canvas to the window's size while keeping high resolution
canvas.style.height = window.innerHeight + "px";  //shrinks the canvas to the window's size while keeping high resolution



/// 3D ENVIRONMENT

let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera( 35, window.innerWidth/window.innerHeight, 1, 1000 );
camera.position.set( 0, 0, 150 );
scene.add( camera );
let controls = new THREE.OrbitControls( camera, renderer.domElement );



/// LIGHT

renderer.setClearColor ( 0xF2F2F2, 1 );  // background color
let lightA1 = new THREE.AmbientLight(0xFFFFFF, 0.8);
scene.add(lightA1);
let lightD1 = new THREE.DirectionalLight( 0xFFFFFF, 0.3 );
lightD1.position.set( -250, 300, 150 );
scene.add( lightD1 );



/// CARD

let cardWidth = 25;
let cardHeight = 35;
let cardDepth = cardWidth/50;

let hw = cardWidth/2;  // half width
let hh = cardHeight/2;  // half height
let hd = cardDepth/2;  // half depth
let cr = 1.4;  // corner radius
let bhl = cr*.552;  // bezier handle length (for perfect circle curve)
let bdc = cr-bhl;  // bezier handle distance from corner

let cardShape = new THREE.Shape();

cardShape.moveTo( -hw+cr, hh );
cardShape.lineTo( hw-cr, hh );
cardShape.bezierCurveTo( hw-bdc, hh, hw, hh-bdc, hw, hh-cr );
cardShape.lineTo( hw, -hh+cr );
cardShape.bezierCurveTo( hw, -hh+bdc, hw-bdc, -hh, hw-cr, -hh );
cardShape.lineTo( -hw+cr, -hh);
cardShape.bezierCurveTo( -hw+bdc, -hh, -hw, -hh+bdc, -hw, -hh+cr );
cardShape.lineTo( -hw, hh-cr);
cardShape.bezierCurveTo( -hw, hh-bdc, -hw+bdc, hh, -hw+cr, hh );

let extrudeGeometry = new THREE.ExtrudeGeometry( cardShape, { depth: cardDepth, bevelEnabled: false } );

let materialsArray = [];

let cardBackImage = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/409445/figgie-card-back-po2.png";
let cardHeartImage = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/409445/figgie-card-heart-1.png";

let cardSidesMaterial = new THREE.MeshLambertMaterial( { color: "red" /*0x444FA1*/ } );
materialsArray.push( cardSidesMaterial );  //(materialindex = 0)

let cardBackLoader = new THREE.TextureLoader();
cardBackLoader.load( cardBackImage, function ( texture ) { 
  let cardBackMaterial = new THREE.MeshBasicMaterial( { map: texture } );
  materialsArray.push( cardBackMaterial );  //(materialindex = 1)
});

let cardHeartLoader = new THREE.TextureLoader();
cardHeartLoader.load( cardHeartImage, function ( texture ) { 
  let cardHeartMaterial = new THREE.MeshBasicMaterial( { map: texture } );
  materialsArray.push( cardHeartMaterial );  //(materialindex = 2)
});

let faceCount = extrudeGeometry.faces.length;
for ( let i=0; i<faceCount; i++ ) {
  if ( i < 50 ) {
    extrudeGeometry.faces[i].materialIndex = 1;
  } else if ( i < 100 ) {
    extrudeGeometry.faces[i].materialIndex = 2;
  } else {
    extrudeGeometry.faces[i].materialIndex = 0;
  }
}

let card = new THREE.Mesh( extrudeGeometry, materialsArray );
scene.add( card );



/// RENDERING

function render() {
  requestAnimationFrame( render );
  camera.updateProjectionMatrix();
  renderer.render( scene, camera );
};
render(); 



/// INTERACTION

function onWindowResize() {
	let sceneHeight = window.innerHeight;
	let sceneWidth = window.innerWidth;
	canvas.style.width = window.innerWidth + "px";
  canvas.style.height = window.innerHeight + "px";
	camera.aspect = sceneWidth/sceneHeight;
	camera.updateProjectionMatrix();
}

window.addEventListener('resize', onWindowResize, false);

Just make the card model in Blender, it’s like 0.5 seconds, automatically perfectly aligned UVs included … :’)

But yeah - since that isn’t exactly an answer to your question, and we’re not in the making-dev-lives-easier business here - long story short, your UVs are messed up. Code from this answer should help you recalculate them and align with model bounds (tested on codepen and seems to look fine.)
Just remember to always set extrudeGeometry.uvsNeedUpdate = true; and extrudeGeometry.elementsNeedUpdate = true; after updating stuff in these arrays.

1 Like

Beautiful. Works perfectly.