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.
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.
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>
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 onTextureLoader'sload()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.
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.
Thank you so much. It is working fine now. You saved my life big time. Thx!!!