ThreeJS cannot load Json files - javascript

first, i have already read this question didn't help
How i do: first i export a model from C4D to .ojb. Then i import the obj into www.trheejs/editor
I fill all the blank
then from the tree i select my object and export it to a Threejs Object, it save a .json file
My code
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var kiss = new THREE.Object3D(), loader = new THREE.JSONLoader(true);
loader.load( "brikk2.json", function ( geometry, materials ) {
var mesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial( { color: 0xff0000, ambient: 0xff0000 } ) );
scene.add( mesh );
});
var render = function () {
requestAnimationFrame(render);
renderer.render(scene, camera);
};
render();
</script>
When i run i have theses error messages
THREE.WebGLRenderer 67 three.js:20806
THREE.WebGLRenderer: elementindex as unsigned integer not supported. three.js:26942
XHR finished loading: "http://xxxxxx.xx/tst/mrdoob-three2/brikk2.json". three.js:12018
THREE.JSONLoader.loadAjaxJSON three.js:12018
THREE.JSONLoader.load three.js:11942
load test.html:23
(anonymous function) test.html:28
Uncaught TypeError: Cannot read property 'length' of undefined three.js:12087
parseModel three.js:12087
THREE.JSONLoader.parse three.js:12028
xhr.onreadystatechange three.js:11969
the Json i load
{
"metadata": {
"version": 4.3,
"type": "Object",
"generator": "ObjectExporter"
},
"geometries": [
{
"uuid": "213E28EF-E388-46FE-AED3-54695667E086",
"name": "brikkG",
"type": "Geometry",
"data": {
"vertices": [0.036304,-0.016031,-0.027174,0.036304,0.......
........ 232,1228,1139,1141,1140,1]
}
}],
"materials": [
{
"uuid": "F74C77E4-8371-41BC-85CA-31FC96916CC6",
"name": "lego",
"type": "MeshPhongMaterial",
"color": 16721408,
"ambient": 16777215,
"emissive": 0,
"specular": 16777215,
"shininess": 30,
"opacity": 1,
"transparent": false,
"wireframe": false
}],
"object": {
"uuid": "3BAAB8CA-1EB7-464A-8C6D-FC4BBB3C63C6",
"name": "BrikkM",
"type": "Mesh",
"geometry": "213E28EF-E388-46FE-AED3-54695667E086",
"material": "F74C77E4-8371-41BC-85CA-31FC96916CC6",
"matrix": [1000,0,0,0,0,1000,0,0,0,0,1000,0,0,0,0,1]
}
}
structure of the json file
basically i have tried all i have read about importing native json into ThreeJS, i tried files from the treejs/editor or clara.io still have the same error message, i have no idea anymore, i spend 3 days trying all the way i read to solve this.
If i try to create geometry like CubeGeometry it render without problems, but at soon as i try with native json, nothing work anymore
somebody could help ?

Ok, i found the answer here: http://helloenjoy.com/2013/from-unity-to-three-js/
the native json code is perfect, it's just no be mean to be loaded with JSONLoader but with ObjectLoader (do not mismatch with OBJLoader like i did i one of my experiment). JSONLoader is mean to load json, but with a different format/structure. ObjectLoader is mean to load native format that is also written in json but with a native structure/format.
so use
var loader = new THREE.ObjectLoader();
loader.load( 'brikk2.json', function ( object ) {
scene.add( object );
} );
and it's working
full example code
<body>
<script src="build/three.min.js"></script>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setClearColor( 0xffffff, 1);
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var ambient = new THREE.AmbientLight( 0x101030 );
scene.add( ambient );
var directionalLight = new THREE.DirectionalLight( 0xffeedd );
directionalLight.position.set( 0, 0, 1 );
scene.add( directionalLight );
var loader = new THREE.ObjectLoader();
loader.load( 'brikk2.js', function ( object ) {
scene.add( object );
} );
camera.position.z = 5;
var render = function () {
requestAnimationFrame(render);
renderer.render(scene, camera);
};
render();
</script>
</body>
EDIT
The top code i showed in the top question was right but it was for Geometry loading
loader = new THREE.JSONLoader();
loader.load( 'ugeometry.json', function ( geometry ) {
mesh = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { envMap: THREE.ImageUtils.loadTexture( 'environment.jpg', new THREE.SphericalReflectionMapping() ), overdraw: 0.5 } ) );
scene.add( mesh );
So the recap.
if from threes/editor or Clara.io you save GEOMETRY use JSONLoader, if you save as OBJECT use ObjectLoader, and if you save as SCENE they should be a SceneLoader (unverified)

Related

Load Models Three.js GLTFLoader Syntax error JSON.parse

I learn how to use Three.js by following the tutorial on discoverthreejs.com.
I have no worries about creating meshes and geometry via three.js
The problem is when I want to load models coming from blender or others.
I use blender 2.8 to create my model and export it as a .glb file. I test the file with a gtlf viewer and everything works as expected.
But as soon as I want to import my model with Three.js to my website, I get this error:
I thought it came from my model, I tried to export it in gltf or glb: same error.
I downloaded another model available on the web: same error.
I use parcel.js if it helps.
{
"name": "cedric_grvl",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"clean": "rm -rf dist",
"dev": "parcel src/index.html --host 192.168.0.37 --open Firefox"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {},
"devDependencies": {
"autoprefixer": "^9.7.3",
"parcel-bundler": "^1.12.4",
"postcss-custom-properties": "^9.0.2",
"postcss-modules": "^1.4.1",
"postcss-preset-env": "^6.7.0",
"sass": "^1.23.7",
"three": "^0.111.0"
}
}
Everything is test in my index.js.
Here is how I call Three.js: (all is good here)
*index.js*
import * as THREE from 'three';
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
Here are the function for Three.js (tutorial)(all good here)
*index.js*
// these need to be accessed inside more than one function so we'll declare them first
let container;
let camera;
let controls;
let renderer;
let scene;
let mesh;
function init() {
container = document.querySelector( `[data-js="canvas"]` );
scene = new THREE.Scene();
scene.background = new THREE.Color( 0xFFFFFF );
createCamera();
createControls();
createLights();
createMeshes();
createRenderer();
// start the animation loop
renderer.setAnimationLoop( () => {
update();
render();
} );
}
function createCamera() {
camera = new THREE.PerspectiveCamera(
35, // FOV
container.clientWidth / container.clientHeight, // aspect
0.1, // near clipping plane
100, // far clipping plane
);
camera.position.set( -4, 4, 10 );
}
function createControls() {
controls = new OrbitControls( camera, container );
}
function createLights() {
const ambientLight = new THREE.HemisphereLight(
0xddeeff, // sky color
0x202020, // ground color
5, // intensity
);
const mainLight = new THREE.DirectionalLight( 0xffffff, 5 );
mainLight.position.set( 10, 10, 10 );
scene.add( ambientLight, mainLight );
}
function createMeshes() {
const geometry = new THREE.BoxBufferGeometry( 2, 2, 2 );
const material = new THREE.MeshStandardMaterial( { color: 0x800080 } );
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
}
function createRenderer() {
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( container.clientWidth, container.clientHeight );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.gammaFactor = 2.2;
renderer.gammaOutput = true;
renderer.physicallyCorrectLights = true;
container.appendChild( renderer.domElement );
}
// perform any updates to the scene, called once per frame
// avoid heavy computation here
function update() {
// Don't delete this function!
}
// render, or 'draw a still image', of the scene
function render() {
renderer.render( scene, camera );
}
// a function that will be called every time the window gets resized.
// It can get called a lot, so don't put any heavy computation in here!
function onWindowResize() {
// set the aspect ratio to match the new browser window aspect ratio
camera.aspect = container.clientWidth / container.clientHeight;
// update the camera's frustum
camera.updateProjectionMatrix();
// update the size of the renderer AND the canvas
renderer.setSize( container.clientWidth, container.clientHeight );
}
window.addEventListener( 'resize', onWindowResize );
// call the init function to set everything up
init();
Problem is here maybe I do something wrong.
const loader = new GLTFLoader();
const url = "./assets/models/test.glb";
// Here, 'gltf' is the object that the loader returns to us
const onLoad = ( gltf ) => {
console.log( gltf );
};
loader.load( url, onLoad );
I've been thinking about a problem with the path
I tried :
'/src/assets/models/test.glb'
'assets/models/test.glb'
Here is my folder structure:
Thx for your time
In your code import the model like this
import MODEL from './assets/Horse.glb'
Model will be the path to the glb asset then use it to load like this:
loader.load( MODEL, function ( glb ) {
that.scene.add( glb.scene );
}, undefined, function ( error ) {
console.error( error );
});
I found a solution discourse.threejs.org
const parcelPath = new URL('./public/models/hands.glb', import.meta.url);
loader.load( parcelPath.href , function ( glb ) {
that.scene.add( glb.scene );
});

three.js mtl loader renders black

I am trying to add a level .obj for my program but it renders black. The .mtl file requires several images placed everywhere (not one space is non-textured). I used to same object in my last project and it works, but it doesn't in my current project. When I remove the materials the lighting affects it, but when I add it, it is pitch black. The renderer renders continously. Also, there are no errors in the console.
Here is the code used in my current project: (MaterialLoader is an MTLLoader instance and ObjectLoader is an OBJLoader instance)
MaterialLoader.load("bbb/bbb.mtl",
function(materials) {
materials.preload()
ObjectLoader.setMaterials(materials)
ObjectLoader.load("bbb.obj",
function(model) {
let mesh = model.children[0]
scene.add(mesh)
}, null, function(error) {alert(error)}
)
}, null, function(error) {alert(error)}
)
Here is the code from my previous project (the loader variable is an OBJLoader instance, and the materials load successfully here.)
mtlLoader.load(
"bbb.mtl",
function(materials) {
materials.preload()
loader.setMaterials(materials)
loader.load("bbb.obj",
function(obj) {
level = obj.children[0]
scene.add(level)
}, null,
function(error) { alert(error) }
)
}, null,
function(error) { alert(error) }
)
https://discourse.threejs.org/t/objloader-mtlloader-not-loading-texture-image/2534
try change object material color, like this:
model.children[0].material.color.r = 1;
model.children[0].material.color.g = 1;
model.children[0].material.color.b = 1;
its work for me
Your code works when tested! Maybe it's an issue with the material export, uv unwrapping, the texture's path, do you have lighting added to the scene, etc. Here's my test code:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75,320/240,1,500);
camera.position.set( 0,2,2 );
camera.lookAt( scene.position );
var lightIntensity = 1;
var lightDistance = 10;
var light = new THREE.AmbientLight( 0xFFFFFF, lightIntensity, lightDistance );
light.position.set( 0, 5, 0 );
scene.add( light );
var grid = new THREE.GridHelper(10,10);
scene.add( grid );
var renderer = new THREE.WebGLRenderer({});
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( 320,240 );
renderer.domElement.style.margin = '0 auto';
renderer.domElement.style.display = 'block';
renderer.domElement.style.backgroundColor = '#dddddd';
$(document.body).append(renderer.domElement);
function update(){
renderer.render( scene, camera );
requestAnimationFrame( update );
}
update();
mtl_loader = new THREE.MTLLoader();
mtl_loader.load("assets/doughnut.mtl",
function(materials) {
materials.preload()
var obj_loader = new THREE.OBJLoader();
obj_loader.setMaterials(materials)
obj_loader.load("assets/doughnut.obj",
function(object) {
let mesh = object.children[0]
scene.add(mesh);
}, null, function(error) {alert(error)}
)
}, null, function(error) {alert(error)}
);

I'm trying to make a skybox, but I must be missing something fundamental

I am trying to make a skybox, and every tutorial I have tried will not work. I thought I could make an array and pass it as a param for the material like I saw in an earlier example, but the method has apparently changed to TextureLoader() since then. Below is my code:
// Adds a skybox around the content
var skyBoxMaterials = [
new THREE.MeshBasicMaterial( { map: new THREE.TextureLoader( 'images/skybox/sky1.jpg') }),
new THREE.MeshBasicMaterial( { map: new THREE.TextureLoader( 'images/skybox/sky2.jpg') }),
new THREE.MeshBasicMaterial( { map: new THREE.TextureLoader( 'images/skybox/sky3.jpg') }),
new THREE.MeshBasicMaterial( { map: new THREE.TextureLoader( 'images/skybox/sky4.jpg') }),
new THREE.MeshBasicMaterial( { map: new THREE.TextureLoader( 'images/skybox/sky5.jpg') }),
new THREE.MeshBasicMaterial( { map: new THREE.TextureLoader( 'images/skybox/sky6.jpg') }),
];
var skyBoxGeom = new THREE.CubeGeometry( 10000, 10000, 10000, 1, 1, 1);
skyBox = new THREE.Mesh( skyBoxGeom, skyBoxMaterials );
skyBox.position.set(0, 25.1, 0);
scene.add( skyBox );
When I run it currently, I get the error "Uncaught TypeError: Cannot read property 'x' of undefined" in the console infinitely looping until the server is killed. I could not find the exact answer in the examples, docs, or in another question, here. Any suggestions?
UPDATE: After some more digging, I finally found the example I needed in the docs under cubeGeometry, but it still does not render. My code is below:
// Adds a skybox around the content
var loader = new THREE.CubeTextureLoader();
loader.setPath( 'images/skybox/' );
var textureCube = loader.load( [
'sky1.jpg', 'sky2.jpg',
'sky3.jpg', 'sky4.jpg',
'sky5.jpg', 'sky6.jpg'
] );
var skyMaterials = new THREE.MeshBasicMaterial( { color: 0xffffff, envMap:
textureCube } );
var skyBoxGeom = new THREE.CubeGeometry( 10000, 10000, 10000, 1, 1, 1);
skyBox = new THREE.Mesh( skyBoxGeom, skyMaterials );
skyBox.position.set(0, 25.1, 0);
scene.add( skyBox );
I do not have any error messages in the console, but the cube is not rendering at all. The other objects in the scene render normally.
You can use .background property of THREE.Scene() straight, as it accepts cube textures.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.set( 0, 0, 300 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var controls = new THREE.OrbitControls( camera, renderer.domElement );
var loader = new THREE.CubeTextureLoader();
loader.setCrossOrigin( "" );
loader.setPath( 'https://threejs.org/examples/textures/cube/skybox/' );
var cubeTexture = loader.load( [
'px.jpg', 'nx.jpg',
'py.jpg', 'ny.jpg',
'pz.jpg', 'nz.jpg'
] );
scene.background = cubeTexture;
render();
function render() {
requestAnimationFrame(render);
renderer.render( scene, camera );
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
Have you downloaded the Three.js Master file? It has all the examples in working order. So all the examples you see on the Examples Page are there along with support files, textures assets etc. This way, you can start your project with a working example and build from there. You will need to run them from your local server (from your post, I gather you already know this).
There are a few examples that may help you like Panorama Cube. In the examples directory of the download, you will find a file called 'webgl_panorama_cube.html' that will be your local copy of this example.

Trouble with merging model with materials in three.js

I have in this fiddle an example of the problem I'm having: http://jsfiddle.net/saward/78Bjk/7/
If you uncomment scene.add(tree_mesh) and scene.add(mesh2), and comment out scene.add(mesh) then you can see both objects. But when I merge both, the material information for tree_mesh seems to be lost. If I modify the mesh to use the same material as mesh2, then both objects display but obviously with the wrong material.
I would appreciate help in understanding what's going on here and how to fix it!
Thanks
Here is the code from the fiddle (requires three.js r57):
var camera, scene, renderer, geometry, material, mesh1, mesh2, mesh;
init();
animate();
function init() {
var tree = {
"metadata" :
{
"formatVersion" : 3.1,
"sourceFile" : "tree.obj",
"generatedBy" : "OBJConverter",
"vertices" : 24,
"faces" : 18,
"normals" : 0,
"colors" : 0,
"uvs" : 0,
"materials" : 1
},
"scale" : 1.000000,
"materials": [ {
"DbgColor" : 15658734,
"DbgIndex" : 0,
"DbgName" : "Material",
"colorAmbient" : [0.0, 0.0, 0.0],
"colorDiffuse" : [0.64, 0.64, 0.64],
"colorSpecular" : [0.5, 0.5, 0.5],
"illumination" : 2,
"opticalDensity" : 1.0,
"specularCoef" : 96.078431,
"transparency" : 1.0
}],
"vertices": [1.000000,-1.000000,-1.000000,1.000000,-1.000000,1.000000,-1.000000,-1.000000,1.000000,-1.000000,-1.000000,-1.000000,0.590806,-0.802478,-0.590806,0.590806,-0.802478,0.590807,-0.590806,-0.802478,0.590806,-0.590806,-0.802478,-0.590806,0.406036,0.737103,-0.406036,0.406036,0.737103,0.406036,-0.406036,0.737103,0.406036,-0.406036,0.737103,-0.406036,0.406036,-0.810673,-0.406036,0.406036,-0.810673,0.406036,-0.406036,-0.810673,0.406036,-0.406036,-0.810673,-0.406036,-0.703524,0.091037,0.703524,-0.703524,0.091037,-0.703524,0.703524,0.091037,-0.703524,0.703524,0.091037,0.703524,-0.703524,1.498086,0.703524,-0.703524,1.498086,-0.703524,0.703524,1.498086,-0.703524,0.703524,1.498086,0.703524],
"morphTargets": [],
"morphColors": [],
"normals": [],
"colors": [],
"uvs": [[]],
"faces": [3,0,1,2,3,0,3,4,7,6,5,0,3,0,4,5,1,0,3,1,5,6,2,0,3,2,6,7,3,0,3,4,0,3,7,0,3,12,8,9,13,0,3,13,9,10,14,0,3,14,10,11,15,0,3,15,11,8,12,0,3,8,9,10,11,0,3,15,14,13,12,0,3,20,21,17,16,0,3,21,22,18,17,0,3,22,23,19,18,0,3,23,20,16,19,0,3,16,17,18,19,0,3,23,22,21,20,0]
};
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.z = 500;
scene.add(camera);
geometry = new THREE.CubeGeometry(200, 200, 200);
material = new THREE.MeshNormalMaterial();
var loader = new THREE.JSONLoader();
var tree_obj = loader.parse(tree, null);
var tree_materials = tree_obj.materials;
var tree_face_materials = new THREE.MeshFaceMaterial(tree_materials);
var tree_geo = tree_obj.geometry;
var tree_mesh = new THREE.Mesh(tree_geo, tree_face_materials);
tree_mesh.scale.x = tree_mesh.scale.y = tree_mesh.scale.z = 100;
mesh2 = new THREE.Mesh(geometry, material);
mesh2.position.y = 200;
console.log(tree_mesh.scale);
//scene.add(tree_mesh);
//scene.add(mesh2);
materials = [];
THREE.GeometryUtils.setMaterialIndex(tree_mesh.geometry, 0);
THREE.GeometryUtils.setMaterialIndex(mesh2.geometry, 1);
materials.push(tree_face_materials);
materials.push(material);
var new_geo = new THREE.Geometry();
THREE.GeometryUtils.merge(new_geo, tree_mesh);
THREE.GeometryUtils.merge(new_geo, mesh2);
mesh = new THREE.Mesh(new_geo, new THREE.MeshFaceMaterial(materials));
scene.add(mesh);
renderer = new THREE.CanvasRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
mesh.rotation.x += 0.01;
mesh.rotation.y += 0.02;
renderer.render(scene, camera);
}
Update: The way I specifically solved this was by using the current dev version of three.js 58, to add the materials for each model to a larger array.
As noted by the accepted answer, you can't use MeshFaceMaterial as a material, so iterate over all the materials within the MeshFaceMaterial, adding them in order.
Then note the index of the first material in the larger array for each model. Then when it comes time to merge the meshes, instead of using setMaterialIndex, give it the index of the first material in the array for that specific model. Along these lines:
THREE.GeometryUtils.merge(large_geo, some_mesh, some_mesh.material_offset);
large_mesh = new THREE.Mesh(large_geo, new THREE.MeshFaceMaterial(materials_list));
Where "some_mesh.material_offset" will be a new value you set and store for yourself somewhere. This will not work with r57 or lower.
When using MeshFaceMaterial( materials ), then materials must be an array of materials. You can't include MeshFaceMaterial as one of the materials.
In your case, it would be:
materials = [];
materials.push( tree_obj.materials[0] );
materials.push( material );
mesh = new THREE.Mesh( new_geo, new THREE.MeshFaceMaterial( materials ) );
Fiddle: http://jsfiddle.net/78Bjk/8/
three.js r.57

MeshFaceMaterial/ JSON material error

My model loads fine with this code:
loader.load( "js/charWalk01.js", function( geometry, materials ) {
mesh = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial() );
scene.add( mesh );
} );
However, when I try to use the MeshFaceMaterial (so as to use the material in the JSON file), I get two really odd three.min.js error messages (below).
loader.load( "js/charWalk01.js", function( geometry, materials ) {
materials[ 0 ].morphTargets = true;
mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial() );
scene.add( mesh );
} );
The errors are:
TypeError: 'undefined' is not an object (evaluating 'a.map') three.min.js:347
TypeError: 'undefined' is not an object (evaluating 'ma.attributes') three.min.js:429
The JSON file is perfectly normal (created with the OBJ converter), here's the material code from it:
"materials": [ {
"DbgColor" : 15658734,
"DbgIndex" : 0,
"DbgName" : "Mat.1",
"colorDiffuse" : [1.0, 1.0, 1.0],
"colorSpecular" : [0.4, 0.52, 0.53],
"illumination" : 4,
"mapDiffuse" : "Character_01.jpg"
}],
Any help as to why those errors might appear?
Cheers,
Ian
You need to pass materials as an argument to MeshFaceMaterials, like so:
loader.load( "js/charWalk01.js", function( geometry, materials ) {
materials[ 0 ].morphTargets = true;
mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( materials ) );
scene.add( mesh );
} );
three.js r.53

Categories