How to animate the gltf model with threejs - javascript

I have a cube model which is GLTF format, now i am trying to animate it by changing the textures material.
Now currently, there are 300 heat map images as the texture material, the requirement from supervisor is animating the cube model by loading heat map images one by one.
Texture materials set
About the animation, I tried to use VectorKeyFrameTrack to change the child.material. But it does not work.
the codes:
if (WEBGL.isWebGLAvailable() === false) {
document.body.appendChild(WEBGL.getWebGLErrorMessage());
}
var camera, scene, renderer;
init();
function init() {
//init scene
scene = new THREE.Scene();
scene.background = new THREE.Color(0x999999);
//add directional light and spotlight
var light = new THREE.DirectionalLight(0xffffff);
light.position.set(3, 15.0, -29).normalize();
scene.add(light);
var light1 = new THREE.DirectionalLight(0xffffff);
light.position.set(-20, 7.0, -2).normalize();
scene.add(light1);
var light2 = new THREE.DirectionalLight(0xffffff);
light.position.set(-5, 15.0, 30).normalize();
scene.add(light2);
var light3 = new THREE.DirectionalLight(0xffffff);
light.position.set(15, 5.0, -15).normalize();
scene.add(light3);
//add camera
camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 500);
camera.position.y = 5;
camera.position.z = 10;
scene.add(camera);
//add grid
var grid = new THREE.GridHelper(50, 50, 0xffffff, 0x555555);
scene.add(grid);
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
//Generate textures array
var loadedTexture = new THREE.TextureLoader().load("1.png");
var material = new THREE.MeshBasicMaterial({map: loadedTexture});
var loadedTexture2 = new THREE.TextureLoader().load("2.png");
var material1 = new THREE.MeshBasicMaterial({map: loadedTexture2});
//Load Collada file
var path = "./image/"
var format = ".png";
var a = "Avg_Displacement_";
var material_list = [];
var times = [];
for (var i = 0; i <= 314; i++) {
var loadedTexture = new THREE.TextureLoader().load(path + a + i + format);
var material = new THREE.MeshBasicMaterial({map: loadedTexture});
material_list.push(material);
times.push(i);
}
console.log(material_list);
var loader = new THREE.GLTFLoader();
loader.load('scene.gltf', function (gltf) {
gltf.scene.scale.set(0.3, 0.3, 0.3);
// console.log(gltf.scene.children[0].material);
// var kf = new THREE.VectorKeyframeTrack( '.scene.material', times, material_list );
// var clip = new THREE.AnimationClip('Action', 315, [kf]);
//
// mixer = new THREE.AnimationMixer(gltf);
// var clipAction = mixer.clipAction(clip);
// clipAction.play();
gltf.scene.traverse(function (child) {
if (child.isMesh) {
var kf = new THREE.VectorKeyframeTrack('child.material', times, material_list);
var clip = new THREE.AnimationClip('Action', 3, [kf]);
mixer = new THREE.AnimationMixer(child);
var clipAction = mixer.clipAction(clip);
clipAction.play()
// child.material = material;
}
scene.add(gltf.scene);
});
});
var controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.addEventListener('change', render);
controls.update();
window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
render();
}
function render() {
renderer.render(scene, camera);
}
// function animate() {
//
// requestAnimationFrame( animate );
//
// mesh.material.map.offset.x += 0.005;
// mesh.material.map.offset.y += 0.005;
//
// renderer.render( scene, camera );
//
// }
child.material
the second problem is how to animate the model by loading each image as the texture as material.

Related

3D object turning black on loading the mtl file

On loading the MTL file, the entire model is turning black. I have referred to this link and set the rbg parameters to 1 but that hasnt solved my issue.
three.js mtl loader renders black
Here is the code associated with it:
var scene = new THREE.Scene();
scene.background = new THREE.Color('0xf1f1f1');
var axesHelper = new THREE.AxesHelper( 5 );
scene.add( axesHelper );
const canvas = document.querySelector('#scene1');
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
camera.position.set(5,5,5);
scene.add(camera);
var renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var controls = new THREE.OrbitControls(camera, renderer.domElement);
//controls.autoRotate = true;
//controls.autoRotateSpeed = 5;
controls.enableZoom = true;
var keyLight = new THREE.DirectionalLight(new THREE.Color('hsl(30, 100%, 75%)'), 1.0);
keyLight.position.set(-100, 0, 100);
var fillLight = new THREE.DirectionalLight(new THREE.Color('hsl(240, 100%, 75%)'), 0.75);
fillLight.position.set(20, 20, 20);
var backLight = new THREE.DirectionalLight(0xffffff, 1.0);
backLight.position.set(20, 20, -20).normalize();
var ambientLight = new THREE.AmbientLight();
var pointLight = new THREE.PointLight(0xffffff,1,100);
pointLight.position.set(20,20,20);
var pointLight2 = new THREE.PointLight(0xffffff,0.5,100);
pointLight2.position.set(20,-20,20);
var pointLight3 = new THREE.PointLight(0xffffff,0.5,100);
pointLight3.position.set(-20,20,-20);
var pointLight4 = new THREE.PointLight(0xffffff,0.5,100);
pointLight4.position.set(-20,-20,-20);
//scene.add(ambientLight);
scene.add(pointLight);
scene.add(pointLight2);
scene.add(pointLight3);
scene.add(pointLight4);
//scene.add(keyLight);
//scene.add(fillLight);
//scene.add(backLight);
var mtlLoader = new THREE.MTLLoader();
//mtlLoader.setTexturePath('https://i.ibb.co/n1vnyP6/piper-diffuse.jpg');
mtlLoader.setPath('https://raw.githubusercontent.com/fnaseem/3dModelTest/tc/Test/');
mtlLoader.load('soccer_ball.mtl',function(material){
material.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials(material);
objLoader.load('https://raw.githubusercontent.com/fnaseem/3dModelTest/tc/Test/soccer_ball.obj', function(object){
object.position.set(0,0,0);
console.log(object.children[0].material.color);
object.children[0].material.color.r = 1;
object.children[0].material.color.g = 1;
object.children[0].material.color.b = 1;
console.log(object.children[0].material.color);
scene.add(object);
//renderer.render(scene, camera);
});
});
var animate= function(){
controls.update();
renderer.render( scene, camera );
requestAnimationFrame( animate );
};
animate();
Here is the link to the codepen:
https://codepen.io/FarhaNaseem/pen/gOmwbYj?editors=0010
What I am expecting is this output:
The MTL loads the texture as a TIFF image which can't be used as an image data source. Use JPG or PNG instead.
Sidenote: You will notice that the object's material has a texture assigned to the map property but with an undefined image value. In such a case, the texture appears black.

ThreeJs different Text on each face of cube

I'm working on Threejs to animate a cube with different text on each cube faces. I used DynamicTexture to place text on cube faces, but it places same text on each side of cube. I don't know how to place different text on each side. Is there any way to do is and place text on runtime by user inputs? Thanks.
Main.js
var scene = new THREE.Scene();
scene.background = new THREE.Color('white');
var camera = new THREE.PerspectiveCamera(50, window.innerWidth/window.innerHeight, 1, 1000);
camera.position.set(4, 4, 4);
camera.lookAt(0, 0, 0);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById('display').appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera);
var dynamictexture = new THREEx.DynamicTexture(512, 512);
dynamictexture.context.font = "bolder 90px verdana";
dynamictexture.texture.needsUpdate = true;
dynamictexture.clear('#d35400').drawText('Text', undefined, 256, 'green');
var geometry = new THREE.BoxGeometry(2, 2, 2);
var material = new THREE.MeshBasicMaterial({color: 0xffffff, map: dynamictexture.texture, opacity:1,
transparent: true});
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
function animate() {
requestAnimationFrame(animate);
controls.update();
dynamictexture.texture
renderer.render(scene, camera);
};
animate();
You can use THREE.MeshFaceMaterial(materials) to accomplish this. All you need to do is pass an array containing the materials and specifying the map for each of the faces.
var face_textures = [];
function createFaceTextures() {
var i;
for(i = 0; i < 6; i++) {
var dynamictexture = new THREEx.DynamicTexture(512, 512);
dynamictexture.context.font = "bolder 90px verdana";
dynamictexture.texture.needsUpdate = true;
dynamictexture.clear('#d35400').drawText(i.toString(), undefined, 256, 'green');
face_textures.push(dynamictexture);
}
}
createFaceTextures();
var scene = new THREE.Scene();
scene.background = new THREE.Color('white');
var camera = new THREE.PerspectiveCamera(50, window.innerWidth/window.innerHeight, 1, 1000);
camera.position.set(4, 4, 4);
camera.lookAt(0, 0, 0);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById('display').appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera);
var dynamictexture = new THREEx.DynamicTexture(512, 512);
dynamictexture.context.font = "bolder 90px verdana";
dynamictexture.texture.needsUpdate = true;
dynamictexture.clear('#d35400').drawText('Text', undefined, 256, 'green');
var geometry = new THREE.BoxGeometry(2, 2, 2,);
var material = new THREE.MeshBasicMaterial({color: 0xffffff, map: dynamictexture.texture, opacity:1, transparent: true});
var materials = [
new THREE.MeshBasicMaterial({map: face_textures[0].texture}),
new THREE.MeshBasicMaterial({map: face_textures[1].texture}),
new THREE.MeshBasicMaterial({map: face_textures[2].texture}),
new THREE.MeshBasicMaterial({map: face_textures[3].texture}),
new THREE.MeshBasicMaterial({map: face_textures[4].texture}),
new THREE.MeshBasicMaterial({map: face_textures[5].texture})
];
var cube = new THREE.Mesh(geometry, materials);
scene.add(cube);
function animate() {
requestAnimationFrame(animate);
controls.update();
dynamictexture.texture
renderer.render(scene, camera);
}
animate();

Why does "light.castShadow = true" cause my scene to break?

I am trying to build a simple solar system with sun, earth and moon, using threejs. The system includes lighting and shadows.
My only problem is, while creating the shadow that will be cast from earth to the moon and vice-versa, my script will stop working.
Console gives me an error of "isMultiSample is not defined".
I have tried searching the web but could not find any solutions to why the error would occur.
The part causing problems:
var sunLight = new THREE.PointLight(0x404040, 10, 1000000);
sunLight.position.set(0, 0, 0);
sunLight.castShadow = true; // This line will cause the error
Full code:
<script>
var camera, scene, renderer;
var spaceBox, sunPivot, earthPivot, moonPivot;;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 4000000 );
camera.position.z = 2400;
scene = new THREE.Scene();
// Surrounding space
var texture = new THREE.TextureLoader().load( 'space.jpg' );
var skygeometry = new THREE.BoxBufferGeometry( 15000, 15000, 15000 );
var skymaterial = new THREE.MeshBasicMaterial({ map: texture, side : THREE.DoubleSide});
spaceBox = new THREE.Mesh(skygeometry, skymaterial);
scene.add(spaceBox);
// Sun, earth and moon textures
var sunTexture = new THREE.TextureLoader().load('sun.jpg')
var sunGeometry = new THREE.SphereBufferGeometry(800, 32, 32);
var sunMaterial = new THREE.MeshPhongMaterial({ map: sunTexture });
var earthTexture = new THREE.TextureLoader().load('earth.jpg')
var earthGeometry = new THREE.SphereBufferGeometry(250, 32, 32);
var earthMaterial = new THREE.MeshPhongMaterial({ map: earthTexture, side: THREE.DoubleSide });
var moonTexture = new THREE.TextureLoader().load('moon.jpg')
var moonGeometry = new THREE.SphereBufferGeometry(80, 32, 32);
var moonMaterial = new THREE.MeshPhongMaterial({ map: moonTexture, side: THREE.DoubleSide });
// LIGHTS
var ambientLight = new THREE.AmbientLight(0x404040,3); // soft white light
scene.add(ambientLight);
var sunLight = new THREE.PointLight(0x404040, 10, 1000000);
sunLight.position.set(0, 0, 0);
//sunLight.castShadow = true;
sunLight.shadow.mapSize.width = 1024;
sunLight.shadow.mapSize.height = 1024;
sunLight.shadow.camera.near = 500;
sunLight.shadow.camera.far = 10000;
sunLight.shadow.camera.fov = 30;
scene.add(sunLight);
// Add sun, earth and moon rotating around eachother
sun = new THREE.Mesh(sunGeometry, sunMaterial);
scene.add(sun);
earthPivot = new THREE.Object3D();
sun.add(earthPivot);
earth = new THREE.Mesh(earthGeometry, earthMaterial);
earth.position.x = 4000;
earth.castShadow = true;
earth.receiveShadow = true;
earthPivot.add(earth);
moonPivot = new THREE.Object3D();
earth.add(moonPivot);
var moon = new THREE.Mesh(moonGeometry, moonMaterial);
moon.position.x = 750;
moon.castShadow = true;
moon.receiveShadow = true;
moonPivot.add(moon);
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
//
controls = new THREE.OrbitControls(camera, renderer.domElement);
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
earthPivot.rotation.y += 0.002;
moonPivot.rotation.y += 0.005;
requestAnimationFrame( animate );
controls.update();
renderer.render( scene, camera );
}</script>

zoom in the cube on page load using this javascript cube function

I have below code now when the page is loaded I want the cube to zoom out and stop ..how do i do that..i am new to 3js so have no idea..I want it to start off with a small cube and come u as a big cube and stop
<script>
//var resultlabel = (document.getElementById('resultvalue').innerHTML);
//if (resultlabel == 0) {
var container
var camera, controls, scene, renderer;
var objects = [];
var plane = new THREE.Plane();
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2(),
offset = new THREE.Vector3(),
intersection = new THREE.Vector3(),
INTERSECTED, SELECTED;
init();
animate();
function init() {
container = document.getElementById('canvas1');
camera = new THREE.PerspectiveCamera(70, container.offsetWidth / container.offsetHeight, 1, 10000);
//camera.position.z = 2000;
camera.position.set(3000, 3000, 3000);
//camera.position.set(1000, 1000, 1000);
controls = new THREE.TrackballControls(camera, container); //**
controls.rotateSpeed = 1.0;
controls.zoomSpeed = 1.2;
controls.panSpeed = 0.8;
controls.noZoom = false;
controls.noPan = false;
controls.staticMoving = true;
controls.dynamicDampingFactor = 0.3;
scene = new THREE.Scene();
var directionalLight = new THREE.DirectionalLight(0x505050);
scene.add(directionalLight);
//var resultlabel = (document.getElementById('resultvalue').innerHTML);
//if (resultlabel == 0) {
var geometry = new THREE.BoxGeometry(500, 500, 500);
var ax = ay = az = 0;
for (var i = 0; i < 1; i++) {
var object = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({ ambient: 0xffffff, map: THREE.ImageUtils.loadTexture('/imgs/12.jpg') }));
object.position.x = ax;
object.position.y = ay;
object.position.z = az;
object.scale.x = 2;
object.scale.y = 2;
object.scale.z = 2;
scene.add(object);
light = new THREE.DirectionalLight(0x666699);
light.position.set(0, 1, 0);
scene.add(light);
light = new THREE.DirectionalLight(0x666699);
light.position.set(0, -1, 0);
scene.add(light);
//back
light = new THREE.DirectionalLight(0x666699);
light.position.set(1, 0, 0);
scene.add(light);
// front
light = new THREE.DirectionalLight(0x666699);
light.position.set(-1, 0, 0);
scene.add(light);
//right
light = new THREE.DirectionalLight(0x666699);
light.position.set(0, 0, 1);
scene.add(light);
//left
light = new THREE.DirectionalLight(0x666699);
light.position.set(0, 0, -1);
scene.add(light);
objects.push(object);
}
var material = new THREE.MeshPhongMaterial({ map: THREE.ImageUtils.loadTexture('/1.png') });
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setClearColor(0xf0f0f0);
renderer.setPixelRatio(container.devicePixelRatio);
renderer.setSize(container.offsetWidth - 4, container.offsetHeight - 4);
renderer.sortObjects = false;
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFShadowMap;
container.appendChild(renderer.domElement);
stats = new Stats();
container.appendChild(stats.dom);
window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
render();
stats.update();
}
function render() {
controls.update();
renderer.render(scene, camera);
}
You can use THREE.Vector3.lerp to get a smooth animation.
Declare a vector3 where you want your camera to go:
var destPosition = new THREE.Vector3(1000,1000,1000);
and in your animation loop write:
camera.position = camera.position.lerp(destPosition, alpha);
where alpha is a value between 0 and 1 and determine how far the camera will travel each loop.
This is a quick trick to get it going and have some flaws, like you will never really get to the destPosition (just very very close). Read up on linear interpolation for a deeper understanding. Good luck!

ThreeJS - Intersection of a line and sphere

I have two objects on my scene: a red line and a sphere.
While camera rotating/zooming/moving, I need to check the following:
Does the line intersects with the sphere looking from the current position of the camera (please see images below)? Please use this JS fiddle that creates the scene on the images.
I know how to find the intersection between the current mouse position and objects on the scene (just like this example shows).
But how to do this in my case?
JS Fiddle Code:
/**
* PREPARE SCENE
*/
var mouse = {
x : 0,
y : 0
};
var projector = new THREE.Projector();
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75,
window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.x = -5;
camera.position.y = 5;
camera.position.z = 30;
var renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.TrackballControls(camera,
renderer.domElement);
controls.rotateSpeed = 3.0;
controls.zoomSpeed = 1.5;
controls.panSpeed = 1.0;
controls.staticMoving = true;
var grid = new THREE.GridHelper(20, 5);
scene.add(grid);
/**
* CREATE SPHERE
*/
var sphere = new THREE.Mesh(
new THREE.SphereGeometry(5, 10, 10),
new THREE.MeshNormalMaterial());
sphere.overdraw = true;
scene.add(sphere);
/**
* CREATE LINE
*/
var lineMaterial = new THREE.LineBasicMaterial({
color : 0xFF0000
});
var lineGeometry = new THREE.Geometry();
lineGeometry.vertices.push(new THREE.Vector3(8, 8, 8));
lineGeometry.vertices.push(new THREE.Vector3(8, 8, 20));
var line = new THREE.Line(lineGeometry, lineMaterial);
scene.add(line);
renderer.domElement.addEventListener('mousemove', render, false);
render();
function render(event) {
var mouse = {};
/*
* INTERSECTION
*/
if (event != null) {
//intersection job???
}
controls.update();
renderer.render(scene, camera);
}
So, I found the solution that is pretty simple (of course). See new JS Fiddle that checks intersection of the line and sphere and visualizes the ray for debugging.
The JS Fiddle code:
var camera, controls, scene, renderer;
init();
animate();
render();
function init() {
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.z = 800;
controls = new THREE.TrackballControls(camera);
controls.rotateSpeed = 5.0;
controls.zoomSpeed = 1.2;
controls.panSpeed = 4;
controls.noZoom = false;
controls.noPan = false;
controls.staticMoving = true;
controls.addEventListener('change', render);
// world
scene = new THREE.Scene();
sceneTarget = new THREE.Scene();
var grid = new THREE.GridHelper(500, 50);
scene.add(grid);
/**
* CREATE LINE
*/
var lineMaterial = new THREE.LineBasicMaterial({
color : 0xFF0000
});
var lineGeometry = new THREE.Geometry();
lineGeometry.vertices.push(new THREE.Vector3(100, 200, 100));
lineGeometry.vertices.push(new THREE.Vector3(300, 200, 200));
var line = new THREE.Line(lineGeometry, lineMaterial);
sceneTarget.add(line);
/*
* CREARE SPHERE
*/
var sphere = new THREE.Mesh(new THREE.SphereGeometry(150, 100, 100), new THREE.MeshNormalMaterial());
sphere.overdraw = true;
scene.add(sphere);
// renderer
renderer = new THREE.WebGLRenderer({
alpha: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.autoClear = false;
renderer.setClearColor(0xffffff, 1);
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
controls.update();
}
function render() {
renderer.render(scene, camera);
renderer.render(sceneTarget, camera);
intersect();
}
function intersect() {
var direction = new THREE.Vector3(100, 200, 100);
var startPoint = camera.position.clone();
var directionVector = direction.sub( startPoint );
var ray = new THREE.Raycaster(startPoint, directionVector.clone(). normalize());
scene.updateMatrixWorld(); // required, since you haven't rendered yet
var rayIntersects = ray.intersectObjects(scene.children, true);
if (rayIntersects[0]) {
//inersection is found
console.log(rayIntersects[0]);
//visualize the ray for debugging
var material = new THREE.LineBasicMaterial({
color: 0x0000ff
});
var geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3(ray.ray.origin.x, ray.ray.origin.y, ray.ray.origin.z));
geometry.vertices.push(new THREE.Vector3(100, 200, 100));
var line = new THREE.Line(geometry, material);
sceneTarget.add( line );
}
}

Categories

Resources