Need help applying a texture to an extruded object (size and color are not right)

Hi,

I want to make a simulator for a door, that changes according to the cut of each side, the size of the door, and the texture it should have. For this, I created the shape of the cut from lists of points like this:

points: [
[0, 0], //bottom right corner
[-20, 0], //bottom left corner
[-20, 20], //top left corner
[-5, 5], //inside corner
[0, 10], // top right corner
[0, 0] //back to start
]

that look something like this:

These shapes are extruded into “slabs”, according to the wanted size, like this:

On each of these slabs I want to apply a texture coming from an image like this:

My problem is that I can’t make this fit with the right size, or color. Btw, it should look like metal.
I have another example from a different shapes:

Regarding the color, I have tried many approaches for lighting and applying the texture, however this was the only one that came close to the tone of the image, but still too bright.
As for the placement of the texture, I just don’t understand how to make it have the correct size.

I made a very small version of the code to be used in fiddle, just add this code:

// Simple three.js example

import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

let mesh, renderer, scene, camera, controls;

init();
animate();

function createMaterial(src, extrudeGeometry) {
    const textureLoader = new THREE.TextureLoader();
    const texture = textureLoader.load(src);
    texture.wrapS = THREE.RepeatWrapping;
    texture.wrapT = THREE.RepeatWrapping;
    texture.rotation = Math.PI / 2; // Rotate by 45 degrees
    texture.center.set(0.5, 0.5); // Set the center of rotation to the middle of the texture


    // Scale the texture mapping to fit the extruded geometry
    const bbox = extrudeGeometry.boundingBox;
    const width = bbox.max.x - bbox.min.x;
    const height = bbox.max.y - bbox.min.y;

    // Adjust texture scaling to fit the geometry
    const scaleFactor = 0.001; // Adjust this to control the image size
    texture.repeat.set(width * scaleFactor, height * scaleFactor);

    return new THREE.MeshBasicMaterial({ map: texture });

}

function init() {

    // renderer
    renderer = new THREE.WebGLRenderer();
  	renderer.setClearColor(0x000000, 0);  // Set clear color to transparent
		renderer.setSize( window.innerWidth, window.innerHeight );
    renderer.setPixelRatio( window.devicePixelRatio );
    document.body.appendChild( renderer.domElement );

    // scene
    scene = new THREE.Scene();
    
    // camera
    camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 10000 );
    camera.position.set( 20, 20, 20 );

    // controls
    controls = new OrbitControls( camera, renderer.domElement );
    
    // ambient
    const ambientLight = new THREE.AmbientLight(0xffffff, 0);  // Soft white light
    scene.add(ambientLight);

    const directionalLight = new THREE.DirectionalLight(0xffffff, 0);  // Directional light for shadows
    directionalLight.position.set(100, 100, 100).normalize();  // Light comes from top right
    scene.add(directionalLight);
    
    // axes
    scene.add( new THREE.AxesHelper( 20 ) );

    // geometry
		// Create main profile
    //let points= [[0, 0], [-20, 0], [-20, 20], [-5, 5], [0, 10], [0, 0]];
        
    let points= [[0, 0],[-1, 0],[-1, 9],[-2, 10],[-14.5, 10],  [-15.5, 9],[-15.5, -30],[-17, -30],[-17, 60], [0, 60],[0, 2],[5, 2],[5, 0], [0, 0]];
        
    const shape = new THREE.Shape();
    shape.moveTo(...points[0]);
    for (let i = 1; i < points.length; i++) {
      shape.lineTo(...points[i]);
    }

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

    extrudeGeometry.computeBoundingBox();
    
    // material
  	const material = createMaterial('https://i.postimg.cc/tCJ1Ph00/dourado-texturado.png', extrudeGeometry);
    
    // mesh
    mesh = new THREE.Mesh( extrudeGeometry, material );
    scene.add( mesh );
    
}

function animate() {

    requestAnimationFrame( animate );
    
    //controls.update();

    renderer.render( scene, camera );

}

on this template: three.js dev template - module - JSFiddle - Code Playground

For some reason, I copied exactly what I have but the sides of the “slab” are not visible in this example.

Thank you for your time and attention!

When loading a texture, you will need to assign a color space. For a PNG or JPG texture used for color (not a normal map, roughness map, etc.) it’s very likely the texture is sRGB.

texture.colorSpace = THREE.SRGBColorSpace;
2 Likes

Thank you so much! It really solved the problem of the color! Do you have any insights you can give me about the texture? I would like for each side to have just one repetition of the texture, but I don’t know how to define the sides.

Here’s some code I wrote for doing a “box unwrapping” of uvs. It may help.

import *as THREE from "three"

export function boxUnwrap(geometry) {
    const position = geometry.attributes.position;
    const normalAttr = geometry.attributes.normal;
    if (!position || !normalAttr) return;
    
    const uvArray = new Float32Array(position.count * 2);
    const normal = new THREE.Vector3();
    const pos = new THREE.Vector3();

    for (let i = 0; i < position.count; i++) {
        pos.fromBufferAttribute(position, i);
        normal.fromBufferAttribute(normalAttr, i).set(Math.abs(normal.x), Math.abs(normal.y), Math.abs(normal.z));

        let u = 0, v = 0;
        if (normal.x >= normal.y && normal.x >= normal.z) {
            u = pos.y; v = pos.z; // X projection (YZ plane)
        } else if (normal.y >= normal.x && normal.y >= normal.z) {
            u = pos.x; v = pos.z; // Y projection (XZ plane)
        } else {
            u = pos.x; v = pos.y; // Z projection (XY plane)
        }

        uvArray[i * 2] = (u - geometry.boundingBox.min.x) / geometry.boundingBox.getSize(new THREE.Vector3()).x;
        uvArray[i * 2 + 1] = (v - geometry.boundingBox.min.y) / geometry.boundingBox.getSize(new THREE.Vector3()).y;
    }

    geometry.setAttribute('uv', new THREE.BufferAttribute(uvArray, 2));
}