Why aren't any texture on .obj-s? (Three.js) - three.js

I am working on an anatomy application based on three.js. Recently I am trying to visualize a skeleton and an ecorche model. Both of us are .obj-s with an .mtl file and there are jpeg files as textures. My problem is that my app visualize the two models but on the ecorche the are no textures and the skeleton is black. The problem is somewhere in the obj and mtl loader. I guess there is also an easier way to load the models.
The files of a model is in a separate folder.
My other question is how I can manage to make a button that change the actual model to the other one.
Thank you for your help!
Here is the code:
if (!Detector.webgl) {
Detector.addGetWebGLMessage();
}
var container;
var camera, controls, scene, renderer;
var lighting, ambient, keyLight, fillLight, backLight;
var windowDivideX = window.innerWidth / 3.4;
var files=['WorkAlpha.obj','untitled.mtl'];
init();
animate();
function init() {
container = document.createElement('viewer');
document.body.appendChild(container);
/*Creating Camera*/
camera = new THREE.PerspectiveCamera(45, windowDivideX /
window.innerHeight, 1, 100);
camera.position.y = 0;
camera.position.z = 40;
camera.position.x = 0;
/* Scene and Lights */
scene = new THREE.Scene();
lighting = false;
ambient = new THREE.AmbientLight(0xEAE1EA, 0.3);
scene.add(ambient);
keyLight = new THREE.DirectionalLight(0xEAE1EA, 0.6);
//(new THREE.Color('hsl(30, 80%, 0%)'), 1.0);
keyLight.position.set(-100, 0, 100);
fillLight = new THREE.DirectionalLight(0xEAE1EA, 0.6);
//(new THREE.Color('hsl(30, 80%, 0%)'), 0.6);
fillLight.position.set(100, 0, 100);
backLight = new THREE.DirectionalLight(0xffffff, 0.6);
backLight.position.set(100, 0, -100).normalize();
//ambient.intensity = 0.1;
scene.add(keyLight);
scene.add(fillLight);
scene.add(backLight);
/////////////////////////////////////////////////////////////////////////
/* Model */
var mtlLoader = new THREE.MTLLoader();
mtlLoader.setBaseUrl('assets/');
mtlLoader.setPath('assets/');
mtlLoader.load(files [0], function (materials) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials(materials);
objLoader.setPath('assets/');
objLoader.load('WorkAlpha.obj', function (object) {
object.position.y = 3;object.position.x = 0;
object.position.z = 0;
object.name = "muscles";
scene.add(object);
});
});
mtlLoader.setBaseUrl('skeleton/');
mtlLoader.setPath('skeleton/');
mtlLoader.load(files[1], function (materials) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials(materials);
objLoader.setPath('skeleton/');
objLoader.load('untitled.obj', function (object) {
object.position.y = -15;object.position.x = 0;
object.position.z = 0;
object.name = "skeleton";
scene.add(object);
});
});
/* Renderer */
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(windowDivideX, window.innerHeight);
renderer.setClearColor(0xC9D2D3);
container.appendChild(renderer.domElement);
/* Controls */
controls = new THREE.OrbitControls(camera,
renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.enableZoom = true;
controls.maxPolarAngle = Math.PI/2;
/* Events */
window.addEventListener('resize', onWindowResize, false);
window.addEventListener('keydown', onKeyboardEvent, false);
}
function onWindowResize() {
camera.aspect = windowDivideX / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(windowDivideX, window.innerHeight);
}
function onKeyboardEvent(e) {
if (e.code === 'KeyL') {
lighting = !lighting;
if (lighting) {
ambient.intensity = 0.25;
scene.add(keyLight);
scene.add(fillLight);
scene.add(backLight);
} else {
ambient.intensity = 1.0;
scene.remove(keyLight);
scene.remove(fillLight);
scene.remove(backLight);
}
}
}
function animate() {
requestAnimationFrame(animate);
controls.update();
render();
}
function render() {
renderer.render(scene, camera);
}
Here you can see the HTML:
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="three.js"></script>
<script src="Detector.js"></script>
<script src="OrbitControls.js"></script>
<script src="OBJLoader.js"></script>
<script src="MTLLoader.js"></script>
<script src="TrackballControls.js"></script>
<script
src="https://threejs.org/examples/js/renderers/Projector.js">
</script>
<script
src="https://threejs.org/examples/js/renderers/CanvasRenderer.js">
</script>
<link rel="stylesheet" href="bootstrap.min.css">
<script src="jquery.min.js"></script>
<script src="bootstrap.min.js"></script>
<link rel="stylesheet" type="text/css" href="design.css">
</head>
<body>
<script src="3d.js"></script>
</body>
</html>

Related

this.geometry is undefined when using tree-mesh-bvh accelerated raycasting and ifc.js

In a simple IFC.js application, loading IFC models (and fragments for that matter) fails with TypeError: this.geometry is undefined when accelerating the raycast using three-mesh-bvh. Removing that makes the application work again. I have tried with plenty of different IFC models, all of which work when removing the acceleration. Even the test models (Schependomlaan.ifc for example) fail when loading them.
Source of the app: https://github.com/gjkf/simple-ifc
app.js:
import { AmbientLight, AxesHelper, DirectionalLight, GridHelper, PerspectiveCamera, Scene, WebGLRenderer } from 'three';
import { acceleratedRaycast, computeBoundsTree, disposeBoundsTree } from 'three-mesh-bvh';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { IFCLoader } from 'web-ifc-three/IFCLoader';
//Creates the Three.js scene
const scene = new Scene();
//Object to store the size of the viewport
const size = {
width: window.innerWidth,
height: window.innerHeight,
};
//Creates the camera (point of view of the user)
const camera = new PerspectiveCamera(75, size.width / size.height);
camera.position.z = 15;
camera.position.y = 13;
camera.position.x = 8;
//Creates the lights of the scene
const lightColor = 0xffffff;
const ambientLight = new AmbientLight(lightColor, 0.5);
scene.add(ambientLight);
const directionalLight = new DirectionalLight(lightColor, 1);
directionalLight.position.set(0, 10, 0);
directionalLight.target.position.set(-5, 0, 0);
scene.add(directionalLight);
scene.add(directionalLight.target);
//Sets up the renderer, fetching the canvas of the HTML
const threeCanvas = document.getElementById("three-canvas");
const renderer = new WebGLRenderer({ canvas: threeCanvas, alpha: true });
renderer.setSize(size.width, size.height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
//Creates grids and axes in the scene
const grid = new GridHelper(50, 30);
scene.add(grid);
const axes = new AxesHelper();
axes.material.depthTest = false;
axes.renderOrder = 1;
scene.add(axes);
//Creates the orbit controls (to navigate the scene)
const controls = new OrbitControls(camera, threeCanvas);
controls.enableDamping = true;
controls.target.set(-2, 0, 0);
//Animation loop
const animate = () => {
controls.update();
renderer.render(scene, camera);
requestAnimationFrame(animate);
};
animate();
//Adjust the viewport to the size of the browser
window.addEventListener("resize", () => {
(size.width = window.innerWidth), (size.height = window.innerHeight);
camera.aspect = size.width / size.height;
camera.updateProjectionMatrix();
renderer.setSize(size.width, size.height);
});
//Sets up the IFC loading
const ifcLoader = new IFCLoader();
ifcLoader.ifcManager.useWebWorkers(true, "worker/IFCWorker.js");
ifcLoader.ifcManager.setWasmPath("../wasm/");
ifcLoader.ifcManager.applyWebIfcConfig({
USE_FAST_BOOLS: true,
COORDINATE_TO_ORIGIN: true,
});
ifcLoader.ifcManager.setupThreeMeshBVH(
acceleratedRaycast,
computeBoundsTree,
disposeBoundsTree
);
const input = document.getElementById("file-input");
input.addEventListener(
"change",
async (changed) => {
const ifcURL = URL.createObjectURL(changed.target.files[0]);
// ifcLoader.load(ifcURL, (ifcModel) => scene.add(ifcModel));
const model = await ifcLoader.loadAsync(ifcURL, (e) => console.log(e));
console.log(model);
scene.add(model);
},
false
);
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<title>IFC.js</title>
</head>
<body>
<input type="file" id="file-input" accept=".ifc, .ifcXML, .ifcZIP">
<canvas id="three-canvas"></canvas>
<script src="bundle.js"></script>
</body>
</html>
I made this simple application to nail down the problem, but in a different (Angular) project I would really need the accelerated raycasting to ensure the experience is smooth.
The problem was with your call to "setupThreeMeshBVH()"
This is a proper call with a proper sequence👇
ifcLoader.ifcManager.setupThreeMeshBVH(
computeBoundsTree,
disposeBoundsTree,
acceleratedRaycast
);
In your code, you had given "computeBoundsTree" as the second parameter whereas it should be first.

Annotation using three.js

I have two cubes of .obj file.The obj file is render on the browser. I want to do is as the user click on any of the cube or anywhere on the cube one prompt box display to add annotation to that place on the cube.How to do this? I am new to three.js. Anyone can help me out?
Here is my code with.obj file
<!DOCTYPE html>
<html>
<head>
<title>Mouse Picking</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="three.js"></script>
<script src="Detector.js"></script>
<script src="OrbitControls.js"></script>
<script src="OBJLoader.js"></script>
<script src="MTLLoader.js"></script>
<script src="DragControls.js"></script>
<style>
body {
overflow: hidden;
margin: 0;
padding: 0;
background: hsl(0, 0%, 10%);
}
</style>
</head>
<body>
<script>
if (!Detector.webgl) {
Detector.addGetWebGLMessage();
}
var container;
var camera, controls, scene, renderer;
var lighting, ambient, keyLight, fillLight, backLight;
var BlueCube, RedCube;
var objects = [];
init();
animate();
function init() {
container = document.createElement('div');
document.body.appendChild(container);
/* Camera */
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.x = 5;
camera.position.y = 3;
camera.position.z = 7;
/* Scene */
scene = new THREE.Scene();
lighting = true;
ambient = new THREE.AmbientLight(0xffffff, 2.5);
scene.add(ambient);
keyLight = new THREE.DirectionalLight(new THREE.Color('hsl(30, 100%, 75%)'), 1.0);
keyLight.position.set(-100, 0, 100);
fillLight = new THREE.DirectionalLight(new THREE.Color('hsl(240, 100%, 75%)'), 0.75);
fillLight.position.set(100, 0, 100);
backLight = new THREE.DirectionalLight(0xffffff, 1.0);
backLight.position.set(100, 0, -100).normalize();
/* Model */
var mtlLoader = new THREE.MTLLoader();
mtlLoader.setBaseUrl('assets/');
mtlLoader.setPath('assets/');
mtlLoader.load('mouse_picking.mtl', function (materials) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials(materials);
objLoader.setPath('assets/');
objLoader.load('mouse_picking.obj', function (object) {
scene.add( object );
objects.push( object );
});
});
raycaster = new THREE.Raycaster();
mouse = new THREE.Vector2();
/* Renderer */
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(new THREE.Color("hsl(0, 0%, 10%)"));
container.appendChild(renderer.domElement);
/* Controls */
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.enableZoom = false;
/* Events */
window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
//selected();
requestAnimationFrame(animate);
controls.update();
render();
}
function render() {
renderer.render(scene, camera);
}
</script>
</body>
</html>
I recommend that you subdivide the geometry of the cube mesh, and then use raycasting to determine the part of the scene (specifically, the triangle in the mesh) that was clicked. Then you could add a sprite object, which is a plane that always faces the camera, to display some text.
For more information, check out the collection of examples at http://stemkoski.github.io/Three.js/index.html - they are a little outdated, but the examples "Mouse Click" and "Sprite Text Labels" might help you to get started.

three.js r88 meshdepthmaterial there is no effect

I'm a new three.js men, and below is my code snippet...
In three.js docs said that the MeshDepthMaterial is drawing geometry by depth. Depth is based off of the camera near and far plane. White is nearest, black is farthest. But in my case, there is no effect for three.js r88, but three.js r 67. Can anybody please tell me why? Thanks very much...
<!DOCTYPE html>
<html>
<head>
<title>示例 04.02 - MeshDepthMaterial</title>
<script src="../build/three.js"></script>
<script src="../build/js/controls/OrbitControls.js"></script>
<script src="../build/js/libs/stats.min.js"></script>
<script src="../build/js/libs/dat.gui.min.js"></script>
<script src="../build/js/renderers/CanvasRenderer.js"></script>
<script src="../build/js/renderers/Projector.js"></script>
<script src="../jquery/jquery-3.2.1.min.js"></script>
<style>
body {
/* 设置 margin 为 0,并且 overflow 为 hidden,来完成页面样式 */
margin: 0;
overflow: hidden;
}
/* 统计对象的样式 */
#Stats-output {
position: absolute;
left: 0px;
top: 0px;
}
</style>
</head>
<body>
<!-- 用于 WebGL 输出的 Div -->
<div id="webgl-output"></div>
<!-- 用于统计 FPS 输出的 Div -->
<div id="stats-output"></div>
<!-- 运行 Three.js 示例的 Javascript 代码 -->
<script type="text/javascript">
var scene;
var camera;
var render;
var webglRender;
var canvasRender;
var controls;
var stats;
var guiParams;
var ground;
var cube;
var plane;
var sphere;
var meshMaterial;
var ambientLight;
var spotLight;
$(function() {
stats = initStats();
scene = new THREE.Scene();
scene.overrideMaterial = new THREE.MeshDepthMaterial({
morphTargets: true
});
webglRender = new THREE.WebGLRenderer( {antialias: true, alpha: true, logarithmicDepthBuffer: true} ); // antialias 抗锯齿
webglRender.setSize(window.innerWidth, window.innerHeight);
webglRender.setClearColor(0x000000, 1.0);
webglRender.shadowMap.enabled = true; // 允许阴影投射
render = webglRender;
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); // 2147483647
camera.position.set(-50, 40, 50);
var target = new THREE.Vector3(0, 0 , 0);
controls = new THREE.OrbitControls(camera, render.domElement);
controls.target = target;
camera.lookAt(target);
$('#webgl-output')[0].appendChild(render.domElement);
window.addEventListener('resize', onWindowResize, false);
ambientLight = new THREE.AmbientLight(0x000000);
scene.add(ambientLight);
/** 用来保存那些需要修改的变量 */
guiParams = new function() {
this.rotationSpeed = 0.02;
this.near = 2;
this.far = 50;
this.addCube = function() {
for (var i=0; i<100; i++) {
// 定义 cube 几何
var cubeGeometry = new THREE.BoxGeometry(5, 5, 5);
// 定义网格材质
meshMaterial = new THREE.MeshLambertMaterial({color: Math.random() * 0xffffff});
// 定义 cube 网格
cube = new THREE.Mesh(cubeGeometry, meshMaterial);
cube.castShadow = true;
cube.position.x = -60 + Math.round((Math.random() * 100));
cube.position.y = Math.round((Math.random() * 10));
cube.position.z = -100 + Math.round((Math.random() * 150));
// 默认加入 cube
scene.add(cube);
}
};
}
/** 定义 dat.GUI 对象,并绑定 guiParams 的几个属性 */
var gui = new dat.GUI();
gui.add(guiParams, 'addCube');
gui.add(guiParams, 'near', 0, 50).onChange(function(e) {
camera.near = e;
});
gui.add(guiParams, 'far', 5, 200).onChange(function(e) {
camera.far = e;
});
guiParams.addCube();
renderScene();
});
/** 渲染场景 */
function renderScene() {
stats.update();
rotateMesh(); // 旋转物体
requestAnimationFrame(renderScene);
render.render(scene, camera);
}
/** 初始化 stats 统计对象 */
function initStats() {
stats = new Stats();
stats.setMode(0); // 0 为监测 FPS;1 为监测渲染时间
$('#stats-output').append(stats.domElement);
return stats;
}
/** 当浏览器窗口大小变化时触发 */
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
render.setSize(window.innerWidth, window.innerHeight);
}
/** 旋转物体 */
function rotateMesh() {
scene.traverse(function(mesh) {
if (mesh instanceof THREE.Mesh) {
mesh.rotation.x += guiParams.rotationSpeed;
mesh.rotation.y += guiParams.rotationSpeed;
mesh.rotation.z += guiParams.rotationSpeed;
}
});
}
</script>
</body>
</html>
When you change camera.near or camera.far you need to call:
camera.updateProjectionMatrix();
three.js r.88

addEventListener: undefined is not a function

On my chrome browser, I've got an error:
undefined is not a function
at the line: dom.addEventListener( 'mouseup', onMouseUp, false);
I'm learning webGL and here is my actual code:
<html>
<head>
<?php include "header.php"?>
<title>Learning WebGL</title>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
<script type="text/javascript" src="/glmatrix/glMatrix.min.js"></script>
<script type="text/javascript" src="../three.min.js"></script>
<script type="text/javascript" src="../requestAnimationFrame.js"> </script>
<script>
var renderer = null,
scene = null,
camera = null,
cube = null,
animating = false;
function onload()
{
var container = document.getElementById("container");
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(container.offsetWidth, container.offsetHeight);
container.appendChild(renderer.domElement);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(45, container.offsetWidth/container.offsetHeight, 1, 4000);
camera.position.set(0,0,3);
var light = new THREE.DirectionalLight(0xffffff, 1.5);
light.position.set(0,0,1);
scene.add(light);
var mapUrl = "/test.jpg";
var map = THREE.ImageUtils.loadTexture(mapUrl);
var material = new THREE.MeshPhongMaterial({map: map});
var geometry = new THREE.CubeGeometry(1,1,1);
cube = new THREE.Mesh(geometry, material);
cube.rotation.x = Math.PI / 5;
cube.rotation.y = Math.PI / 5;
scene.add(cube);
addMouseHandler();
run();
}
function run()
{
renderer.render(scene,camera);
if(animating){
cube.rotation.y -= 0.01;
}
requestAnimationFrame(run);
}
function addMouseHandler()
{
var mydom = renderer.domElement;
mydom.addEventlistener('mouseup', onMouseUp, false);
}
function onMouseUp(event){
event.preventDefault();
animating = !animating;
}
</script>
</head>
<body onload="onload();">
<?php include "navigation.php"?>
<div id="container" style="width:95%; height:95%; position:absolute;">
</div>
<div id="prompt" style="width:95%; height:6%; bottom:0; position:absolute;">
Click to animate the cube
</div>
</body>
</html>
I've tried changing the variable name from "dom" to "mydom" but that doesn't help.
Many thanks!

THREE.js: OrbitControls pan and zoom issue

I tried adding the latest OrbitControls.js to my scene and orbit seams to work ok. However, when I zoom using the middle mouse button or scroll wheel the axis seams to be off and it no longer rotates correctly. Pan (or strafe) does not seem to work correctly in my scene either.
In the example, http://threejs.org/examples/#misc_controls_orbit right mouse button moves the camera parallel to the scene and in my scene it just orbits the same as left mouse button. You can see how mine is misbehaving http://www.xrez.com/tufa_test/.
<!DOCTYPE html>
<html lang="en">
<head>
<title>obj tester</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
background:#fff;
padding:0;
margin:0;
overflow:hidden;
font-family:georgia;
text-align:center;
}
</style>
</head>
<body>
<script src="cam.js"></script>
<script src="three.min.js"></script>
<script src="OrbitControls.js"></script>
<script>
var SCREEN_WIDTH = window.innerWidth;
var SCREEN_HEIGHT = window.innerHeight;
var container;
var camera, scene, controls, renderer;
var canvasRenderer, webglRenderer;
var mesh, zmesh, geometry;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
var meshes = [];
init();
animate();
function init() {
container = document.createElement('div');
document.body.appendChild(container);
camera = new THREE.PerspectiveCamera(75, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 100000);
camera.position.x = 400;
camera.position.y = 200;
camera.position.z = 400;
controls = new THREE.OrbitControls( camera );
controls.addEventListener( 'change', render );
scene = new THREE.Scene();
// LIGHTS
var ambient = new THREE.AmbientLight(0xFFFFFF);
scene.add(ambient);
// var directionalLight = new THREE.DirectionalLight(0x000000);
//directionalLight.position.set(0, 70, 100).normalize();
//scene.add(directionalLight);
// RENDERER
webglRenderer = new THREE.WebGLRenderer();
webglRenderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
webglRenderer.domElement.style.position = "relative";
container.appendChild(webglRenderer.domElement);
var loader = new THREE.JSONLoader(),
callbackKey = function(geometry) {createScene(geometry, 0, 0, 0, 15, "twe.jpg")};
loader.load("tufaWallEarly02_v3.js", callbackKey);
window.addEventListener('resize', onWindowResize, false);
}
function createScene(geometry, x, y, z, scale, tmap) {
zmesh = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({map: THREE.ImageUtils.loadTexture(tmap)}));
zmesh.position.set(x, y, z);
zmesh.scale.set(scale, scale, scale);
meshes.push(zmesh);
scene.add(zmesh);
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
webglRenderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
for(var i = 0; i < meshes.length; i++){
meshes[i].rotation.y += .001;
}
requestAnimationFrame(animate);
controls.update();
render();
}
function render() {
camera.lookAt(scene.position);
webglRenderer.render(scene, camera);
}
</script>
</body>
remove the camera.lookAt(scene.position); line
In OrbitControls.js line 219 find onMouseDown
and comment this lines
/*if ( event.button === 2 )
state = STATE.PAN;*/

Resources