ThreeJS, 3D object texture not working only online - json

I'm using three.js for an AR application to show a 3D object (exported from Maya with maya exporter to threejs) on a marker detected using JSARToolKit.
It all works fine on localhost(I see texture), but when I upload it online (github) and I see the preview object appears all black without texture (like if I remove the light).
// load the model
var loader = new THREE.JSONLoader;
var object;
//var geometry = new THREE.BoxGeometry(1, 1, 1);
loader.load('js/object3d.js', function(geometry, materials){
var material = new THREE.MeshFaceMaterial(materials);
object = new THREE.Mesh(geometry, material);
container.add(object);
});
var ambLight = new THREE.AmbientLight( 0x909090, 2.0 );
container.add( ambLight );
Any ideas?

I am not sure if this is the problem, but it might be that your loader runs into some error but since you didn't set an error handler for your loader you don't get notified.
The JSONLoader load method takes four arguments (url, onLoad, onProgress, onError) as you can see here in the class on line 40.
Try to set an error handler (onError callback method) and see what you get. For example:
var onload = function(geometry, materials){
var material = new THREE.MeshFaceMaterial(materials);
object = new THREE.Mesh(geometry, material);
container.add(object);
});
var onProgress = function(){
// your optional on progress logic
}
var onError = function(error){
console.log( error );
}
var loader = new THREE.JSONLoader;
loader.load('js/object3d.js', onLoad, onProgress, onError);

Related

THEE.JSONLoader Object as public variable

I was wondering if its possible to add an object that is loaded via THREE.JSONLoader as public variable? Ideally, I'd like all my loaded textures, material creation, and geometry to be public variables at the top of my script for easy manipulation (I have strong 3D background but new to js and webGL). I'm finding that my public vars that are declared something - are no longer public once they're added as a parameter to a function - in this case the JSONLoader. However, just naming a var, without declaring its value "runs" but I get weird THREE.min.js error I can't comprehend. I've included my code below - know it has other issues - please feel free to let me know how bad it is - it helps me learn :)
//webGL
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
camera.position.set(0, 16, 25);
camera.rotation.x += -0.32;
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
cubeCamera = new THREE.CubeCamera(1, 1000, 256); // parameters: near, far, resolution
cubeCamera.renderTarget.texture.minFilter = THREE.LinearMipMapLinearFilter; // mipmap filter
scene.add(cubeCamera);
///LOADERS
var loadTexture = new THREE.TextureLoader();
var loaderJs = new THREE.JSONLoader();
///TEXTURES
var skyTexture = loadTexture.load("textures/background.jpg");
var seatTexture = loadTexture.load("textures/abc_Diffuse.jpg");
///MATERIALS
var skyMaterial = new THREE.MeshBasicMaterial({
side: THREE.DoubleSide,
map: skyTexture
});
var frameMaterial = new THREE.MeshLambertMaterial({
//envMap: cubeCamera.renderTarget,
color: 0xffffff
});
var seatMaterial = new THREE.MeshLambertMaterial({
map: seatTexture
});
///GEOMETRY and MESHES
var frameGeo;
var skyGeo = new THREE.SphereGeometry(30, 30, 30);
var skySphere = new THREE.Mesh(skyGeo, skyMaterial);
scene.add(skySphere);
loaderJs.load("models/stoolFrame.js", function (){
frameGeo = new THREE.Mesh(frameGeo, frameMaterial);
frameGeo.scale.set(.5, .5, .5);
barStool.add(frameGeo);
});
loaderJs.load("models/stoolSeat.js", function (seatGeo){
seatGeo = new THREE.Mesh(seatGeo, seatMaterial);
seatGeo.scale.set(.5, .5, .5);
barStool.add(seatGeo);
});
var barStool = new THREE.Object3D();
scene.add(barStool);
var render = function () {
requestAnimationFrame(render);
barStool.rotation.y += 0.01;
frameGeo.visible = false;
cubeCamera.position.copy(frameGeo.position);
cubeCamera.updateCubeMap(renderer, scene);
frameGeo.visible = true;
renderer.render(scene, camera);
};
render();
When loading your stoolFrame, you forgot to add the parameters for the callback function, check the documentation example. The callback function takes a geometry and a material. When loading the stoolSeat you forgot the material aswell (provided you have a material for the stool)
var frameGeometry;
var frameMaterial;
var frameMesh;
loaderJs.load("models/stoolFrame.js", function (geometry, material){
frameGeometry = geometry;
frameMaterial = material
frameMesh = new THREE.Mesh(frameGeometry, frameMaterial);
frameMesh.scale.set(.5, .5, .5);
barStool.add(frameMesh);
});
Above is an example on how to make the geometry, material and mesh into global variables. However you probably dont need to save the geometry and material as global vars (you can access them from the mesh anyway: frameMesh.material; frameMesh.geometry).
If the parameter names are the same as a global variable name, javascript will use the parameter variable instead of the global one when trying to access it.

Three.js JSONLoader blender model error: property 'length' undefined

I have been trying out Three.js lately and i used the exporter addon for Blender to test out making models in blender and exporting so i can use them in a three.js program.
I included the add-on to blender, and using just the basic cube model of blender, exported it to .json as the exporter says. Then i imported the model into my three.js using this as a guide
but that gave me an error:
Uncaught TypeError: Cannot read property 'length' of undefined.
Ive already searched online and tried a few different approaches(like including a materials in the function call of the loader) but nothing seems to work.
I also checked stackoverflow for answers but so far nothing seems solved. If anyone would clarify what im doing wrong I would be very grateful.
The code for my three.js program:
var WIDTH = 1000,
HEIGHT = 1000;
var VIEW_ANGLE = 45,
ASPECT = WIDTH / HEIGHT,
NEAR = 0.1,
FAR = 10000;
var radius = 50,
segments = 16,
rings = 16;
var sphereMaterial =
new THREE.MeshLambertMaterial(
{
color: 0xCCCCCC
});
var sphere = new THREE.Mesh(
new THREE.SphereGeometry(
radius,
segments,
rings),
sphereMaterial);
var pointLight =
new THREE.PointLight(0x660000);
var $container = $('#container');
var renderer = new THREE.WebGLRenderer();
var camera =
new THREE.PerspectiveCamera(
VIEW_ANGLE,
ASPECT,
NEAR,
FAR);
var scene = new THREE.Scene();
var loader = new THREE.JSONLoader(); // init the loader util
scene.add(camera);
pointLight.position.x = 10;
pointLight.position.y = 50;
pointLight.position.z = 130;
scene.add(pointLight);
camera.position.z = 300;
renderer.setSize(WIDTH, HEIGHT);
$container.append(renderer.domElement);
window.requestAnimFrame = (function () {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
loader.load('test.json', function (geometry, materials) {
var material = new THREE.MeshFaceMaterial(materials);
var object = new THREE.Mesh(geometry, material);
scene.add(object);
});
(function animloop() {
requestAnimFrame(animloop);
renderer.render(scene, camera);
})();
When you export, change the Type from buffergeometry to Geometry (Blender 2.76)
In my experience so far with the exporter, you have to be very careful which boxes you tick!
This length error is usually because you are either not exporting the vertexes, or exporting the scene rather the object.
I have the same issue with the new exporter.
If select SCENE then I usually get "Cannot read property 'length' of undefined"
If I select only the object and the materials and vertices. It usually just seems to get stuck forever.
UPDATE
Check this response to this issue!
Threejs blender exporter exports in wrong format
As roadkill stated earlier, exporting as Geometry instead of BufferedGeometry works.
Also note that loading JSON model loading is handled asyncronously (the callback is only called only when the operation is completed, the rest of your code keeps running). The model won't exist for the first frame or two, so check that your model exists before doing any operations with it inside the animation loop.

Three.js JSON loader on apache

I have created a 3D model website for showing JSON files with three.js.
This is working if I open the html file locally stored on my computer.
But if I upload all files to my webserver (apache2) nothing is displayed.
I have tried to run a simple Three.js example without JSON loader and this is working on my webserver.
I also checked the paths to the JSON files and they are all relative paths I can open each file in the browser if I type the name or if I use firebug I can browse all files.
I checked the apache error log but no error message appears.
What can be the problem or how can I find out what the problem is?
This is my Script part.
var scene;
var camera;
var controls;
var geometryArray;
initializeScene();
animateScene();
function initializeScene(){
if(!Detector.webgl){
Detector.addGetWebGLMessage();
return;
}
renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setClearColor(0x000000, 1);
canvasWidth = window.innerWidth;
canvasHeight = window.innerHeight;
renderer.setSize(canvasWidth, canvasHeight);
document.getElementById("WebGLCanvas").appendChild(renderer.domElement);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(45, canvasWidth / canvasHeight, 1, 100);
camera.position.set(0, 0, 6);
camera.lookAt(scene.position);
scene.add(camera);
controls = new THREE.TrackballControls(camera, renderer.domElement);
axisSystem = new AxisSystem(camera, controls);
geometryArray = new Object();
var loader = new THREE.JSONLoader();
for(var i = 0; i < jsonFileNames.length; i++){
var layerName = jsonFileNames[i].split("/")[2].split(".")[0];
loader.load(layerName, jsonFileNames[i], function(geometry, materials, layerName){
mesh = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({vertexColors: THREE.FaceColors, side:THREE.DoubleSide}));
mesh.scale.set(0.013, 0.013, 0.013);
scene.add(mesh);
geometryArray[layerName] = mesh;
}, layerName);
}
var directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);
directionalLight.position = camera.position;
scene.add(directionalLight);
}
function animateScene(){
controls.update();
axisSystem.animate();
requestAnimationFrame(animateScene);
renderScene();
}
function renderScene(){
renderer.render(scene, camera);
axisSystem.render();
}
My guess is that your files are not being loaded because of the for loop you are using. Load is asynchronous, so each time you call loader.load, you corrupt object state from previous call. Try creating new loader in every step or come up with different way of loading multiple files.

ThreeJS load time and texture rendering problems

I have a 3D object of a chair made in Blender and exported as a .obj and .mtl. First of all, the load time is a horrendous 40+ seconds; I have no idea why (Visual Studio possibly?) Second, the images textures are not loading properly. With no ambient or directional lighting I get a silhouette. With the lighting I get a slight hint of gray to give a little depth but nothing close to the many colors in the original object. I have only been working with ThreeJS for a few days now so I'm quite new to it. Hence, I am at a loss. I have read several artciles related to my issue but none seem to solve the problem. I even went so far as to add an addon to Blender to export to .js. I could not get it to even load properly (I assume it had to do with the fact I kept the same loader info from the .OBJMTLLoader and the .JSONLoader doesn't support or needs more than what I gave; I just am not familiar enough with it know). Any ideas/suggestions? Here is my script:
`
<script src="js/three.min.js"></script>
<script src="js/controls/TrackballControls.js"></script>
<script src="js/loaders/MTLLoader.js"></script>
<script src="js/loaders/OBJMTLLoader.js"></script>
<script src="js/Detector.js"></script>
<script>
if (!Detector.webgl) Detector.addGetWebGLMessage();
var container;
var camera, controls, scene, renderer;
init();
animate();
function init() {
container = document.createElement('div');
document.body.appendChild(container);
camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 0.01, 1e10);
camera.position.z = 2;
//controls
controls = new THREE.TrackballControls(camera);
controls.rotateSpeed = 5.0;
controls.zoomSpeed = 5;
controls.panSpeed = 2;
controls.noZoom = false;
controls.noPan = false;
controls.staticMoving = true;
controls.dynamicDampingFactor = 0.3;
scene = new THREE.Scene();
scene.add(camera);
//lights
var ambient = new THREE.AmbientLight(0xCCCCCC);
scene.add(ambient);
var directionalLight = new THREE.DirectionalLight(0xCCCCCC);
directionalLight.position.set(0, 0, 2).normalize();
scene.add(directionalLight);
//main img
var material = new THREE.MeshBasicMaterial({ color: '0xCCCCCC' });
var loader = new THREE.OBJMTLLoader();
loader.addEventListener('load', function (event) {
var geometry = event.content;
//var mesh = new THREE.Mesh(geometry);
scene.add(geometry, material);
});
loader.load('chair.obj', 'chair.mtl');
// renderer
renderer = new THREE.WebGLRenderer({ antialias: false });
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement);
//
window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
controls.handleResize();
}
function animate() {
requestAnimationFrame(animate);
render();
controls.update();
}
function render() {
var timer = Date.now() * 0.0005;
renderer.render(scene, camera);
}
</script>
`
Well, you are defining a gray MeshBasicMaterial to use with your obj instead of using the material(s) that the loader will create for you, i guess.
Just use this. The "object" should have the material defined in your mtl-file.
loader.addEventListener( 'load', function ( event ) {
var object = event.content;
scene.add( object );
});
loader.load( 'chair.obj', 'chair.mtl' );
Concerning your load time: Could be your local server. Also, be aware that the obj file format ist quite big in raw ascii format. Also, if the mtl-file defines textures, they are maybe quite big in file size, too.
#GuyGood was correct in my case for the long load time. I was using the python simplehttpserver and switch to a node server and no more slow texture loading problems. Check out the threejs wiki for other local server options.

detect event from SWFElement in OSMF

I use OSMF's SWFElement for my project to load SWF file in to main Application but the main app can't detect event from child SWF at all, tried to search around but not found any solution
CODE in the Main App
mediaPlayerSprite = new MediaPlayerSprite();
var swfElement:SWFElement = new SWFElement();
swfElement.resource = new URLResource("file:///C:/Users/user/document/OXO/SWF/sampleswfanimation.swf");
// this one not work
swfElement.addEventListener('animationEnd',onSWFEnd );
//this one not work
var loadTrait:LoadTrait = mediaElement.getTrait(MediaTraitType.LOAD) as LoadTrait;
loadTrait.addEventListener('animationEnd',onSWFEnd );
//this one not work too
var displayTrait:DisplayObjectTrait = mediaElement.getTrait(MediaTraitType.DISPLAY_OBJECT) as DisplayObjectTrait;
displayTrait.addEventListener('animationEnd',onSWFEnd );
displayTrait.displayObject.addEventListener('animationEnd',onSWFEnd );
addChild(mediaPlayerSprite);
mediaPlayerSprite.media = swfElement;
CODE in the Child Flash SWF using Flash CS3 add code in The FLASH TimeLine
this.dispatchEvent(new Event('animationEnd') );
I came up with the following solution.I'm not sure if there are better ways but but it works fine.
mediaPlayerSprite = new
MediaPlayerSprite();
var swfElement:SWFElement = new SWFElement();
swfElement.resource = new URLResource("file:///C:/Users/user/document/OXO/SWF/sampleswfanimation.swf");
swfElement.addEventListener(MediaElementEvent.TRAIT_ADD,onTraitAdd);
function onTraitAdd(evt:MediaElement):void
{
if(evt.traitType == "displayObject")
{
var swf:SWFElement = evt.currentTarget as SWFElement;
var displayTrait:DisplayObjectTrait = swf.getTrait( MediaTraitType.DISPLAY_OBJECT ) as DisplayObjectTrait;
var loader:Loader = Loader(displayTrait.displayObject);
loader.content.addEventListener( 'animationEnd',onSWFEnd );
}
}