Three.js - DOMException: "The operation is insecure." - most likely cross domain issue - three.js

I have implemented a three.js viewer for my panoramic pictures a couple of years ago and now that I'm moving my site to another location, I have an issue with Three.js not willing to load anymore.
Error message in the console:
DOMException: "The operation is insecure."
Here is the html part I'm using:
<div class="article-pano-gallery" style="display:table">
<img onclick="init('https://images.laurentwillen.be/sites/21/2017/05/photo-panoramique-360-Catane.jpg')" class="article-gallery-image pano-image" data-srcset="https://images.laurentwillen.be/sites/21/2017/05/photo-panoramique-360-Catane.jpg" src="https://images.laurentwillen.be/sites/21/2017/05/photo-panoramique-360-Catane-150x150.jpg" width="150" height="150">
</div>
And for the JS part:
<script async src="https://ajax.googleapis.com/ajax/libs/threejs/r84/three.min.js"></script>
<script>
var camera, scene, renderer;
var isUserInteracting = false,
onMouseDownMouseX = 0, onMouseDownMouseY = 0,
lon = 0, onMouseDownLon = 0,
lat = 0, onMouseDownLat = 0,
phi = 0, theta = 0;
function init(full_image)
{
var container, mesh;
container = document.getElementById( 'background-section' );
document.getElementById( 'background-section') .style.display='block';
document.getElementById( 'pano-loading-section') .style.display='block';
document.getElementById( 'close') .style.display='block';
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1100 );
camera.target = new THREE.Vector3( 0, 0, 0 );
scene = new THREE.Scene();
var geometry = new THREE.SphereBufferGeometry( 500, 60, 40 );
// invert the geometry on the x-axis so that all of the faces point inward
geometry.scale( - 1, 1, 1 );
var material = new THREE.MeshBasicMaterial( {
map: new THREE.TextureLoader().load( full_image )
} );
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth*0.95, window.innerHeight*0.95 );
container.appendChild( renderer.domElement );
document.addEventListener( 'mousedown', onPointerStart, false );
document.addEventListener( 'mousemove', onPointerMove, false );
document.addEventListener( 'mouseup', onPointerUp, false );
document.addEventListener( 'wheel', onDocumentMouseWheel, false );
document.addEventListener( 'touchstart', onPointerStart, false );
document.addEventListener( 'touchmove', onPointerMove, false );
document.addEventListener( 'touchend', onPointerUp, false );
document.addEventListener( 'dragover', function ( event )
{
event.preventDefault();
event.dataTransfer.dropEffect = 'copy';
}, false );
document.addEventListener( 'dragenter', function ()
{
document.body.style.opacity = 0.5;
}, false );
document.addEventListener( 'dragleave', function ()
{
document.body.style.opacity = 1;
}, false );
document.addEventListener( 'drop', function ( event )
{
event.preventDefault();
var reader = new FileReader();
reader.addEventListener( 'load', function ( event ) {
material.map.image.src = event.target.result;
material.map.needsUpdate = true;
}, false );
reader.readAsDataURL( event.dataTransfer.files[ 0 ] );
document.body.style.opacity = 1;
}, false );
//
window.addEventListener( 'resize', onWindowResize, false );
document.getElementById( 'pano-loading-section') .style.display='none';
animate();
}
function onWindowResize()
{
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth*0.95, window.innerHeight*0.95 );
}
function onPointerStart( event )
{
isUserInteracting = true;
var clientX = event.clientX || event.touches[ 0 ].clientX;
var clientY = event.clientY || event.touches[ 0 ].clientY;
onMouseDownMouseX = clientX;
onMouseDownMouseY = clientY;
onMouseDownLon = lon;
onMouseDownLat = lat;
}
function onPointerMove( event )
{
if ( isUserInteracting === true )
{
var clientX = event.clientX || event.touches[ 0 ].clientX;
var clientY = event.clientY || event.touches[ 0 ].clientY;
lon = ( onMouseDownMouseX - clientX ) * 0.1 + onMouseDownLon;
lat = ( clientY - onMouseDownMouseY ) * 0.1 + onMouseDownLat;
}
}
function onPointerUp()
{
isUserInteracting = false;
}
function onDocumentMouseWheel( event )
{
var fov = camera.fov + event.deltaY * 0.05;
camera.fov = THREE.Math.clamp( fov, 10, 75 );
camera.updateProjectionMatrix();
}
function animate()
{
requestAnimationFrame( animate );
update();
}
function update()
{
if ( isUserInteracting === false )
{
lon += 0.1;
}
lat = Math.max( - 85, Math.min( 85, lat ) );
phi = THREE.Math.degToRad( 90 - lat );
theta = THREE.Math.degToRad( lon );
camera.target.x = 500 * Math.sin( phi ) * Math.cos( theta );
camera.target.y = 500 * Math.cos( phi );
camera.target.z = 500 * Math.sin( phi ) * Math.sin( theta );
camera.lookAt( camera.target );
/*
// distortion
camera.position.copy( camera.target ).negate();
*/
renderer.render( scene, camera );
}
</script>
I was using the same script on another domain for images and it was working well but now that I have moved, it doesn't work anymore.
I suppose it has something to do with cross domain but I don't see where exactly. I have tried a local version of the JS file and it's the same issue.
The error in the JS occurs on line 121. Here is the full text as requested below:
DOMException: "The operation is insecure." three.js:121:396
texImage2D https://wp.laurentwillen.be/js/three.js:121
n https://wp.laurentwillen.be/js/three.js:97
setTexture2D https://wp.laurentwillen.be/js/three.js:181
hf https://wp.laurentwillen.be/js/three.js:7
upload https://wp.laurentwillen.be/js/three.js:343
G https://wp.laurentwillen.be/js/three.js:147
renderBufferDirect https://wp.laurentwillen.be/js/three.js:165
n https://wp.laurentwillen.be/js/three.js:134
render https://wp.laurentwillen.be/js/three.js:180
update https://wp.laurentwillen.be/circuits/circuit-italie/catane/?bb:1679
animate https://wp.laurentwillen.be/circuits/circuit-italie/catane/?bb:1659
Thanks

This is definitely a CORS issue. I recommend you get yourself acquainted with how modern browsers handle cross-domain requests.
My best guess is that your images.laurentwillen.be server isn't configured to allow delivering assets to other domains. This is a safety feature so other people don't steal your bandwidth (you probably wouldn't want 1000s of sites freeloading by using images hosted on your server).
There are 2 solutions to this problem:
Host the images in the same domain where they're being requested.
Figure out how to let your server allow delivery of images to the domain where you're using them. The way to achieve this depends on the type of server you're running and you'll have to do some digging to figure out how to configure it, so solution 1 would be easiest.

Related

m3u8 360 virtual reality video with Three js

Is there a way to play 360 video with Three js coming from m3u8 file?
I found a similar question here but no answer: https://github.com/mrdoob/three.js/issues/8216
https://threejs.org/examples/webgl_video_panorama_equirectangular.html
I have used the code from thee website for playing 360 video and this work fine when normal mp4 video url is used but when I try to include m3u8 then it fails with error.MEDIA_ERR_SRC_NOT_SUPPORTED:
The video could not be loaded, either because the server or network failed or because the format is not supported.
Here is the code:
<video id="video" width=960 height=540 style="display:none">
<source src="https://bitmovin.com/player-content/playhouse-vr/m3u8s/105560.m3u8" type="application/x-mpegURL">
</video>
var camera, scene, renderer;
var isUserInteracting = false,
lon = 0, lat = 0,
phi = 0, theta = 0,
distance = 50,
onPointerDownPointerX = 0,
onPointerDownPointerY = 0,
onPointerDownLon = 0,
onPointerDownLat = 0;
init();
animate();
function init() {
var container, mesh;
container = document.getElementById( 'container' );
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1100 );
camera.target = new THREE.Vector3( 0, 0, 0 );
scene = new THREE.Scene();
var geometry = new THREE.SphereBufferGeometry( 500, 60, 40 );
// invert the geometry on the x-axis so that all of the faces point inward
geometry.scale( - 1, 1, 1 );
var video = document.getElementById( 'video' );
video.play();
var texture = new THREE.VideoTexture( video );
var material = new THREE.MeshBasicMaterial( { map: texture } );
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'mouseup', onDocumentMouseUp, false );
document.addEventListener( 'wheel', onDocumentMouseWheel, false );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onDocumentMouseDown( event ) {
event.preventDefault();
isUserInteracting = true;
onPointerDownPointerX = event.clientX;
onPointerDownPointerY = event.clientY;
onPointerDownLon = lon;
onPointerDownLat = lat;
}
function onDocumentMouseMove( event ) {
if ( isUserInteracting === true ) {
lon = ( onPointerDownPointerX - event.clientX ) * 0.1 + onPointerDownLon;
lat = ( onPointerDownPointerY - event.clientY ) * 0.1 + onPointerDownLat;
}
}
function onDocumentMouseUp() {
isUserInteracting = false;
}
function onDocumentMouseWheel( event ) {
distance += event.deltaY * 0.05;
distance = THREE.MathUtils.clamp( distance, 1, 50 );
}
function animate() {
requestAnimationFrame( animate );
update();
}
function update() {
lat = Math.max( - 85, Math.min( 85, lat ) );
phi = THREE.MathUtils.degToRad( 90 - lat );
theta = THREE.MathUtils.degToRad( lon );
camera.position.x = distance * Math.sin( phi ) * Math.cos( theta );
camera.position.y = distance * Math.cos( phi );
camera.position.z = distance * Math.sin( phi ) * Math.sin( theta );
camera.lookAt( camera.target );
renderer.render( scene, camera );
}
m3u8 plays on chrome (and some other browsers). I have been using it for years. The problem is in combining m3u8 format with three js
m3u8 works as can be seen here: https://hls-js.netlify.app/demo/ enter this url : https://bitmovin.com/player-content/playhouse-vr/m3u8s/105560.m3u8
HLS (.m3u8 file type) and MPEG DASH (.mpd file type) are adaptive bit rate streaming protocols (ABR).
ABR creates multiple bit rate versions of your content and chunks them, so the client can choose the next chunk from the best bit rate for the device and current network conditions (https://stackoverflow.com/a/42365034/334402).
To play a HSL or DASH file you typically use a Javascript based video player, which in turn will leverage the HTML5 Media Soure Extension API - HTML5 MSE:
https://developer.mozilla.org/en-US/docs/Web/API/Media_Source_Extensions_API
The Javascript video player downloads the chunks of video, choosing the most appropriate bit rate for each chunk, and assembles them and passes them to the HTML5 video player.
Many Javascript Video Players will support 360 video and you may find it is easier to simply integrate one of these into your project. As an example, extensions to the commonly used videoJS player will support 360 video:
https://github.com/videojs/videojs-vr

glb/gltf Model not loading on Netlify, but loads locally

I am using Three.js with the gltf loader to load a single .glb resource onto a page. It works locally, though then I upload to Netlify the model does not load and the xhr progressEvent's total is 0. I checked that the model is still being loaded in the network tab, but yet it still does not show in the page.
It seems this problem has occurred before, but not sure how to resolve it when using Netlify if there are any environment variables I need to change.
https://github.com/mrdoob/three.js/issues/15584
HTML
<div class="model-wrapper">
<div id="model_target" class="loading">
<div class="myimage fade" id="placeholder">
<img src="images/placeholder.png" height="328px"/></div>
</div>
</div>
<!-- THREE.js -->
<script src="https://threejs.org/build/three.js"></script>
<!-- GLTFLoader.js -->
<script src="https://cdn.rawgit.com/mrdoob/three.js/r92/examples/js/loaders/GLTFLoader.js"></script>
JS
```
let camera, scene, renderer;
const mouse = new THREE.Vector2();
const look = new THREE.Vector2();
const windowHalf = new THREE.Vector2( window.innerWidth /
2, window.innerHeight / 2 );
var plane = new THREE.Plane(new THREE.Vector3(0, 0, 0.4),
-9);
var raycaster = new THREE.Raycaster();
var pointOfIntersection = new THREE.Vector3();
let modelLoaded = false;
let placement = document.getElementById("model_target")
window.addEventListener('DOMContentLoaded', init);
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 60, 1, 1, 1000);
camera.position.set(5, 3, 28)
//camera.position.y = 13;
var light = new THREE.DirectionalLight("#fff", 1.5);
var ambient = new THREE.AmbientLight("#FFF");
light.position.set( 0, -70, 100 ).normalize();
scene.add(light);
// scene.add(ambient);
var texture = new THREE.Texture();
var loader = new THREE.GLTFLoader();
THREE.Cache.enabled = true;
// Load a glTF resource
loader.load(
// 3d model resource
'./assets/models/mrktechy3.glb',
// called when the resource is loaded
function ( gltf ) {
mesh = gltf.scene;
mesh.scale.set( 5, 5, 5 );
scene.add( mesh );
},
// called when loading is in progress
function ( xhr ) {
// Loading progress of model
console.log(xhr);
console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
if((xhr.loaded / xhr.total * 100) == 100){
modelLoaded = true;
//Loading overlay
var placeholder = document.getElementById("placeholder");
placeholder.classList.add("faded");
placement.classList.remove("loading");
}
},
// called when loading has errors
function ( error ) {
console.log( 'An error happened' );
}
);
//scene.background = new THREE.Color(0xfff); //Set background color
renderer = new THREE.WebGLRenderer( { alpha: true, antialias: true } );
renderer.setSize( 800, 500 );
placement.appendChild( renderer.domElement );
renderer.setClearColor(0x000000, 0);
renderer.gammaOutput = true;
document.addEventListener( 'mousemove', onMouseMove, false );
window.addEventListener( 'resize', onResize, false );
render()
}
function onMouseMove( event ) {
if (modelLoaded){
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 0;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 0;
raycaster.setFromCamera(mouse, camera);
raycaster.ray.intersectPlane(plane, pointOfIntersection);
mesh.lookAt(pointOfIntersection);
}
}
function onResize( event ) {
const width = 800 ;
const height = 500;
windowHalf.set( width / 2, height / 2 );
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize( width, height );
}
var easeAmount = 8;
function update(){
look.x += (mouse.x-look.x)/easeAmount;
look.y += (mouse.y-look.y)/easeAmount;
raycaster.setFromCamera(look, camera);
raycaster.ray.intersectPlane(plane, pointOfIntersection);
mesh.lookAt(pointOfIntersection);
}
function render() {
camera.aspect = renderer.domElement.clientWidth / renderer.domElement.clientHeight;
camera.updateProjectionMatrix();
requestAnimationFrame( render );
if (modelLoaded){
update();
}
renderer.render( scene, camera );
}
```
Any glb resource can be replaced in the code and it works locally but not when hosted.
In the IIS settings, try to add mime type for gltf. Something like this:
application/gltf-buffer .gltf
This solved my problem.

three.js, tween camera and mousemove event

I'm trying my hands on three.js
I am moving the camera using a tween, and it works quite good.
At the end of the animation, however, the camera jumps back to its initial position.
I found out that the mousemove event was causing that behavior.
How can i fix this problem and keep both the tween movement and the mouse move?
I have constructed my three.js based on this example;
Mousemove declared inside render function
function render() {
camera.position.x += ( mouseX - camera.position.x ) * 0.04;
camera.position.y += ( - mouseY - camera.position.y ) * 0.04;
camera.lookAt( scene.position );
TWEEN.update();
renderer.render( scene, camera );
}
Tween movement
function setupTween (position, target, duration) {
TWEEN.removeAll();
new TWEEN.Tween (position)
.to (target, duration)
.easing (TWEEN.Easing.Quadratic.InOut)
.onUpdate (
function() {
// copy incoming position into camera position
camera.position.copy (position);
})
.start();
};
tween function source
UPDATE
Complete working code:
<script>
var container,
i,
camera,
scene,
renderer,
particles,
geometry,
materials = [],
color,
sprite,
size,
mouseX = 0,
mouseY = 0,
isTweening,
windowHalfX = window.innerWidth / 2,
windowHalfY = window.innerHeight / 2;
// +++++ three.js +++++
// +++++ +++++ +++++ +++++ +++++
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.5, 2000 );
camera.position.set (0,0,1900);
scene = new THREE.Scene();
scene.fog = new THREE.FogExp2( 0x000000, 0.0005 );
geometry = new THREE.Geometry();
var textureLoader = new THREE.TextureLoader();
for ( i = 0; i < 1000; i ++ ) {
var vertex = new THREE.Vector3();
vertex.x = Math.random() * 2000 - 1000;
vertex.y = Math.random() * 2000 - 1000;
vertex.z = Math.random() * 2000 - 1000;
geometry.vertices.push( vertex );
}
sprite = textureLoader.load( "circle.png" );
color = [0.90, 0.05, 0.8];
size = 8.5;
materials = new THREE.PointsMaterial( { size: size, map: sprite, blending: THREE.AdditiveBlending, depthTest: false, transparent : false } );
materials.color.setHSL( color[0], color[1], color[2] );
particles = new THREE.Points( geometry, materials );
scene.add( particles );
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onDocumentMouseMove( event ) {
mouseX = event.clientX - windowHalfX;
mouseY = event.clientY - windowHalfY;
}
function animate() {
requestAnimationFrame( animate );
render();
}
function startTween() {
isTweening = false;
var target = new THREE.Vector3(getRandomNumber(), getRandomNumber(), getRandomNumber());
new TWEEN.Tween (camera.position.clone())
.to (target, 1000)
.easing (TWEEN.Easing.Quadratic.InOut)
.onUpdate( function() {
camera.position.copy(this);
})
.onStart ( function() {
isTweening = true;
})
.onComplete ( function() {
isTweening = false;
})
.start();
}
function getRandomNumber() {
// get a number between -1000 and -500 and 500 and 1000
return ( Math.random() * 500 + 500 ) * ( Math.random() < 0.5 ? -1 : 1 );
}
function render() {
if(!isTweening && (mouseX || mouseY)) {
// more a generic approach, not just transforming x and y (maybe it needs to be improved a bit)
var upVector = camera.up.clone().transformDirection(camera.matrix);
var forwardVector = new THREE.Vector3().subVectors(scene.position, camera.position).normalize();
var rightVector = new THREE.Vector3().crossVectors(forwardVector, upVector);
camera.translateOnAxis(rightVector, mouseX);
camera.translateOnAxis(upVector, -mouseY);
mouseX = mouseY = 0;
}
camera.lookAt( scene.position );
TWEEN.update();
renderer.render( scene, camera );
}
init();
animate();
setTimeout(function(){
startTween();
},2500);
</script>
I think, you should only update the position by the mousemove event, when it's not tweening. So you need to check if its currently tweening or not.
var isTweening = false;
new TWEEN.Tween (camera.position)
.to (target, duration)
.easing (TWEEN.Easing.Quadratic.InOut)
.onStart ( function() {
isTweening = true;
})
.onComplete ( function() {
isTweening = false;
})
.start();
// in your render loop
function render() {
if (!isTweening) {
camera.position.x += ( mouseX - camera.position.x ) * 0.04;
camera.position.y += ( - mouseY - camera.position.y ) * 0.04;
}
camera.lookAt( scene.position );
TWEEN.update();
renderer.render( scene, camera );
}
You don't need to set an onUpdate function and copy the new position to camera.position. You can just pass over camera.position to the tween and it will work.
EDIT:
I didn't see the link to example. Now, I know which kind of navigation is used (which is actually used in a lot of three.js examples). It's not the mousemove event that is causing your problem, it's this kind of calculating the new camera position (camera.position.x += ( mouseX - camera.position.x ) * 0.04;). So, I changed the code of the example a bit, especially the navigation. Here are the important parts:
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
function onDocumentMouseMove( event ) {
mouseX = (event.movementX * 0.5) || event.mozMovementX || event.webkitMovementX || 0;
mouseY = (event.movementY * 0.5) || event.mozMovementY || event.webkitMovementY || 0;
}
function render() {
if(!isTweening && (mouseX || mouseY)) {
// more a generic approach, not just transforming x and y (maybe it needs to be improved a bit)
var upVector = camera.up.clone().transformDirection(camera.matrix);
var forwardVector = new THREE.Vector3().subVectors(scene.position, camera.position).normalize();
var rightVector = new THREE.Vector3().crossVectors(forwardVector, upVector);
camera.translateOnAxis(rightVector, mouseX);
camera.translateOnAxis(upVector, -mouseY);
mouseX = mouseY = 0;
}
camera.lookAt( scene.position );
TWEEN.update();
}
function startTween() {
isTweening = false;
var target = new THREE.Vector3(getRandomNumber(), getRandomNumber(), getRandomNumber());
new TWEEN.Tween (camera.position.clone())
.to (target, 1000)
.easing (TWEEN.Easing.Quadratic.InOut)
.onUpdate( function() {
camera.position.copy(this);
})
.onStart ( function() {
isTweening = true;
})
.onComplete ( function() {
isTweening = false;
})
.start();
}
function getRandomNumber() {
// get a number between -1000 and -500 and 500 and 1000
return ( Math.random() * 500 + 500 ) * ( Math.random() < 0.5 ? -1 : 1 );
}
And you are right about TWEEN.onUpdate: you need to copy the new values to camera.position. My earlier approach do also work, but then all of the functionality of THREE.Vector3 gets lost. I didn't realize that until now.

Three.js, OBJLoader -> Uncaught ReferenceError: object is not defined

My code below.
When I uncomment
object.rotation.y += ( targetRotation - object.rotation.y ) * 0.05; from render() or animate() function I get "Uncaught ReferenceError: object is not defined " error.
I tried anything, my animate() function is even in loader callback, I tried changing three.js to older version (currently using r59), hoped var object = event.content; might solve it, no effect.
I want to add "click and move your mouse to rotate model" usability, I have no problems with that when its cube.
but it just won't work with my *obj.
Help? =)
var scene, camera, renderer, loader, ambient, directionalLight;
var windowHalfX = 300;
var windowHalfY = 145;
var targetRotation = 0;
var targetRotationOnMouseDown = 0;
var mouseX = 0;
var mouseXOnMouseDown = 0;
init();
function init() {
container = document.createElement( 'div' );
document.getElementById("3dbox").appendChild(container);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 45, 600 / 290, 0.1, 1000 );
//camera.position.set( -15, 10, 15 );
renderer = new THREE.WebGLRenderer();
renderer.setSize( 600, 290 );
container.appendChild( renderer.domElement );
// MODEL
var loader = new THREE.OBJMTLLoader();
loader.addEventListener( 'load', function ( event ) {
var object = event.content;
scene.add( object );
animate();
});
loader.load( '<?php bloginfo('template_directory'); ?>/obj/female02.obj', '<?php bloginfo('template_directory'); ?>/obj/female02.mtl' );
camera.position.z = 100;
camera.position.y = 10;
ambient = new THREE.AmbientLight( 0x101030 );
scene.add( ambient );
directionalLight = new THREE.DirectionalLight( 0xffeedd );
directionalLight.position.set( 0, 0, 1 );
scene.add( directionalLight );
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
document.addEventListener( 'touchstart', onDocumentTouchStart, false );
document.addEventListener( 'touchmove', onDocumentTouchMove, false );
}
function render() {
//object.rotation.y += ( targetRotation - object.rotation.y ) * 0.05;
renderer.render(scene, camera);
}
function animate() {
//object.rotation.y += ( targetRotation - object.rotation.y ) * 0.05;
requestAnimationFrame( animate );
render();
}
function onDocumentMouseDown( event ) {
event.preventDefault();
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'mouseup', onDocumentMouseUp, false );
document.addEventListener( 'mouseout', onDocumentMouseOut, false );
mouseXOnMouseDown = event.clientX - windowHalfX;
targetRotationOnMouseDown = targetRotation;
}
function onDocumentMouseMove( event ) {
mouseX = event.clientX - windowHalfX;
targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.02;
}
function onDocumentMouseUp( event ) {
document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
}
function onDocumentMouseOut( event ) {
document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
}
function onDocumentTouchStart( event ) {
if ( event.touches.length === 1 ) {
event.preventDefault();
mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX;
targetRotationOnMouseDown = targetRotation;
}
}
function onDocumentTouchMove( event ) {
if ( event.touches.length === 1 ) {
event.preventDefault();
mouseX = event.touches[ 0 ].pageX - windowHalfX;
targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05;
}
}
It is because "object" is a local variable in your callback function. Decare it globally:
var object;
Then in your callback,
object = event.content;
three.js r.59

THREE.js can not rotate object

I am attempting to rotate an object I uploaded along its y axis. The object uploads and the material is applied. I have used the same code to rotate a sphere but it does not seem to work with a custom object. If I un-comment the line at the bottom that is supposed to handle the actual rotation, the image no longer shows up as if there is an error.
Web GL Test
body {
font-family: Monospace;
background-color: #f0f0f0;
margin: 0px;
overflow: hidden;
}
<script src="js/three.min.js"></script>
<script src="js/OBJLoader.js"></script>
<script type="text/javascript">
var container, stats;
var camera, scene, renderer;
var targetRotation = 0;
var targetRotationOnMouseDown = 0;
var mouseX = 0;
var mouseXOnMouseDown = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.y = 200;
camera.position.z = 150;
scene = new THREE.Scene();
var loader = new THREE.OBJLoader();
loader.addEventListener( 'load', function ( event ) {
var object = event.content;
var geom = new THREE.SphereGeometry( 100, 50, 50 );
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.material.map = texture;
}
} );
object.position.y = 150;
scene.add( object );
});
loader.load( 'Head.obj' );
var texture = THREE.ImageUtils.loadTexture('face.gif');
texture.needsUpdate = true;
renderer = new THREE.CanvasRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
document.addEventListener( 'touchstart', onDocumentTouchStart, false );
document.addEventListener( 'touchmove', onDocumentTouchMove, false );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
//
function onDocumentMouseDown( event ) {
event.preventDefault();
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'mouseup', onDocumentMouseUp, false );
document.addEventListener( 'mouseout', onDocumentMouseOut, false );
mouseXOnMouseDown = event.clientX - windowHalfX;
targetRotationOnMouseDown = targetRotation;
}
function onDocumentMouseMove( event ) {
mouseX = event.clientX - windowHalfX;
targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.02;
}
function onDocumentMouseUp( event ) {
document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
}
function onDocumentMouseOut( event ) {
document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
}
function onDocumentTouchStart( event ) {
if ( event.touches.length === 1 ) {
event.preventDefault();
mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX;
targetRotationOnMouseDown = targetRotation;
}
}
function onDocumentTouchMove( event ) {
if ( event.touches.length === 1 ) {
event.preventDefault();
mouseX = event.touches[ 0 ].pageX - windowHalfX;
targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05;
}
}
//
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
//object.rotation.y += ( targetRotation - object.rotation.y ) * 0.05;
renderer.render( scene, camera );
}
</script>
</body>
The problem is that you use the variable "object" in the animate function before it is initialized. Also the variable "object" has a scope limited to the callback function of the loader.
You might want to read something about javascript variable scope.
http://www.mredkj.com/tutorials/reference_js_intro_ex.html
To solve your problem you might to change a few things.
1) Make the variable "object" global
// Make object a global variable
var camera, scene, renderer, object;
2) Do not call the animate function before the object is initialized
init();
//animate();
3) Do not use "var" inside callback function of the loader
var loader = new THREE.OBJLoader();
loader.addEventListener( 'load', function ( event ) {
//var object = event.content;
object = event.content;
var geom = new THREE.SphereGeometry( 100, 50, 50 );
4) Call "animate" after "object" is initialized
object.position.y = 150;
scene.add( object );
// Call animate after object is loaded and added to the scene
animate();
5) Good luck ;)

Resources