Texture Not Displaying After Loading it unto gltf model

Hey guys, I am quite annoyed at this, but I am trying to change the texture of my model but I cannot see the chnage on the model, I am not getting any error or any issue in my console and even the console.log gives me the correct response so has anyone ever dealt with this issue before?

const tile = new THREE.TextureLoader();
    const taylorTile = tile.load('./texture/Tile.jpg');
const loadGLTFModel = () => {
      const loader = new GLTFLoader();
      loader.load(
        'Buggy.gltf',
        (gltf) => {
          const model = gltf.scene;
scene.add(model);
          model.traverse((child) => {
            if (child.isMesh) {
              
              if (
                child.isMesh &&
                child.userData.name
              ) {
                console.log("Applying texture to:", child.userData.name);
                child.material.map = taylorTile;
                child.material.needsUpdate = true;
}
}
}
              }undefined,
        (error) => {
          console.error('Error loading model:', error.message, error.stack);
        }
      );
    };
    loadGLTFModel();

And you’re seeing your logs, etc?

Can you try moving the gltf loading Inside the loaded callback of the texture?

new THREE.TextureLoader('./texture/Tile.jpg',(tex)=>new THREE.GLTFLoader().load('Buggy.gltf',(gltf)=>gltf.scene.traverse(e=>e.isMesh&&(e.material.map=tex)));

Or the async variant:

let tex = await (new THREE.TextureLoader()).loadAsync(“./texture/Tile.jpg”);

let glb = await (new THREE.GLTFLoader()).loadAsync(“Buggy.gltf”);

1 Like

Would also try:

taylorTile.flipY = false;
taylorTile.colorSpace = THREE.SRGBColorSpace; // if it's a color (not data) texture

It shouldn’t be necessary to do .needsUpdate = true on the material.

1 Like

I tried this but nothing occurred. Also for reference, the texture and gltf loader is in a useEffect bracket.

are you creating this model in React?

1 Like

Yes I am creating this using react with javascript

Instead of using Vanilla GLTFLoader and TextureLoader provided by three.js use useGLTF from react three drei.

First you should convert your model into a jsx component to make it compatible and work better with React-Three-Fiber to do that just follow the steps on the gltfjsx site.

When you will convert the model using gltfjsx the jsx compnent will have all the seperate children and parent objects, making them all individually customisable. There you can easily attach the texture you are trying to apply on to your model using useTexture which will make it easier to load and use the textures.

1 Like

Thank you I am trying it now. Will update shortly!

So I tried that and it still does not work this is the texture I am trying to add to it.

I am somewhat getting to see the color but not the actual texture as depicted in the image.

I basically just went online and downloaded an image i wanted to use for the texture.

Does your model have UVs? You’ll need UV layouts to add textures to models, usually the model and the texture are designed to be used together – if not, you’ll probably want to use something like Blender to do the UV layout.

Also, make sure the scene has lighting. A demo may be helpful if you still can’t see any result.

Can you share any JSFiddle, codepen or codesandbox so that we can see in detail what the problem in your code really is? If not what about the model and the part where you want to apply the texture.

No my model does not have UV’s. But my scene and my lighthing are already created and defined.

This is what the texturing looks like before I have applied it
image

This is what the texturing looks like after I have applied it

Sure here is the whole code.

import { useEffect } from 'react';
import { useThree } from '@react-three/fiber';
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';

export default function LoadModel() {
  const { camera, scene, gl } = useThree();

  useEffect(() => {
    // Set camera position and orientation
    camera.position.set(30, 30, 30);
    camera.lookAt(new THREE.Vector3(0, 0, 0));
    camera.fov = 60;

    // Add ambient light
    const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
    scene.add(ambientLight);

    // Add directional light
    const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
    directionalLight.position.set(0, 20, 10);
    scene.add(directionalLight);

    // Set scene background and fog
    scene.background = new THREE.Color(0x2b2b2b);

    // Load texture
    const hardwoodTexture = new THREE.TextureLoader().load('./texture/HardWoodOak.jpg');
    hardwoodTexture.flipY = false;
    hardwoodTexture.encoding = THREE.sRGBEncoding;

    // Create materials
    const hardwoodMaterial = new THREE.MeshBasicMaterial({ map: hardwoodTexture });

    // Function to traverse and texture the model
    const loadGLTFModel = () => {
      const loader = new GLTFLoader();

      loader.load(
        'buggy.gltf',
        (gltf) => {
          const model = gltf.scene;
        let child;
          // Traverse through the model to find parts named "floor"
          model.traverse((node) => {
            if (node.isMesh && node.userData.name.includes('Floor')) {
                node.material = hardwoodMaterial;
                child = node
            }
          });

          scene.add(child);
        },
        undefined,
        (error) => {
          console.error('Error loading model:', error.message, error.stack);
        }
      );
    };

    // Load the GLTF model
    loadGLTFModel();

  }, [scene, camera, gl]);

  return null;
}

This is what the material looks like:
image

This is what I am getting shown:
image

UVs define how a texture wraps onto a model. Without UVs (or something like them), the texture cannot be wrapped on the model — you may just be seeing pixel 0,0 from the texture here.

If the model is just a box or plane, you can use built-in three.js geometries, which come with basic UVs. To add UVs and a texture to your model, you would want to use something like Blender I think. Or something like a triplanar projection, which is (currently) more difficult to do in three.js.

2 Likes

First of all since you are making your project in R3F and not in three.js instead of using GLTFLoader you can use gltfjsx to convert the model into a React component, that would make modification of children nodes easier. Also you should take a look at React-Three-Drei an awesome R3F component library that could save you loads of time, and I would prefer you to specially take a look at the Texture / useTexture helper of drei

Currently, there are only 2 possible solution for applying this texture on your geometry.

  1. To is to define the UVs to the texture as already stated by @donmccurdy that would make the texture to wrap on the model just as you want in a customised manner.

  2. To convert the geometry into a jsx component using the gltfjsx cli that would give you the component of the model containing all the geometry nodes that can be modified separately and if the geometry have all the faces of the floor as a separate node you can easily map the texture on each node using the Texture / useTexture helper

There is also an online gltfjsx converter that can instantly convert the model as well as provide the code: Poimandres gltf

Note – this approach will still require that the meshes have UVs.

1 Like

Correct me if I am wrong cause I am still learning too, but I worked on a project in which I had a roof model which was made in SketchUp by the client and he wanted a texture on it, so I imported the model in blender and observed that the model had its all nodes separated, what I did instead of defining the UVs I applied the same texture on all the separate nodes and it did the work just fine.

So this was the model with this jsx code:

And I modified the code like this:

And got the texture to wrap on the object just fine.

Did you load roof textures the same way as above?

As in the SS I have attached? Yes!

So I did all that there was some issues so I had to create it as glb rather than gltf but this is my code

import { useEffect } from "react";
import { useThree, useLoader } from "@react-three/fiber";
import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { TextureLoader } from 'three/src/loaders/TextureLoader'

export default function LoadModel() {

  const gltf = useLoader(GLTFLoader, "./buggy.glb");
  console.log(gltf)
  const colorMap = useLoader(TextureLoader, './texture/HardWoodOak.jpg')
  return (
    <>
      <mesh geometry={gltf.nodes[`IfcSlabFloorFloorFloorWood_Truss__Joist_12"_-_Carpet_Finish`].geometry} >
        <meshBasicMaterial map={colorMap}/>
        </mesh>
    </>
  );
}
// App.js
import { Canvas } from '@react-three/fiber';
import LoadModel from './LoadModel';
import { OrbitControls } from '@react-three/drei';
import './App.css';

function App() {
  return (
    <div className="canvas-container">
      <Canvas>
      <ambientLight intensity={0.1} />
      <directionalLight
        position={[5, 5, 5]}
        intensity={1}
        castShadow
      />
      
      {/* Second directional light */}
      <directionalLight
        position={[-5, -5, -5]}
        intensity={0.5}
      />
      <OrbitControls
                    enablePan={true}
                    enableZoom={true}
                  />
        <LoadModel />
      </Canvas>
    </div>
  );
}

export default App;

Here is the result:

Here is a link to the glb model:

Here is a link to the img texture:

I tried transforming it but it was already in a glb format so I decided no to transform,it I played around with the lights and yet no changes. Thus I have provided my entire functions and material in hopes that someone can tell me what else I need to do. Thank you all again so very much!!!