Three.js: Texture: Can't set .flipY before texture has loaded

Created on 4 Jan 2019  Â·  7Comments  Â·  Source: mrdoob/three.js

Hi, I am implementing 3d model with Three.js on my web application. The problem is that updating texture image on imported gltf model is not working correctly. I first exported the model from 3ds max using gltf-export plug-in. And i get 3 files which are .bin, .gltf, .texture image file. After that, I put those three files and other texture image files in the same folder.

After that, I loaded gltf file on my web using GLTFLoader from Three.js. It worked fine shown as below.

https://discourse-cdn-sjc2.com/standard17/uploads/threejs/original/2X/b/b6a0d3711d226355ec41a13632e3b9c008ab50b3.jpeg

But when I try to change the texture image that has green color using TextureLoader and apply onto my model, it shows up like this as below.

https://discourse-cdn-sjc2.com/standard17/uploads/threejs/original/2X/d/d9a002c3b8e1f6a4ab99bbc1dbd99561fdeba898.jpeg

I thought that the problem might be the GLTFLoader already loaded the original gltf file rendering with .bin file that is not editable once loaded and i am applying external texture image onto it. But it turns out to be it is not the cause of problem because it shows same problem when I apply the same texture image when the model is loaded very first time, it shows the same messed up model with same color.

So bascially, I came with this far conclusion. After I succesfully loaded my model as gltf format, updating texture manually is not working correctly. Below is my source code so far. Please help me to fix this. Also, I am sharing the exported gltf model files below.

https://drive.google.com/open?id=1mZrQHVJHmFv0Q_I1aInqmgA4-WtZDwID

---MY CODE---

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%@ page session="false" %>

<!doctype html>

<head>
    <script src="<c:url value="/resources/three.js" />"></script>
    <script src="<c:url value="/resources/three.min.js" />"></script>
    <script src="<c:url value="/resources/OrbitControls.js" />"></script>
    <script src="<c:url value="/resources/GLTFLoader.js" />"></script>

    <style type="text/css">

        #canvas {
        width: 600px;
        height: 600px;
        background: white;
        }
  </style>
</head>
<body>

<div id="canvas"></div>

<select id="colorOption" onchange="setAnotherTexture()">
  <option value="blue">blue</option>
  <option value="red">red</option>
  <option value="green">green</option>
  <option value="black">black</option>
</select>

<script type='text/javascript'>
// Set up the scene, camera, and renderer as global variables.
var scene, camera, renderer, modelObj;

init();
animate();

// Sets up the scene.
function init() {

    // Create the [SCENE] and set the scene size.
    scene = new THREE.Scene();
    scene.background = new THREE.Color( 0xffffff );
    //Create a [RENDERER] and add it to the DOM.
    renderer = new THREE.WebGLRenderer({antialias:true});
    //renderer.gammaFactor = 2.2;

    var container = document.getElementById('canvas');
    var WIDTH = container.offsetWidth;
    var HEIGHT = container.offsetHeight;

    renderer.setSize(WIDTH, HEIGHT);
    container.appendChild(renderer.domElement);


    // Create a [CAMERA], zoom it out from the model a bit, and add it to the scene.
    camera = new THREE.PerspectiveCamera(45, WIDTH / HEIGHT, 0.1, 20000);
    camera.position.set(0,6,0);
    scene.add(camera);


    // Update the Viewport on Resize
    // Create an event listener that resizes the renderer with the browser window.
    window.addEventListener('resize', function() {
        var WIDTH = container.offsetWidth,
            HEIGHT = container.offsetHeight;

        renderer.setSize(WIDTH, HEIGHT);
        camera.aspect = WIDTH / HEIGHT;
        camera.updateProjectionMatrix();
    });


    // Add Lighting
    // Set the background color of the scene.
    renderer.setClearColor(0xffffff, 1);
    renderer.gammaOutput = true;

    // Create a light, set its position, and add it to the scene.
    var light = new THREE.HemisphereLight( 0xbbbbff, 0x444422 );
    //light.position.set( 0, 1, 0 );
    scene.add( light );


    // Instantiate a loader
    var loader = new THREE.GLTFLoader().setPath( 'resources/models/gltf/Hermes_Berkin/' );
    loader.setResourcePath( 'resources/models/gltf/Hermes_Berkin/' );

    loader.load( 'hermes.gltf', function ( gltf ) {

        modelObj = gltf.scene;

        scene.add( modelObj );

        console.log(modelObj);

    }, undefined, function ( error ) {

        console.error( error );

    } );



    // Add Controls
    // Add OrbitControls so that we can pan around with the mouse.
    controls = new THREE.OrbitControls(camera, renderer.domElement);
    //container.addEventListener("touchstart", handlerFunction, false);

}

//Renders the scene and updates the render as needed.
function animate() {

    // Read more about requestAnimationFrame at http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
    requestAnimationFrame(animate);

    // Render the scene.
    renderer.render(scene, camera);
    controls.update();

}

function setAnotherTexture() {
    var textureColor = document.getElementById("colorOption").value;
    var textureLoader = new THREE.TextureLoader();

    var newTexture = textureLoader.load( "resources/models/gltf/Hermes_Berkin/hermes_birkin_" + textureColor + "_d.jpg");

    newTexture.encoding = THREE.sRGBEncoding;
    newTexture.flipY = false;

    modelObj.traverse( function ( child ) {

        if (child instanceof THREE.Mesh) {
            //create a global var to reference later when changing textures
            //apply texture

            child.material.map = newTexture;
            child.material.needsUpdate = true;
            child.material.map.needsUpdate = true;

        }
    });
    console.log(modelObj);

}
</script>

</body>
Help (please use the forum)

All 7 comments

This issue is related to setting properties on the texture (.flipY, .encoding) before it has fully loaded — you can work around it by using the callback on TextureLoader's load() function:

textureLoader.load( "hermes_birkin_" + textureColor + "_d.jpg", function( newTexture ) {

    newTexture.encoding = THREE.sRGBEncoding;
    newTexture.flipY = false;

    modelObj.traverse( function ( child ) {

      if (child instanceof THREE.Mesh) {
          //create a global var to reference later when changing textures
          //apply texture

          child.material.map = newTexture;
          child.material.needsUpdate = true;
          child.material.map.needsUpdate = true;

      }
    });
    console.log(modelObj);

  });

I think it may be a bug that setting those properties earlier doesn't work, though.

This issue is related to setting properties on the texture (.flipY, .encoding) before it has fully loaded — you can work around it by using the callback on TextureLoader's load() function:

textureLoader.load( "hermes_birkin_" + textureColor + "_d.jpg", function( newTexture ) {

    newTexture.encoding = THREE.sRGBEncoding;
    newTexture.flipY = false;

    modelObj.traverse( function ( child ) {

      if (child instanceof THREE.Mesh) {
          //create a global var to reference later when changing textures
          //apply texture

          child.material.map = newTexture;
          child.material.needsUpdate = true;
          child.material.map.needsUpdate = true;

      }
    });
    console.log(modelObj);

  });

I think it may be a bug that setting those properties earlier doesn't work, though.

I just tried but it still does the same thing...I don't think it is a encoding or flipY property setting problem..

Hm, that change fixed an error i was seeing in the console, but yeah the back of the model still looks incorrect... looking at it but not sure why that is yet. Here's a live demo: https://three-bug-hermes-texture-upmeucjdhl.now.sh/

Oh ok, here's the fix:

newTexture.wrapS = THREE.RepeatWrapping;
newTexture.wrapT = THREE.RepeatWrapping;

This model uses a repeat mode that needs to be applied to any new textures you load.

Demo: https://three-bug-hermes-texture-mwgerowkhe.now.sh/

Thank you so much. It is working fine now. You saved my life big time.
Thx!!!

On Fri, Jan 4, 2019 at 2:37 PM Don McCurdy notifications@github.com wrote:

Oh ok, here's the fix:

newTexture.wrapS = THREE.RepeatWrapping;newTexture.wrapT = THREE.RepeatWrapping;

This model uses a repeat mode that needs to be applied to any new textures
you load.

Demo: https://three-bug-hermes-texture-mwgerowkhe.now.sh/

—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/mrdoob/three.js/issues/15520#issuecomment-451357338,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AsAuFBY5hPbnOUicNjWwZTXkhq9h7ONcks5u_uingaJpZM4ZpH6v
.

Oh ok, here's the fix:

newTexture.wrapS = THREE.RepeatWrapping;
newTexture.wrapT = THREE.RepeatWrapping;

This model uses a repeat mode that needs to be applied to any new textures you load.

Demo: https://three-bug-hermes-texture-mwgerowkhe.now.sh/

Thank you so much. It is working fine now. You saved my life big time. Thx!!!

Was this page helpful?
0 / 5 - 0 ratings