Three.js: flip image loaded with loadTextureCube - javascript

I have a legacy code snippet that has long since been part of a web application. The goal is to render a cube from 6 image urls via three.js. The problem is, that the bottom image is flipped around on its y axis. All other sides look fine.
There is no way to flip the original image, since they are provided by an external service. Also when I open the bottom image directly, it is displayed correctly, only in the three.js cube its flipped.
Since I have no prior experience with three.js, I first looked at the documentation for this functionality and realized that the code used in our script is deprecated. unfortunately there is no detailed documentation of the old function (THREE.ImageUtils.loadTextureCube) - or I was simply unable to find it (if someone knows where it is, a link would be great!).
I know that for the long term, a reimplementation to replace all deprecated functions would in order, but since this would take a lot more time (for someone unfamiliar with three.js), I first wanted to check if the problem can be fixed using the existing code base.
I read in various other posts/issues that this is a known issue because three.js for some internal reason defaults to flipY=true on textures. The problem I have is that I don't know (due to lack of documentation) how to change this parameter on one side of the cube only. I expect a function can be applied to the loader that could update this parameter for one of the images or a transformation could be applied to the loaded image afterwards.
I really hope somebody knows (remembers) how this can be achieved with the old loader function.
The following partial code is from my script:
// passed list of urls (images.bottom is flipped around)
var urls = [ images.left, images.right, images.top, images.bottom, images.back, images.front ];
// SCENE
scene = new THREE.Scene();
// TEXTURES
textureCube = THREE.ImageUtils.loadTextureCube( urls );
textureCube.format = THREE.RGBFormat;
textureCube.mapping = THREE.CubeReflectionMapping;
// MATERIALS
var cubeShader = THREE.ShaderLib[ "cube" ];
var cubeMaterial = new THREE.ShaderMaterial( {
fragmentShader: cubeShader.fragmentShader,
vertexShader: cubeShader.vertexShader,
uniforms: cubeShader.uniforms,
depthWrite: false,
side: THREE.BackSide
} );
cubeMaterial.uniforms[ "tCube" ].value = textureCube;
var cubeGeometry = new THREE.BoxGeometry(50,50,50);
cube = new THREE.Mesh( cubeGeometry, cubeMaterial );
scene.add( cube );
// RENDER
renderer = new THREE.WebGLRenderer();
renderer.autoClear = false;
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( containerWidth, containerHeight );
renderer.setFaceCulling( THREE.CullFaceNone );
$container.append( renderer.domElement );
...

Related

Three.js r89 memory leak with STL models

I'm having a bit of trouble with a page I'm building. I think it's fairly simple, but I'm quickly running into issues from what I think is a memory leak.
First off, I've spent the majority of the day searching for an answer, so if I've missed something obvious I'm sorry, I promise I tried. Everything I've found has pointed me to the method I'm currently using, I'm at a loss now.
I have 30 STL models, all 120kb or less that I swap between. Only 3 are on screen at a time and the viewer can swap them out to customize the complete model.
I currently change the colors of the models using:
var selectedObject = scene.getObjectByName(object);
newMaterial = '#'+matHex[newMaterial-1];
newMaterial = hexToRgb(newMaterial);
selectedObject.material.color = newMaterial;
That part works just fine and doesn't seem to slow anything down.
When it comes to replacing the model I use:
var mesh = scene.getObjectByName(object);
if (mesh instanceof THREE.Mesh)
{
scene.remove(mesh);
mesh.geometry.dispose();
mesh.geometry = null;
mesh.material.dispose();
mesh.material = null;
mesh = null;
}
After that I call a function that adds the model back into the scene:
function addHandle(){
loader.load( stlPath+'Handle'+handleID+'.stl', function ( geometry ) {
material = '0x'+matHex[handleMat-1]; //set color hex from array
var handleMaterial = new THREE.MeshPhongMaterial( { color: parseInt(material), specular: specular, shininess: shininess } );
var handleMesh = new THREE.Mesh( geometry, handleMaterial );
handleMesh.position.set( 0, 0, 0 );
handleMesh.rotation.set( Math.PI/2, - Math.PI/2, 0 );
handleMesh.scale.set( .008, .008, .008 );
handleMesh.name = "Handle";
handleMesh.id = handleID;
handleMesh.castShadow = true;
handleMesh.receiveShadow = true;
scene.add( handleMesh );
updateHandle(); //check if Handle needs to rotate
} );
}
From everything I have been able to find this is the proper method for disposing of meshes but after running through about a dozen of them the camera rotation starts to slow down, it takes slightly longer to load the next model, etc. It's especially noticeable on mobile devices.
Hopefully someone out there is able to notice something obvious that I'm missing, it would be hugely appreciated!
I think I solved the problem, and it was my fault like I suspected. I discovered that I was calling animate(); every time a model was replaced. After removing those it is running much much smoother. I'll report back if it ends up not being fixed!

three.js: loading svg with textureloader not working since r78

The following has worked well for me with svg files in R76 and R77 of Three.js, but in R78 I can only get it to work with pngs and jpgs
var floor = new THREE.TextureLoader();
floor.load('layout.svg', function ( texture ) {
var geometry = new THREE.PlaneBufferGeometry(4096, 4096);
var material = new THREE.MeshBasicMaterial( { map: texture } );
var mesh = new THREE.Mesh(geometry, material);
mesh.rotation.x = -Math.PI / 2;
scene.add(mesh);
} );
Since the problem arose, I added the progress and error functions to the load arguments...
function ( xhr ) {
console.log( (xhr.loaded / xhr.total * 100) + '% loaded' );
},
function ( xhr ) {
console.log( 'An error happened' );
}
...which tells me that in r78, the svg is 100% loaded, but it doesn't show up in the scene.
I should add that I also used this with phongmaterial for the reflection properties, and with transparency to show svg elements apparently floating in a skymap, great fun.
My question is, how can I get this working?
In R77, the svg would map to a planeBufferGeometry in FF or chrome.
In R78 it wont load, no errors shown on Firebug.
UPDATE
I investigated SVGLoader.js, SVGRenderer.js (which also requires Projector.js). Renders an svg file facing camera, responds to translations, but not rotations; i.e. no perspective view possible.
I added an xml header to the svg file, then a doctype, but threejs obviously isn't bothered by their absence. Using localhost makes no difference in FF, required in Chrome
So the problem seems to lie either with TextureLoader or WebGLRenderer, which have both had quite a reshuffle in R78.
I also briefly tried the dev version, which acts as r78 does.
Can anyone suggest where I go from here? I'm not sure whether to submit a bug, or a "feature restore".
Here's the desired effect.
Now my understanding is that prior to R78, svgs were internally converted to raster images before rendering.
To continue to use svg images in R78 onwards with Textureloader, convert them to pngs beforehand.
OR if the svg always faces the camera, use the THREE.SVGLoader.
OR If the separate svg elements are required in a three.js scene, convert them to paths and use this example to make a 2d shape or a 3d extruded shape.
My lesson here was not to rely on examples to just work. I should dig right in, break things, and stay up to date with issues on Github.
And use more than one browser; at the time, Chrome was going through a buggy phase not entirely unrelated to this.

Three.js r74 JSONLoader binds duplicate of all geometry to first bone

I'm rewriting this question since I understand more about the bug now. It looks like when using the JSONLoader in r74, the first named bone in an exported Maya scene gets a duplicate of all the geometry.
EDIT: Here's a JSFiddle
In this example I have 2 boxes. Each box is bound to a single bone, and each of those bones has keyframes that animate the position and rotation. There is another bone that has no geometry bound to it, and has keyframes that make no change to its position or rotation.
The stationary bone is called "joint1" in Maya. The bones that actually have geometry bound to them are called "joint2" and "joint3". If I were to rename the stationary bone "joint4" the result would be a duplicate of both boxes attached to the currently animating "joint2".
My guess is that either this is a bug, or I'm doing something wrong when loading the animations. Any tips would be appreciated. The only workaround I can figure out right now is to separate each animated object into a separate file, and that's really not feasible. Plus, that wouldn't solve the issue when I have a multi-bone skeleton. This example is just single bone rigs with no actual deformation.
Here's my current loader code.
//Load Scene, Materials, and Animation
var mixer, mesh;
var actions = {};
var sceneLoader = new THREE.JSONLoader();
sceneLoader.load( sceneFile, function( geometry,materials ) {
materials.forEach( function( material ){
material.skinning = true;
});
mesh = new THREE.SkinnedMesh( geometry, new THREE.MeshFaceMaterial( materials ) );
mixer = new THREE.AnimationMixer( mesh );
actions.main = mixer.clipAction( geometry.animations[ 0 ]);
actions.main.setEffectiveWeight( 1 );
actions.main.play();
scene.add( mesh );
});
//Render
var render = function () {
requestAnimationFrame( render );
controls.update;
var delta = clock.getDelta();
var theta = clock.getElapsedTime();
if ( mixer ) { mixer.update( delta ); }
renderer.render(scene, camera)
}
render();
This is still an issue, but I've found an ok workaround.
Since the duplicated geometry always gets assigned the default lambert shader that is always included when using the Maya Exporter. As long as all the objects that are intended to be kept have a material other than the default in Maya, you can insert
mesh.material.materials[0].visible = false;
into the loader code which will make any material with the default lambert invisible.
Here's a fiddle

Three.js - Extreme shadow on face of mesh

I've created a chest model using blender, created a handpainted texture for it and set the whole thing up in an environment rendered with Three.js. The chest front face however has a unusually extreme shadow:
Here's my Renderer setup:
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
return renderer;
This is the light source (in the screenshot, it's the only light source) causing this shadow:
var envLight = new THREE.PointLight(color, 0.5, 320);
envLight.position.set(0, 80, zPos);
return envLight;
Material setup:
var material = new THREE.MeshPhongMaterial();
//diffuse texture setup
material.map = THREE.ImageUtils.loadTexture(textureURL);
material.map.wrapS = material.map.wrapT = THREE.RepeatWrapping;
material.map.repeat.set(repeatX, repeatY);
// specular map setup
material.specularMap = THREE.ImageUtils.loadTexture(specularMapURL);
material.specularMap.wrapS = material.specularMap.wrapT = THREE.RepeatWrapping;
material.specularMap.repeat.set(repeatX, repeatY);
material.specular = that.specularLightingColor;
return material;
The mesh is created using this material together with the JSON data containing the geometry and UV mapping exported from Blender. I use THREE.JSONLoader to get the data at runtime.
Here's a screenshot from blender showing the mesh and UV map unwrapped, it seems to be an issue with the selected face as it matches the exact shape and position of the weird shadow.
I've tried disabling the shadow with Object3D's castShadow/receiveShadow attributes but that doesn't show any effect at all.
Another screenshot of the normals orientation of the mesh
(source: front-a-little.de)
I've updated to the latest three.js release (r70) and updated the completely re-written Blender Export addon.
The described issue was most likely a bug in a previous version of this exporter, an exported model using the new addon doesn't show the weird shadow.
The new exporter comes with new settings in the save screen, I had to make sure the "UVs" box under "Materials" is checked in order to load the model via Three.JSONLoader

How to texture animated js model exported from blender ? [Three.js]

I have successfully animated a model in blender using bone animation technique and i have also textured it in blender using uv texturing. Then Using three.js export add-on in blender i have exported the model making sure uv and animation in checked in. However i don't know the technique to load the texture for the animated model. I viewed the morph normal example included in three.js where there is simple color texture is used using Lambert material. I have texture from external file. How do i load the texture. In js animated model file there is location for the texture and it is in same location. But it doesn't load. i used the face material technique as well.
the location for three.js example that i used to modify:
http://threejs.org/examples/webgl_morphnormals.html
Here is my code:
var loader = new THREE.JSONLoader();
loader.load( "bird_final.js", function( geometry, materials ) {
morphColorsToFaceColors( geometry );
geometry.computeMorphNormals();
// the old code to set color to the model
//var material = new THREE.MeshLambertMaterial( { color: 0xffffff, morphTargets: true, morphNormals: true, vertexColors: THREE.FaceColors, shading: THREE.SmoothShading } );
// my code
var meshAnim = new THREE.MorphAnimMesh( geometry, new THREE.MeshFaceMaterial( materials ) );
meshAnim.duration = 500;
meshAnim.scale.set( 20, 20, 20 );
meshAnim.position.y = 150;
meshAnim.position.x = -100;
scene1.add( meshAnim );
morphs.push( meshAnim );
} );
Except the documentation and some basic tutorials scattered across the web, is there anywhere i can learn three.js from ground up. like i know setting up scene and creating basic geometry stuffs but some detail info like loading textured model loading scenes etc.
I have created a series of commented examples for Three.js that illustrate features one at a time, starting with very basic features and progressing to more advanced ones (including loading models).
http://stemkoski.github.io/Three.js
Hope this helps!
Working with complex geometry, materials, textures, and animations are some of the hardest things to figure out in THREE.js - that's why we started there with our editor.
We make all of these easy. Export an FBX file (or OBJ/MTL, or Collada) from Blender. Bring it into a project in Verold Studio, then load it into your THREE.js program using our loader. Service is free for use, you pay us if you want enablement services or have a client who wants a maintenance/support agreement.
See the example below, couldn't be easier to bring your scene to THREE.js,
http://jsfiddle.net/rossmckegney/EeMCk/
// 1. Set and then start the animation :)
this.model.setAnimation("mixamo.com");
this.model.playAnimation(true);
//this.model.pauseAnimation();
// 2. Get the threedata for a model
console.log(this.model.threeData);
// 3. Move the model
this.tweenObjectTo(
this.model.threeData, // the model
new THREE.Vector3(1, 0, 0), // go to
new THREE.Quaternion(), // rotation
1, // time, in seconds
false, // smooth start
true); // smooth end
// 4. Clone the model
that = this;
this.model2 = this.model.clone({
success_hierarchy: function(clonedModel) {
that.veroldEngine.getActiveScene().addChildObject(clonedModel);
}
});

Categories