javascriptthree.jsimage-loadingbuffer-geometry

Trouble loading images onto a BufferGeometry surface with THREE.js


I am trying to make a cube in THREE.js with BufferGeometry, but the image won't load correctly. I have tried a few things but nothing seems to work, and it looks like the uv's aren't working.

script.js

//Load the canvas to draw on
var canvas = document.querySelector('#canvas')
// The three.js scene: the 3D world where you put objects
const scene = new THREE.Scene();


function degrees_to_radians(degrees) {
    let pi = Math.PI;
    return degrees * (pi / 180);
}


// The camera
const camera = new THREE.PerspectiveCamera(
    60,
    window.innerWidth / window.innerHeight,
    0.0001,
    10000
);

// The renderer: something that draws 3D objects onto the canvas
const renderer = new THREE.WebGLRenderer({ canvas: canvas });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x4a4a4a, 1);
document.body.appendChild(renderer.domElement);

const controls = new THREE.PointerLockControls(camera, document.body);

document.addEventListener('click', function () {
    controls.lock();
});

var key_map = {}; // You could also use an array
onkeydown = onkeyup = function (e) {
    e = e || event; // to deal with IE
    key_map[e.keyCode] = e.type == 'keydown';
}


const light = new THREE.PointLight( 0xffffff, 2, 0, 2 );
light.position.set( 10, 50, 10 );
scene.add( light );

camera.position.z = 4


const vertices = new Float32Array([
    -1.0, -1.0, 0.0,
    1.0, -1.0, 0.0,
    1.0, 1.0, 0.0,

    1.0, 1.0, 0.0,
    -1.0, 1.0, 0.0,
    -1.0, -1.0, 0.0
]);

const uvs = new Float32Array([
    0.0, 0.0,
    1.0, 0.0,
    1.0, 1.0,

    1.0, 1.0,
    0.0, 1.0,
    0.0, 0.0
]);

let textureLoader = new THREE.TextureLoader();
var texture = textureLoader.load('./images/grass.jpg');

const material = new THREE.MeshLambertMaterial({ map: texture });

const geometry = new THREE.BufferGeometry();
geometry.addAttribute('position', new THREE.BufferAttribute(vertices, 3));
geometry.addAttribute('uv', new THREE.BufferAttribute(uvs, 3));
geometry.computeVertexNormals();

var mesh = new THREE.Mesh(geometry, material);

scene.add(mesh);


const walk_speed = 0.05;
const sprint_speed = 0.15;
const fly_speed = 0.06;
var speed = 0;
var f_speed = 0;
var b_speed = 0;
var l_speed = 0;
var r_speed = 0;

function render() {
    //handle keypresses
    var cameraDirection = controls.getDirection(new THREE.Vector3()).clone();
    var angle = Math.atan2(cameraDirection.x, cameraDirection.z);

    if (key_map[87]) {
        //forwards
        if (key_map[17]) {
            f_speed = sprint_speed;
        } else {
            f_speed = walk_speed;
        }
        controls.getObject().position.z += (Math.cos(angle)) * f_speed;
        controls.getObject().position.x += (Math.sin(angle)) * f_speed;
    }
    if (key_map[83]) {
        //backwards
        if (key_map[17]) {
            speed = sprint_speed;
        } else {
            speed = walk_speed;
        }
        controls.getObject().position.z -= (Math.cos(angle)) * speed;
        controls.getObject().position.x -= (Math.sin(angle)) * speed;
    }
    if (key_map[65]) {
        //left
        if (key_map[17]) {
            speed = sprint_speed;
        } else {
            speed = walk_speed;
        }
        controls.getObject().position.z -= (Math.sin(angle)) * speed;
        controls.getObject().position.x += (Math.cos(angle)) * speed;
    }
    if (key_map[68]) {
        //right
        if (key_map[17]) {
            speed = sprint_speed;
        } else {
            speed = walk_speed;
        }
        controls.getObject().position.z += (Math.sin(angle)) * speed;
        controls.getObject().position.x -= (Math.cos(angle)) * speed;
    }

    if (key_map[16]) {
        //down
        camera.position.y -= fly_speed;
    }
    if (key_map[32]) {
        //up
        camera.position.y += fly_speed;
    }

    renderer.render(scene, camera);

    // Make it call the render() function about every 1/60 second
    requestAnimationFrame(render);
}


render();

I have a weird error where the texture doesn't work.

Picture

the picture


Solution

  • I don't see that you set any UV texture coordinates. Without them the renderer, shader, WebGL programm (or where the magic happens) does not know how to apply the texture to the mesh.

    const vertices = new Float32Array([
        -1.0, -1.0, 1.0,
        1.0, -1.0, 1.0,
        1.0, 1.0, 1.0,
    
        1.0, 1.0, 1.0,
        -1.0, 1.0, 1.0,
        -1.0, -1.0, 1.0
    ]);
    
    const uvs = new Float32Array([
        0.0, 0.0,
        1.0, 0.0,
        1.0, 1.0,
    
        1.0, 1.0,
        0.0, 1.0,
        0.0, 0.0
    ]);
    
    this.geometry.addAttribute('position', new THREE.BufferAttribute(vertices, 3));
    this.geometry.addAttribute('uv', new THREE.BufferAttribute(uvs, 2));
    

    If you try to create a cube with different textures on each side, you could also just utilize BoxGeometry. It already has a different material index for each side. So, you would only need to apply an array of 6 materials to the mesh.