[newbie] Cannot display a texture on uv

Im new to ThreeJS so I’ve done a stupid newbie error, can someone help me ?

// create a test object for lightmapping
    
    const map = new THREE.TextureLoader().load( "./textures/test.jpg" );
    map.wrapS = THREE.RepeatWrapping;
    map.wrapT = THREE.RepeatWrapping;
    
    //const lightMap = new THREE.TextureLoader().load( "./textures/lightmap.jpg" );
    
    const obj = {
        color: 0xffffffff,
        shininess: 2,
        emissive: 0xffffffff,
        emissiveIntensity: .5,
        transparent: false,
        opacity: 1,
        map: map
        //lightMap: lightMap
    };
    const material2 = new THREE.MeshPhongMaterial(obj);
    
    const indexBuffer = [
        0, 1, 2,
        0, 2, 3,
        1, 4, 5,
        1, 5, 2
    ];
    
    const vertBuffer = new Float32Array([
        0 , 0 , 0 ,
        16, 0 , 32,
        16, 16, 32,
        0 , 16, 0 ,
        32, 0 , 0 ,
        32, 16, 0   
    ]);
    
    const uvTex = new Float32Array([
        0 , 0 ,
        1 , 0 ,
        1 , 1 ,
        0 , 1 ,
        2 , 0 ,
        2 , 1
    ]);
    
    const geometry2 = new THREE.BufferGeometry();
    
    
    geometry2.setAttribute('position', new THREE.BufferAttribute(vertBuffer, 3));
    geometry2.setAttribute('uv', new THREE.BufferAttribute(uvTex, 2));
    geometry2.setIndex( indexBuffer );
    geometry2.computeVertexNormals();
    
    const mesh = new THREE.Mesh(geometry2, material2);
    SCENE.add(mesh);

Do you have an animation loop in your app?

Yes i have.

function VideoRoutine(dt)
{
    requestAnimationFrame(VideoRoutine);

    //DUMMY.rotateZ(Math.PI * 1 / 64 * (K[37] - K[39]));
    //DUMMY.translateY(4 * (K[38] - K[40]));

    RENDERER.render(SCENE, CAMERA);
}

It just displays a grey mesh:

color: 0xffffffff,
shininess: 2,
emissive: 0xffffffff,

to

color: 0xffffff,
shininess: 2,
emissive: 0xffffff,
function VideoRoutine(dt)
{
    requestAnimationFrame(VideoRoutine);

    //DUMMY.rotateZ(Math.PI * 1 / 64 * (K[37] - K[39]));
    //DUMMY.translateY(4 * (K[38] - K[40]));
map.needsUpdate=true;
material2.needsUpdate=true;
    RENDERER.render(SCENE, CAMERA);
}

Check into console texture really loaded.

I made your modifications and still have a grey mesh,

Console says me:

THREE.WebGLRenderer: Texture marked for update but image is undefined

maybe this:

MAP = new THREE.TextureLoader().load( "./textures/test.jpg" );

requires a callback event

i used the callback event and it still doesn’t work.

here’s my full code:

"use strict";
import * as THREE from '../../build/three.module.js';

// globals

var BATCHES = [];
var SCENE = null;
var RENDERER = null;
var CAMERA = null;
var DUMMY = null;
var SUN = null;

var MAP = null;
var LIGHTMAP = null;

function CreatePhongMaterial(color, opacity, wireframe, map, lightMap)
{
    const obj = {
        color: color,
        shininess: 2,
        emissive: 0xffffffff,
        emissiveIntensity: .5,
        transparent: (opacity < 1),
        opacity: opacity,
        wireframe: wireframe,
        map: map,
        lightMap: lightMap
    };
    return new THREE.MeshPhongMaterial(obj);
};

function main()
{
    console.log("INIT APP");

    //Create a WebGLRenderer 

    SCENE = new THREE.Scene();
    CAMERA = new THREE.PerspectiveCamera(90, 800 / 600, 0.1, 10000);
    RENDERER = new THREE.WebGLRenderer();
    RENDERER.setSize(240, 160);
    RENDERER.domElement.style.width = '100%';
    RENDERER.domElement.style.height = '100%';
    document.getElementById("container").appendChild(RENDERER.domElement);

    // world is z-up based
    CAMERA.position.x = 16;
    CAMERA.position.z = 64;
    CAMERA.position.y = 8;
    //camera.rotateX(Math.PI / 4);

    //turn on shadows in the renderer
    //RENDERER.shadowMap.enabled = true;
    //RENDERER.shadowMap.type = THREE.PCFSoftShadowMap;
    //RENDERER.setClearColor(0x000000, 1);

    // sun
    SUN = new THREE.DirectionalLight(0xffffffff, 1);
    SUN.position.set(0, 0, 1000);

    
    
    // load a resource
    const loader = new THREE.TextureLoader();
    loader.load(
	// resource URL
	'./textures/test.jpg',

	// onLoad callback
	function ( texture ) {
            console.log("texture loaded");
            MAP = texture;
            onTexturesLoaded();
	},

	// onProgress callback currently not supported
	undefined,

	// onError callback
	function ( err ) {
            console.error( 'texture load error' );
	}
    );
}

function onTexturesLoaded()
{
    
    // create the dummy

    const geometry = new THREE.BoxGeometry(16, 16, 16);
    
    console.log( geometry.attributes );
    
    const material = CreatePhongMaterial(0xffffffff, 1, false, null, null);
    DUMMY = new THREE.Mesh(geometry, material);
    //SCENE.add(DUMMY);
    
    
    // create a test object for lightmapping
    

    MAP.wrapS = THREE.RepeatWrapping;
    MAP.wrapT = THREE.RepeatWrapping;
    
    //const lightMap = new THREE.TextureLoader().load( "./textures/lightmap.jpg" );
    
    const obj = {
        color: 0xffffff,
        shininess: 2,
        emissive: 0xffffff,
        emissiveIntensity: .5,
        transparent: false,
        opacity: 1,
        map: MAP
        //lightMap: lightMap
    };
    const material2 = new THREE.MeshPhongMaterial(obj);
    
    const indexBuffer = [
        0, 1, 2,
        0, 2, 3,
        1, 4, 5,
        1, 5, 2
    ];
    
    const vertBuffer = new Float32Array([
        0 , 0 , 0 ,
        16, 0 , 32,
        16, 16, 32,
        0 , 16, 0 ,
        32, 0 , 0 ,
        32, 16, 0   
    ]);
    
    const uvTex = new Float32Array([
        0 , 0 ,
        1 , 0 ,
        1 , 1 ,
        0 , 1 ,
        2 , 0 ,
        2 , 1
    ]);
    
    const geometry2 = new THREE.BufferGeometry();
    
    
    geometry2.setAttribute('position', new THREE.BufferAttribute(vertBuffer, 3));
    geometry2.setAttribute('uv', new THREE.BufferAttribute(uvTex, 2));
    geometry2.setIndex( indexBuffer );
    geometry2.computeVertexNormals();
    
    const mesh = new THREE.Mesh(geometry2, material2);
    SCENE.add(mesh);
    
    
    // start video routine
    requestAnimationFrame(VideoRoutine);
}
main();

function exit()
{
    //DUMMY.mesh.dispose();
    
    DUMMY.geometry.dispose();
    DUMMY.material.dispose();
    
    console.log("VRAM CLEANED");
    
    console.log("CLOSE APP");
}
window.onunload = exit;


// keyboard

const K = new Uint8ClampedArray(256);

document.onkeydown = function (e)
{
    e.preventDefault();
    K[e.keyCode] = true;
};

document.onkeyup = function (e)
{
    e.preventDefault();
    K[e.keyCode] = false;
};

function VideoRoutine(dt)
{
    requestAnimationFrame(VideoRoutine);

    //DUMMY.rotateZ(Math.PI * 1 / 64 * (K[37] - K[39]));
    //DUMMY.translateY(4 * (K[38] - K[40]));
    
    MAP.needsUpdate=true;
    //material2.needsUpdate=true;

    RENDERER.render(SCENE, CAMERA);
}
   SUN = new THREE.DirectionalLight(0xffffffff, 1);
   SUN.position.set(0, 0, 1000);

to

   SUN = new THREE.DirectionalLight(0xffffff, 1);
    SUN.position.set(0, 0, 1000);
    SCENE.add(SUN);

emissiveIntensity: .5,
to
emissiveIntensity: .0,

delete

    MAP.needsUpdate=true;
    //material2.needsUpdate=true;

1 Like

I just added scene.add(SUN), i see my texture :slight_smile:

Thank you very very much :slight_smile:

1 Like

Now i’d like to add the lightmap but my code is wrong again:

"use strict";
import * as THREE from '../../build/three.module.js';

// globals

var BATCHES = [];
var SCENE = null;
var RENDERER = null;
var CAMERA = null;
var DUMMY = null;
var SUN = null;

var MAP = null;
var LIGHTMAP = null;

function CreatePhongMaterial(color, opacity, wireframe, map, lightMap)
{
    const obj = {
        color: color,
        shininess: 2,
        emissive: 0xffffffff,
        emissiveIntensity: .5,
        transparent: (opacity < 1),
        opacity: opacity,
        wireframe: wireframe,
        map: map,
        lightMap: lightMap
    };
    return new THREE.MeshPhongMaterial(obj);
};

function main()
{
    console.log("INIT APP");

    //Create a WebGLRenderer 

    SCENE = new THREE.Scene();
    CAMERA = new THREE.PerspectiveCamera(90, 800 / 600, 0.1, 10000);
    RENDERER = new THREE.WebGLRenderer();
    RENDERER.setSize(480, 320);
    RENDERER.domElement.style.width = '100%';
    RENDERER.domElement.style.height = '100%';
    document.getElementById("container").appendChild(RENDERER.domElement);

    // world is z-up based
    CAMERA.position.x = 16;
    CAMERA.position.z = 64;
    CAMERA.position.y = 8;
    //camera.rotateX(Math.PI / 4);

    //turn on shadows in the renderer
    //RENDERER.shadowMap.enabled = true;
    //RENDERER.shadowMap.type = THREE.PCFSoftShadowMap;
    //RENDERER.setClearColor(0x000000, 1);

    // sun
    SUN = new THREE.DirectionalLight(0xffffff, 1);
    SUN.position.set(0, 0, 1000);
    SCENE.add(SUN);

    
    // create the dummy

    const geometry = new THREE.BoxGeometry(16, 16, 16);
    
    console.log( geometry.attributes );
    
    const material = CreatePhongMaterial(0xffffffff, 1, false, null, null);
    DUMMY = new THREE.Mesh(geometry, material);
    //SCENE.add(DUMMY);
    
    
    // create a test object for lightmapping
    
    MAP = new THREE.TextureLoader().load( "./textures/test.jpg" );
    MAP.wrapS = THREE.RepeatWrapping;
    MAP.wrapT = THREE.RepeatWrapping;
    
    LIGHTMAP = new THREE.TextureLoader().load( "./textures/lightmap.jpg" );
    LIGHTMAP.wrapS = THREE.RepeatWrapping;
    LIGHTMAP.wrapT = THREE.RepeatWrapping;
    
    const obj = {
        shininess: 0,
        transparent: false,
        opacity: 1,
        map: MAP,
        lightMap: LIGHTMAP
    };
    const material2 = new THREE.MeshPhongMaterial(obj);
    
    const indexBuffer = [
        0, 1, 2,
        0, 2, 3,
        1, 4, 5,
        1, 5, 2
    ];
    
    const vertBuffer = new Float32Array([
        0 , 0 , 0 ,
        16, 0 , 0,
        16, 16, 0,
        0 , 16, 0 ,
        32, 0 , 0 ,
        32, 16, 0   
    ]);
    
    const uvTex = new Float32Array([
        0 , 0 ,
        1 , 0 ,
        1 , 1 ,
        0 , 1 ,
        2 , 0 ,
        2 , 1
    ]);
    
    const uvLm = new Float32Array([
        0 , 0 ,
        1 , 0 ,
        1 , 1 ,
        0 , 1 ,
        2 , 0 ,
        2 , 1
    ]);
    
    const geometry2 = new THREE.BufferGeometry();
    
    
    geometry2.setAttribute('position', new THREE.BufferAttribute(vertBuffer, 3));
    geometry2.setAttribute('uv', new THREE.BufferAttribute(uvTex, 2));
    geometry2.setAttribute('uv2', new THREE.BufferAttribute(uvLm, 2));
    geometry2.setIndex( indexBuffer );
    geometry2.computeVertexNormals();
    
    const mesh = new THREE.Mesh(geometry2, material2);
    SCENE.add(mesh);
    
    
    // start video routine
    requestAnimationFrame(VideoRoutine);
}
main();

function exit()
{
    //DUMMY.mesh.dispose();
    
    DUMMY.geometry.dispose();
    DUMMY.material.dispose();
    
    console.log("VRAM CLEANED");
    
    console.log("CLOSE APP");
}
window.onunload = exit;


// keyboard

const K = new Uint8ClampedArray(256);

document.onkeydown = function (e)
{
    e.preventDefault();
    K[e.keyCode] = true;
};

document.onkeyup = function (e)
{
    e.preventDefault();
    K[e.keyCode] = false;
};

function VideoRoutine(dt)
{
    requestAnimationFrame(VideoRoutine);

    //DUMMY.rotateZ(Math.PI * 1 / 64 * (K[37] - K[39]));
    //DUMMY.translateY(4 * (K[38] - K[40]));
    
    //MAP.needsUpdate=true;
    //material2.needsUpdate=true;

    RENDERER.render(SCENE, CAMERA);
}

No errors was found

To avoid such beginner’s mistakes, it helps to take a closer look at a number of examples that work and are not too complicated.

In the Collection of examples from discourse.threejs.org there are simple and advanced examples with links to the posts.

Have a look inside. :face_with_monocle:

3 Likes

Yes i’ve done an error.

I tried to add the lightmap uv layer like that but it doesn’t work;

geometry2.setAttribute('uv2', new THREE.BufferAttribute(uvLm, 2));

Maybe this can help


1 Like

I replaced “uv2” by “uv1” but it still doesn’t work, because the attribute ‘uv1’ doesn’t exist.

Here your uv2 for lightmap and its work:

geometry2.setAttribute('position', new THREE.BufferAttribute(vertBuffer, 3));
geometry2.setAttribute('uv', new THREE.BufferAttribute(uvTex, 2));
geometry2.setAttribute('uv2', new THREE.BufferAttribute(uvLm, 2));
geometry2.setIndex( indexBuffer );
geometry2.computeVertexNormals();

Add for geometry2 not geometry: console.log( geometry2.attributes );

1 Like

My three.js wasn’t up-to-date, now i can see both textures, but they are both on the first uvCoords.

"use strict";
import * as THREE from '../../build/three.module.js';

// globals

var BATCHES = [];
var SCENE = null;
var RENDERER = null;
var CAMERA = null;
var DUMMY = null;
var SUN = null;

var MAP = null;
var LIGHTMAP = null;

function CreatePhongMaterial(color, opacity, wireframe, map, lightMap)
{
    const obj = {
        color: color,
        shininess: 2,
        emissive: 0xffffffff,
        emissiveIntensity: .5,
        transparent: (opacity < 1),
        opacity: opacity,
        wireframe: wireframe,
        map: map,
        lightMap: lightMap
    };
    return new THREE.MeshPhongMaterial(obj);
};

function main()
{
    console.log("INIT APP");

    //Create a WebGLRenderer 

    SCENE = new THREE.Scene();
    CAMERA = new THREE.PerspectiveCamera(90, 800 / 600, 0.1, 10000);
    RENDERER = new THREE.WebGLRenderer();
    RENDERER.setSize(480, 320);
    RENDERER.domElement.style.width = '100%';
    RENDERER.domElement.style.height = '100%';
    document.getElementById("container").appendChild(RENDERER.domElement);

    // world is z-up based
    CAMERA.position.x = 16;
    CAMERA.position.z = 64;
    CAMERA.position.y = 8;
    //camera.rotateX(Math.PI / 4);

    //turn on shadows in the renderer
    //RENDERER.shadowMap.enabled = true;
    //RENDERER.shadowMap.type = THREE.PCFSoftShadowMap;
    //RENDERER.setClearColor(0x000000, 1);

    // sun
    SUN = new THREE.DirectionalLight(0xffffff, 1);
    SUN.position.set(0, 0, 1000);
    SCENE.add(SUN);

    
    // create the dummy

    const geometry = new THREE.BoxGeometry(16, 16, 16);
    
    
    
    const material = CreatePhongMaterial(0xffffffff, 1, false, null, null);
    DUMMY = new THREE.Mesh(geometry, material);
    //SCENE.add(DUMMY);
    
    
    // create a test object for lightmapping
    
    MAP = new THREE.TextureLoader().load( "./textures/test.jpg" );
    MAP.wrapS = THREE.RepeatWrapping;
    MAP.wrapT = THREE.RepeatWrapping;
    
    LIGHTMAP = new THREE.TextureLoader().load( "./textures/lightmap.jpg" );
    LIGHTMAP.wrapS = THREE.RepeatWrapping;
    LIGHTMAP.wrapT = THREE.RepeatWrapping;
    
    const obj = {
        shininess: 0,
        transparent: false,
        opacity: 1,
        map: MAP,
        lightMap: LIGHTMAP
    };
    const material2 = new THREE.MeshPhongMaterial(obj);
    
    const indexBuffer = [
        0, 1, 2,
        0, 2, 3,
        1, 4, 5,
        1, 5, 2
    ];
    
    const vertBuffer = new Float32Array([
        0 , 0 , 0 ,
        16, 0 , 0,
        16, 16, 0,
        0 , 16, 0 ,
        32, 0 , 0 ,
        32, 16, 0   
    ]);
    
    const uvTex = new Float32Array([
        0 , 0 ,
        1 , 0 ,
        1 , 1 ,
        0 , 1 ,
        2 , 0 ,
        2 , 1
    ]);
    
    const uvLm = new Float32Array([
        0 , 0 ,
        .5, 0 ,
        .5,.5 ,
        0 ,.5 ,
        1 , 0 ,
        1 ,.5
    ]);
    
    const geometry2 = new THREE.BufferGeometry();
    
    
    geometry2.setAttribute('position', new THREE.BufferAttribute(vertBuffer, 3));
    geometry2.setAttribute('uv', new THREE.BufferAttribute(uvTex, 2));
    geometry2.setAttribute('uv1', new THREE.BufferAttribute(uvLm, 2));
    geometry2.setIndex( indexBuffer );
    geometry2.computeVertexNormals();
    
    console.log( geometry2.attributes );
    
    const mesh = new THREE.Mesh(geometry2, material2);
    SCENE.add(mesh);
    
    
    // start video routine
    requestAnimationFrame(VideoRoutine);
}
main();

function exit()
{
    //DUMMY.mesh.dispose();
    
    DUMMY.geometry.dispose();
    DUMMY.material.dispose();
    
    console.log("VRAM CLEANED");
    
    console.log("CLOSE APP");
}
window.onunload = exit;


// keyboard

const K = new Uint8ClampedArray(256);

document.onkeydown = function (e)
{
    e.preventDefault();
    K[e.keyCode] = true;
};

document.onkeyup = function (e)
{
    e.preventDefault();
    K[e.keyCode] = false;
};

function VideoRoutine(dt)
{
    requestAnimationFrame(VideoRoutine);

    //DUMMY.rotateZ(Math.PI * 1 / 64 * (K[37] - K[39]));
    //DUMMY.translateY(4 * (K[38] - K[40]));
    
    //MAP.needsUpdate=true;
    //material2.needsUpdate=true;

    RENDERER.render(SCENE, CAMERA);
}

Calling the second attribute “uv1” or “uv2” doesn’t change anything.

LIGHTMAP.wrapT = THREE.RepeatWrapping;

to

LIGHTMAP.wrapT = THREE.RepeatWrapping;    
LIGHTMAP.channel=1;
1 Like

Thank you very much, it works now with:

LIGHTMAP.channel=1
geometry2.setAttribute('uv1', new THREE.BufferAttribute(uvLm, 2));
3 Likes

Another problem, the lightmap appears 50% (black zones are grey).