I have loaded the .obj file and set the color to its details, but it only shows up all black
const loader = new OBJLoader();
loader.load( src, function ( obj ) {
obj.traverse( function ( child ) {
child.material.color.setHex(0xFF0000);
console.log("child.material.color: ", child.material.color);
}
}
scene.add(obj);
...
var hemiLight = new THREE.HemisphereLight( 0xffffff, 0x444444 );
hemiLight.position.set( 0, 300, 0 );
scene.add( hemiLight );
var dirLight = new THREE.DirectionalLight( 0xffffff );
dirLight.position.set( 75, 300, -75 );
scene.add( dirLight );
the console.log print out the object Color: {r: 1, g: 0, b: 0, isColor: true}
So, is there anything I have missed?
It looks to me like the way you have it, you're not actually adding it to the scene because 'obj' ref is only valid within the (async) callback.
If you move scene.add(obj) into your callback it should work.
I created a codepen:
https://codepen.io/flatworldstudio/pen/ExNpedV
Look for this bit:
loader.load(src, function (obj) {
console.log(obj);
scene.add(obj);
ref = obj;
obj.traverse(function (child) {
if (child.material) {
child.material.color.setHex(0xff0000);
console.log("child.material.color: ", child.material.color);
}
});
});
Related
camera.lookAt(myObject) will instantly rotate the three.js camera towards the given object.
I would like to animate this rotation using gsap. I have no problem using gsap to animate a change in camera position, but the camera rotation code below does nothing.
const targetOrientation = myObject.quaternion.normalize();
gsap.to({}, {
duration: 2,
onUpdate: function() {
controls.update();
camera.quaternion.slerp(targetOrientation, this.progress());
}
});
How can I animate a camera rotation in this way?
OK this is now fixed. The main problem was a controls.update() line in my render() function. Orbit controls do not work well with camera rotation so you need to make sure that they are completely disabled during the animation.
My revised code that includes rotation and position animations:
const camrot = {'x':camera.rotation.x,'y':camera.rotation.y,'z':camera.rotation.z}
camera.lookAt(mesh.position);
const targetOrientation = camera.quaternion.clone().normalize();
camera.rotation.x = camrot.x;
camera.rotation.y = camrot.y;
camera.rotation.z = camrot.z;
const aabb = new THREE.Box3().setFromObject( mesh );
const center = aabb.getCenter( new THREE.Vector3() );
const size = aabb.getSize( new THREE.Vector3() );
controls.enabled = false;
const startOrientation = camera.quaternion.clone();
gsap.to({}, {
duration: 2,
onUpdate: function() {
camera.quaternion.copy(startOrientation).slerp(targetOrientation, this.progress());
},
onComplete: function() {
gsap.to( camera.position, {
duration: 8,
x: center.x,
y: center.y,
z: center.z+4*size.z,
onUpdate: function() {
camera.lookAt( center );
},
onComplete: function() {
controls.enabled = true;
controls.target.set( center.x, center.y, center.z);
}
} );
}
});
Try it like so:
let mesh, renderer, scene, camera, controls;
init();
animate();
function init() {
// renderer
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setPixelRatio( window.devicePixelRatio );
document.body.appendChild( renderer.domElement );
// scene
scene = new THREE.Scene();
// camera
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set( 20, 10, 20 );
camera.lookAt( 0, 0, 0 );
// ambient
scene.add( new THREE.AmbientLight( 0x222222 ) );
// light
const light = new THREE.DirectionalLight( 0xffffff, 1 );
light.position.set( 20,20, 0 );
scene.add( light );
// axes
scene.add( new THREE.AxesHelper( 20 ) );
// geometry
const geometry = new THREE.SphereBufferGeometry( 5, 12, 8 );
// material
const material = new THREE.MeshPhongMaterial( {
color: 0x00ffff,
flatShading: true,
transparent: true,
opacity: 0.7,
} );
// mesh
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
const startOrientation = camera.quaternion.clone();
const targetOrientation = mesh.quaternion.clone().normalize();
gsap.to( {}, {
duration: 2,
onUpdate: function() {
camera.quaternion.copy(startOrientation).slerp(targetOrientation, this.progress());
}
} );
}
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
body {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.123/build/three.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.4.0/gsap.min.js"></script>
You have to ensure to call Quaternion.slerp() always with the start orientation and not with camera.quaternion. Otherwise the interpolation will be incorrect.
I've tried to add Bounding Box to my object but it seems to work only for the testObj, he does not work for my others objects with texture.
var testObj = new THREE.Mesh(
new THREE.CylinderGeometry( 1 , 1 , 4 , 8 ),
new THREE.MeshLambertMaterial({ color: 0xff00ff })
);
scene.add(testObj );
staticCollideMesh.push(testObj );
// PADDLE1
loaderTexture.load('http://localhost:8000/WoodTexture.jpg', function (texture ) {
var material = new THREE.MeshLambertMaterial( {
map: texture
});
var geometry = new THREE.BoxGeometry(PADDLE_WIDTH, PADDLE_HEIGHT, PADDLE_DEPTH );
paddle1 = new THREE.Mesh( geometry, material);
paddle1.castShadow = true;
paddle1.receiveShadow = true;
paddle1.name = "paddle1";
scene.add( paddle1 );
staticCollideMesh.push(paddle1);
}, undefined, function ( err ) {
console.error( 'WoodTexture1.jpg : An error happened.' );
}
);
This is how I add BBox and BoxHelper :
let constructCollisionBoxes = function() {
staticCollideMesh.forEach( function( mesh ){
mesh.BBox = new THREE.Box3().setFromObject( mesh );
mesh.BBoxHelper = new THREE.BoxHelper( mesh , 0xff0000 );
scene.add( mesh.BBoxHelper );
});
}
I don't know why the loop just apply for my cylinder ... I need help to understand why this is not working.
EDIT: thanks to #prisoner849 I just added the function in the loader
scene.add(paddle1);
staticCollideMesh.push(paddle1);
constructionCollisionMesh();
In case of using loaders, keep in mind, that loading is asynchronous, so when you call constructCollisionBoxes(), your box, whose creation relies on the moment of finishing of loading of the texture, is not in the staticCollideMesh array yet.
To fix it, you can do it this way:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
camera.position.set(0, 0, 10);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var light = new THREE.DirectionalLight(0xffffff, 1);
light.position.setScalar(1);
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, 0.25));
var staticCollideMesh = [];
var PADDLE_WIDTH = 3,
PADDLE_HEIGHT = 3,
PADDLE_DEPTH = 2;
var testObj = new THREE.Mesh(
new THREE.CylinderGeometry(1, 1, 4, 8),
new THREE.MeshLambertMaterial({
color: 0xff00ff
})
);
scene.add(testObj);
staticCollideMesh.push(testObj);
var texture = new THREE.TextureLoader().load(`https://threejs.org/examples/textures/uv_grid_opengl.jpg`);
// PADDLE1
var material = new THREE.MeshLambertMaterial({
map: texture
});
var geometry = new THREE.BoxGeometry(PADDLE_WIDTH, PADDLE_HEIGHT, PADDLE_DEPTH);
paddle1 = new THREE.Mesh(geometry, material);
paddle1.castShadow = true;
paddle1.receiveShadow = true;
paddle1.name = "paddle1";
scene.add(paddle1);
staticCollideMesh.push(paddle1);
let constructCollisionBoxes = function() {
staticCollideMesh.forEach(function(mesh) {
mesh.BBox = new THREE.Box3().setFromObject(mesh);
mesh.BBoxHelper = new THREE.BoxHelper(mesh, 0xff0000);
scene.add(mesh.BBoxHelper);
});
}
constructCollisionBoxes();
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
});
body {
overflow: hidden;
margin: 0;
}
<script src="https://unpkg.com/three#0.115.0/build/three.min.js"></script>
<script src="https://unpkg.com/three#0.115.0/examples/js/controls/OrbitControls.js"></script>
How remove of hide loaded.load three.js according to the condition for example id the door condition = 0, if will load the flame.stl and reverse
function checkDoorStatus(isDoorOpen, prevIsDoorOpen){
if ( isDoorOpen == 1)
{
var loader = new THREE.STLLoader();
loader.load( 'model/panic.stl', function ( geometry ) {
var material = new THREE.MeshPhongMaterial( { color: 0xa80306, specular: 0x111111, shininess: 200 } );
var mesh = new THREE.Mesh( geometry, material );
mesh.position.set( 0.145, -0.3, -0.29);
mesh.rotation.set( 0 , 0, Math.PI / 2 );
mesh.scale.set( 0.05, 0.05, 0.05);
mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add( mesh );
} );
//console.log("Panic 1");
}
else if (isDoorOpen == 0)
{
var loader = new THREE.STLLoader();
loader.load( 'model/flame.stl', function ( geometry ) {
var material = new THREE.MeshPhongMaterial( { color: 0xa80306, specular: 0x111111, shininess: 200 } );
var mesh = new THREE.Mesh( geometry, material );
mesh.position.set( 0.145, -0.3, -0.29);
mesh.rotation.set( 0 , 0, Math.PI / 2 );
mesh.scale.set( 0.05, 0.05, 0.05);
mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add( mesh );
} );
//console.log("Panic 0");
}
}
According to my understanding, you want to show only one mesh at a time based on some condition. If that is the case, one possible solution is give a name to your mesh before adding to the scene and remove the old door based on its name before adding the new one. For example
mesh.name = "openDoor";
scene.remove(scene.getObjectByName("closedDoor"));
scene.add( mesh )
Hope it helps.
I am trying to render some text onto a "fake 3D" backdrop (see my image link for a picture of what it looks like rendered), however when I rotate the text on the Z-axis to make the text look like it's a part of the fake 3D backdrop the text becomes distorted, almost looking italicized. I've tried rotation on the x and y axis as well to maybe change the depth perception but I can't get it to look right.
Anyone run into this or have thoughts?
Image:
Code:
var desiredWidthInCSSPixels = 1100;
var desiredHeightInCSSPixels = 700;
var scene = new THREE.Scene();
var renderer = new THREE.WebGLRenderer();
var texture_loader = new THREE.TextureLoader();
var font_loader = new THREE.FontLoader();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
renderer.setSize( desiredWidthInCSSPixels, desiredHeightInCSSPixels );
document.body.appendChild( renderer.domElement );
//this is the fake 3d backdrop "business cards"
texture_loader.load( "assets/images/mockups/mockup-1.png", function (texture) {
texture.minFilter = THREE.LinearFilter;
var geometry = new THREE.BoxGeometry( 800, 600, 0 );
var material = new THREE.MeshBasicMaterial( { map: texture } );
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );
});
//here's the company's logo
texture_loader.load( "assets/images/logo.svg", function (texture) {
texture.minFilter = THREE.LinearFilter;
var geometry = new THREE.BoxGeometry( 60, 60, 0 );
var material = new THREE.MeshBasicMaterial( { transparent: true, map: texture } );
var cube = new THREE.Mesh( geometry, [null, null, null, null, material, null] );
cube.rotation.z = -150.12;
cube.position.x = 60;
cube.position.y = -40;
scene.add( cube );
});
//the text loader that looks italicized
font_loader.load( 'assets/fonts/roboto_black_regular.json', function(font) {
var geometry = new THREE.TextGeometry( 'My test text looks italic!!!', {
font: font,
size: 5,
curveSegments: 12,
bevelEnabled: true,
bevelThickness: 3,
bevelSize: 8,
bevelSegments: 5
} );
var material = new THREE.MeshPhongMaterial({
color: 0xddd
});
var cube = new THREE.Mesh( geometry, [material, null, null, null, null, null] );
cube.position.x = 60;
cube.position.y = -40;
cube.position.z = 20;
cube.rotation.x = .12;
cube.rotation.z = -149.95;
scene.add( cube );
});
camera.position.z = 200;
var animate = function () {
requestAnimationFrame( animate );
renderer.render(scene, camera);
};
animate();
function xtest() {
cube.rotation.x += .01;
console.log(cube.rotation.x);
}
function ytest() {
cube.rotation.y += .01;
console.log(cube.rotation.y);
}
function ztest() {
cube.rotation.z += .01;
console.log(cube.rotation.z);
}
function x1test() {
cube.rotation.x -= .01;
console.log(cube.rotation.x);
}
function y1test() {
cube.rotation.y -= .01;
console.log(cube.rotation.y);
}
function z1test() {
cube.rotation.z -= .01;
console.log(cube.rotation.z);
}
taken from AlteredQualia demo:
map = THREE3.ImageUtils.loadTexture( "textures/terrain/grasslight-big.jpg" );
map.wrapS = map.wrapT = THREE3.RepeatWrapping;
map.repeat.set( 16, 16 );
var planeGeo = new THREE3.PlaneGeometry( 200, 200 );
ground = new THREE3.Mesh( planeGeo, new THREE3.MeshPhongMaterial( { color: 0xffffff, ambient: 0xffffff, specular: 0x111111, shininess: 50, map: map, perPixel: true, metal: true } ) );
I have extracted png data from an HTML canvas with ExtJS Ext.getDom('cnvs_img').src; into a var and the var string starts " data:image/png;base64, ..." so think it is valid. I want to use this data instead of loading from disk with loadTexture. Would appreciate some pointers, thanks.
THREE3.ImageUtils.loadTexture( imgVar ) does not work of course :-)
To load a texture from a dataURL, you can follow this pattern:
var image = document.createElement( 'img' );
image.src = dataURL;
image.onload = function() {
var texture = new THREE.Texture( image );
texture.needsUpdate = true; // important!
var material = new THREE.MeshLambertMaterial( {
color: 0xffffff,
map: texture
} );
var mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
};
three.js r.67