Adding a texture to a skinned mesh - javascript

I have Imported a simple extruded cube with 2 bones and a material from blender to threejs using the threejs exporter.
The model, material and bones export are fine. I can rotate the bones and the mesh and material are manipulated correctly.
Issue: When I apply a texture to the mesh then model disappears with following error.
type error material is undefined.
<html>
<head>
</head>
<body>
<script src="js/three.min.js"></script>
<script src="js/three.js"></script>
<script>
var scene,camera,renderer;
var skinnedMesh=[];
var material=[];
var texture=[];
var flag=0;
init();
function init()
{
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize( window.innerWidth, window.innerHeight-125 );
document.body.appendChild( renderer.domElement );
//////////
// CAMERA//
//////////
camera = new THREE.PerspectiveCamera( 70, window.innerWidth/Window.innerHeight, 1, 2000 );
camera.position.z = 15;
scene= new THREE.Scene();
scene.add(camera);
var loader = new THREE.JSONLoader;
loader.load('blockbone.js',loadmesh);
//////////
// LIGHT//
//////////
var light2 = new THREE.SpotLight(0xffffff);
light2.position.set(500,50,3000);
scene.add(light2);
render();
}
function loadmesh(geometry,material) {
//texture=(new THREE.MeshPhongMaterial( { map:
//THREE.ImageUtils.loadTexture( "10.png" ) }));
//texture.needsUpdate = true;
//material[0] = new THREE.MeshFaceMaterial(texture);
skinnedMesh = new THREE.SkinnedMesh(geometry,material[0]);
geometry.dynamic = true;
material[0].skinning = true;
scene.add(skinnedMesh);
}
function render()
{
scene.traverse(function(child){
if (child instanceof THREE.SkinnedMesh)
{
if (child.skeleton.bones[1].rotation.y<=1.5 && flag==0)
{
child.skeleton.bones[1].rotation.y +=.02;
}
else
{
flag=1;
}
if (child.skeleton.bones[1].rotation.y>=-3 && flag==1)
{
child.skeleton.bones[1].rotation.y -=.02;
}
else
{
flag=0;
}
child.skeleton.bones[0].rotation.y -=.01;
}
});
renderer.render(scene, camera);
requestAnimationFrame(render);
}
</script>
</body>
</html>
I have only manipulated textures on manually created meshes. Please suggest/advise what is going wrong.

I have solved this issue. The json file that I had exported from blender to use with Threejs was incomplete. In order to add an external texture to an externely loaded skinned mesh you must first add a texture in blender so that blender generates a UV map then export the json file.
Once the UV map is exported with json file you can then change the texture of the model.
Hope this helps other people.

Related

HTML not rendering my basic three.js code

im a bit of a noob when it comes to three.js and html but ive created other js files and they would import into the html page just fine but im confused why my basic box copy pasta code isnt showing up on the page. it works fine when scripting it all in html but not when import the js file in the same folder. could yall help me understand whats going on?
index.js
/*import * as THREE from 'three'
const canvas=document.querySelector('.webgl')
const scene = new THREE.Scene();
const geo = new THREE.BoxGeometry(1,1,1)
const mats = new THREE.MeshBasicMaterial({
color:'red'
})
const boxmesh=new THREE.Mesh(geo,mats)
scene.add(boxmesh)
const camera = new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,100)
camera.position.set(0,1,2)
scene.add(camera)
const renderer=new THREE.WebGL1Renderer({
canvas:canvas
})
renderer.setSize(window.innerWidth,window.innerHeight)
renderer.setPixelRatio(Math.min(window.devicePixelRatio,2))
renderer.shadowMap.enabled=true
renderer.gammaOutput=true
renderer.render(scene, camera)*/
import * as THREE from 'three';
// init
const camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 10 );
camera.position.z = 1;
const scene = new THREE.Scene();
scene.background= new THREE.Color('black')
const geometry = new THREE.BoxGeometry( 0.2, 0.2, 0.2 );
const material = new THREE.MeshNormalMaterial();
const mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setAnimationLoop( animation );
document.body.appendChild( renderer.domElement );
// animation
function animation( time ) {
mesh.rotation.x = .1;
mesh.rotation.y = .1;
renderer.render( scene, camera );
}
animation()
index.html
<!DOCTYPE html>
<html>
<head>
<meta name="learning html" content="This is learing making websites">
<title>Learing GLTF</title>
<script src="index.js"></script>
</head>
<body>
<canvas class="webgl"></canvas>
?
</body>
</html>
When using the latest versions of three.js(e.g. r140), then it's important to define an import map in your HTML. Otherwise the import import * as THREE from 'three'; does not work. A import map is required so the bare module specifier three can be resolved in browsers. For testing, try it with:
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three#0.140/build/three.module.js"
}
}
</script>

Issue with getting colors in a Blender imported mesh to be shown using Three.js

I am trying to display glued cubes, imported from blender, using Three.js.
I am using latest Version of Three.js and Blender 2.78a.
I started by making my cube object;just like this:
https://www.jonathan-petitcolas.com/2015/07/27/importing-blender-modelized-mesh-in-threejs.html
But I have different/more glued cubes.
I created above 3d object in Blender, Then exported the mesh using the Three.js .js exporter.
Here is the marmelab.json file.
{
"metadata":{
"generator":"io_three",
"faces":6,
"type":"Geometry",
"version":3,
"materials":1,
"normals":6,
"vertices":24,
"uvs":1
},
"faces":[43,8,10,12,14,0,0,1,2,3,0,0,0,0,43,16,18,20,22,0,3,0,1,2,1,1,1,1,43,9,15,19,17,0,3,0,1,2,2,2,2,2,43,1,13,21,5,0,3,0,1,2,3,3,3,3,43,3,11,23,7,0,3,0,1,2,4,4,4,4,43,2,0,4,6,0,3,0,1,2,5,5,5,5],
"materials":[{
"DbgIndex":0,
"blending":"NormalBlending",
"opacity":1,
"depthWrite":true,
"visible":true,
"transparent":false,
"colorEmissive":[0,0,0],
"colorDiffuse":[0.8,0.432941,0],
"wireframe":false,
"DbgName":"01 - Default",
"specularCoef":11,
"colorSpecular":[0.18,0.18,0.18],
"DbgColor":15658734,
"depthTest":true,
"shading":"phong"
}],
"normals":[0,0,1,0,0,-1,0,1,-0,1,0,-0,0,-1,-0,-1,0,-0],
"name":"Untitled.001Geometry.1",
"vertices":[-0.307576,-0,-0.433258,-0.002776,-0,-0.433258,-0.307576,-0,-0.738058,-0.002776,-0,-0.738058,-0.307576,0.3048,-0.433258,-0.002776,0.3048,-0.433258,-0.307576,0.3048,-0.738058,-0.002776,0.3048,-0.738058,-0.307576,-0,-0.433258,-0.307576,-0,-0.433258,-0.307576,-0,-0.738058,-0.307576,-0,-0.738058,-0.002776,-0,-0.738058,-0.002776,-0,-0.738058,-0.002776,-0,-0.433258,-0.002776,-0,-0.433258,-0.307576,0.3048,-0.433258,-0.307576,0.3048,-0.433258,-0.002776,0.3048,-0.433258,-0.002776,0.3048,-0.433258,-0.002776,0.3048,-0.738058,-0.002776,0.3048,-0.738058,-0.307576,0.3048,-0.738058,-0.307576,0.3048,-0.738058],
"uvs":[[1,0,1,1,0,1,0,0]]
}
javascript to load the mesh and display
var scene, camera, renderer;
var WIDTH = window.innerWidth;
var HEIGHT = window.innerHeight;
var SPEED = 0.01;
function init() {
scene = new THREE.Scene();
initMesh();
initCamera();
initLights();
initRenderer();
document.body.appendChild(renderer.domElement);
}
function initCamera() {
camera = new THREE.PerspectiveCamera(70, WIDTH / HEIGHT, 1, 10);
camera.position.set(0, 3.5, 5);
camera.lookAt(scene.position);
}
function initRenderer() {
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(WIDTH, HEIGHT);
}
function initLights() {
var light = new THREE.AmbientLight(0xffffff);
scene.add(light);
}
var mesh = null;
function initMesh() {
var loader = new THREE.JSONLoader();
loader.load('./marmelab.json', function(geometry, materials) {
mesh = new THREE.Mesh(geometry, new THREE.MeshFaceMaterial(materials));
mesh.scale.x = mesh.scale.y = mesh.scale.z = 0.75;
mesh.translation = THREE.GeometryUtils.center(geometry);
scene.add(mesh);
});
}
function rotateMesh() {
if (!mesh) {
return;
}
mesh.rotation.x -= SPEED * 2;
mesh.rotation.y -= SPEED;
mesh.rotation.z -= SPEED * 3;
}
function render() {
requestAnimationFrame(render);
rotateMesh();
renderer.render(scene, camera);
}
init();
render();
However in Browser the shape is rtained ; but the color is white.
What am I missing here?
Thank you so much in advance.
EDIT
I updated the Plunker with the latest version of three.js and it now works with your unedited json above - http://plnkr.co/edit/RwkgzrvfqzYlWtShhpjt?p=preview
Also successfully tested with my own, more complicated, model - http://plnkr.co/edit/SWXv1GyKIGryORiNYlgx?p=preview
The problem is caused by using an older version of three.js. I originally tested using the version provided by the website you linked to. I suspect you might have done the same given the result.
Somewhere around revision 70 they changed the exporter to no longer export the colorAmbient property, and that older version of Three.js required it.

Three.js unexpected render result?

Created the following mesh in blender:
Whenever I load it into three.js I receive the following result:
I export to .obj format and triangulate all of my faces. Not sure why this is happening. Below is the threejs code I am using to render the mesh. I use the same code with other meshes and they render as expected. I'm guessing I've done something that three.js doesn't like with this mesh?
<!DOCTYPE html>
<html>
<head>
<title></title>
<script type="text/javascript" src="/js/three.js"></script>
<script type="text/javascript" src="/js/DDSLoader.js"></script>
<script type="text/javascript" src="/js/MTLLoader.js"></script>
<script type="text/javascript" src="/js/OBJLoader.js"></script>
<script type="text/javascript" src="/js/OrbitControls.js"></script>
<script type="text/javascript" src="/js/stats.js"></script>
<script type="text/javascript" src="/js/dat.gui.js"></script>
<style>
body {
/* set margin to 0 and overflow to hidden, to go fullscreen */
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<div id="Stats-output">
</div>
<!-- Div which will hold the Output -->
<div id="WebGL-output">
</div>
<!-- Javascript code that runs our Three.js examples -->
<script type="text/javascript">
function init() {
var stats = initStats();
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.x = 130;
camera.position.y = 40;
camera.position.z = 50;
camera.lookAt(scene.position);
scene.add(camera);
// create a render and set the size
var webGLRenderer = new THREE.WebGLRenderer();
//webGLRenderer.setPixelRatio( window.devicePixelRatio );
webGLRenderer.setClearColor(new THREE.Color(0xffffff, 1.0));
webGLRenderer.setSize(window.innerWidth, window.innerHeight);
webGLRenderer.shadowMapEnabled = true;
var ambient = new THREE.AmbientLight( 0x444444 );
ambient.intensity = 5;
scene.add( ambient );
if('stiletto_switchblade_knife.mtl' !== ''){
THREE.Loader.Handlers.add( /\.dds$/i, new THREE.DDSLoader() );
var mtlLoader = new THREE.MTLLoader();
mtlLoader.setBaseUrl( '/assets/download/mesh/18/' );
mtlLoader.setPath( '/assets/download/mesh/18/' );
mtlLoader.load( 'stiletto_switchblade_knife.mtl', function( materials ) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials( materials );
objLoader.setPath( '/assets/download/mesh/18/' );
objLoader.load( 'stiletto_switchblade_knife.obj', function ( object ) {
//object.scale.set(100, 100, 100);
//object.rotation.x = -0.3;
scene.add( object );
});
});
} else {
var objLoader = new THREE.OBJLoader();
objLoader.setPath( '/assets/download/mesh/18/' );
objLoader.load( 'stiletto_switchblade_knife.obj', function ( object ) {
object.material = new THREE.MeshLambertMaterial({color: 0xFFFFFF});
//object.scale.set(100, 100, 100);
//object.rotation.x = -0.3;
scene.add( object );
});
}
// add the output of the renderer to the html element
document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);
var controls = new THREE.OrbitControls(camera, webGLRenderer.domElement );
render();
// simple render
function render() {
stats.update();
controls.update();
requestAnimationFrame(render);
webGLRenderer.render(scene, camera);
}
function initStats() {
var stats = new Stats();
stats.setMode(0); // 0: fps, 1: ms
// Align top-left
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
document.getElementById("Stats-output").appendChild(stats.domElement);
return stats;
}
}
window.onload = init;
</script>
</body>
</html>
EDIT
Are meshes required to be watertight in three.js? If so that could be the problem as there are a couple areas that are not in this mesh. That's the only thing I can think of at the moment that differs between this and the meshes that render properly.
Renders like that turned up with OBJ models in three.js R76. It turned out that any object containing a stray "l" (line) element blew up just like what you have shown. I found the bad objects by searching the ASCII OBJ file on "l ", got rid of the strays by selecting and hiding all of the faces, and dealing with whatever was left.
Solved. Turned out I had left a few faces drawn inside of the mesh. This was causing the unexpected behavior. Interesting debugging method. I just started stripping away vertices and rendering with threejs until I found the section that was causing the issue.

Copy/pasted JsonLoader from Threejs.org not working

So I am trying to get a JSONLoader to work from threejs.org
Three.js is working for sure because I have no problem creating a cube. But when I try to load a js file throuh JSONLoader then nothing happens.
<html>
<head>
<title>My first Three.js app</title>
<style>
body { margin: 0; }
canvas { width: 100%; height: 100% }
</style>
</head>
<body>
<script src="three.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( { alpha: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
// instantiate a loader
var loader = new THREE.JSONLoader();
// load a resource
loader.load(
// resource URL
'logo.js',
// Function when resource is loaded
function ( geometry, materials ) {
var material = new THREE.MultiMaterial( materials );
var object = new THREE.Mesh( geometry, material );
scene.add( object );
}
);
camera.position.z = 5;
var render = function () {
renderer.setClearColor( 0x000000, 0 );
requestAnimationFrame( render );
renderer.render(scene, camera);
};
render();
</script>
</body>
</html>
As mentioned in the title then the code is copy pasted from threejs own website and should be working.
Can someone help me figure what is going wrong?
here is a fiddle with the script of logo.js https://jsfiddle.net/380z6096/
the object has been exported from 3ds max with the 3ds Max JSExporter
I am using xampp and chrome.
Your camera is inside your geometry.
You can determine the dimensions of your geometry like so
geometry.computeBoundingSphere();
console.log( geometry.boundingSphere );
or
geometry.computeBoundingBox();
console.log( geometry.boundingBox );
Scale your geometry
object.scale.multiplyScalar( 0.01 );
Or move your camera back.
three.js r.75

JavaScript runtime error: Unable to get property 'geometries' of undefined or null reference when importing 3D models into a three.js viewport

I am trying to import my own 3D models into a three.js viewport but I keep getting this error:
0x800a138f - JavaScript runtime error: Unable to get property
'geometries' of undefined or null reference
My code:
<html>
<head>
<title>My first Three.js app</title>
<style>
body {
margin: 0;
}
canvas {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<script src="js/three.min.js"></script>
<script>
// Our Javascript will go here.
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 json = THREE.JSONLoader("teapot.js"); // I Think this loads the model
var loader = new THREE.JSONLoader();
var result = loader.parse(json, texturePath);
var mesh = new THREE.Mesh(result.geometry, result.materials);
scene.add(mesh);
camera.position.z = 5;
function render() {
requestAnimationFrame(render);
cube.rotation.x += 0.1;
cube.rotation.y += 0.1;
renderer.render(scene, camera);
}
render();
</script>
</body>
</html>
You're loading it wrong, when using the loader, first you declare the loader as such:
var loader = new THREE.JSONLoader();
Then you tell the loader to load your model, since this takes a while, you attach a function to handle adding it to the scene AFTER the loading is done
loader.load('path_to_model', function (geometry) {
var material = new THREE.MeshLambertMaterial({
//whatever material properties you want to use
});
// create a mesh with models geometry and material
var mesh = new THREE.Mesh(
geometry,
material
);
scene.add(mesh);
});
That should do the trick

Categories