How can I use a .png image to display on one face of a 3d tile object loaded from a .obj file

I’m trying to use a .png image as a material for the top face of a tile in a board game. The object is loaded as a .obj file that was exported from Blender. I can get the tile to display properly, but when I try to edit one of the materials, it only displays the bottom left pixel of the .png file on the face.

Since I want to use the same 3d model for all tiles, I create a “prototype” tile that is cloned. Then I want to just edit the top face to show the type of tile that it is.

I searched for hours and I couldn’t find how to properly do this so that’s why I’m asking. It seems like it should be simple.

I know I can access an object’s materials with this, but it doesn’t display the .png properly. It does change the correct face, but not to what I want.

myTile.children[0].material[1] = myPng;

The dark tiles are the ones that I’m trying to display the .png’s on, but it’s just showing the bottom left pixel of the .png file.

Hi!

Shouldn’t it be myTile.children[0].material[1].map = myPng;?

I shall try this once I get back home to my computer! I only started using three.js last week, so I know pretty much nothing about how it works yet.

I tried that out and it’s giving me this error:

Uncaught TypeError: Cannot read property 'elements' of undefined

I know that the image is loaded properly since I can make a cube that displays it on all sides like this:

var myPng = new THREE.MeshStandardMaterial( { map: texture} );
var cube = new THREE.Mesh(
    new THREE.BoxGeometry(1, 1, 1), 
    myPng
);
scene.add(cube)

My tiles are all clones of a tile object that I load using

var loader = THREE.OBJLoader;

I’m not sure if this is a problem. Maybe it’s a problem with how I’m loading the object. I wanted to get the material filename that is used by the object before I load the object because I have to do

loader.setMaterials(materialsData)

before calling the

loader.load 

function, otherwise the materials wouldn’t display on the object at all. This lead me to do a temporary solution like this… Note that I have loaded all .mtl files and stored them in BG.MaterialsData earlier.

 //Loop through all .obj files to load
objectFiles.forEach(file => {
//I don't understand why I need a new OBJLoader for each object.
let loader = new THREE.OBJLoader(); 
//Load the file so we can see what materials to use
loader.load(file, function(object){
    //Set the materials using the object's material file that it uses.
    loader.setMaterials(BG.MaterialsData[object.materialLibraries[0]]);
    //Load the file again since the materials are set properly
    loader.load(file, function(obj){
        objFilesLoaded++;
        let split = file.split("/");
        //Save the obj to create the tiles later.
        BG.ObjectData[split[split.length - 1]] = obj;
        if(objFilesLoaded === objectFiles.length){
            callback();
        }
    });
});
});

As you can see, I have no clue what I’m doing :upside_down_face:

I’m still leaning towards the problem being how I’m setting the material. Isn’t there some kind of setter function in three.js for this kind of thing?

Edit:
I figured out that the problem was my exported 3d model from Blender didn’t have Cube Projection UV Mapping. This answer from Jostein fixed my problem. texturing - Add UV Mapped texture coordinates to OBJ file? - Blender Stack Exchange