Hi i am loading a GLTF model in my scene. But the model looks too yellow i assume this has to do with the material. But i have no clue what is causing it, it is not the model itself since if i check it on donmccurdy's gltf viewer it looks perfect.
See a reference below:
GLTF Viewer:
And this is how the same model looks in my scene:
I have added an environment map to the scene this fixed may things but not the yellowness..
See current code below:
let scene, camera, renderer, controls;
let dummy = new THREE.Object3D();
let mat4 = new THREE.Matrix4();
const loader = new THREE.GLTFLoader();
let clock = new THREE.Clock();
function loadModel(url, callback) {
loader.load(
url,
function ( gltf ) {
const model = gltf.scene.children[0];
callback(model);
},
function ( xhr ) {
console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
},
function ( error ) {
console.log( 'An error happened', error );
}
);
}
function generateInstances(model, count) {
const geometry = model.geometry;
geometry.scale(0.1, 0.1, 0.1);
const material = model.material;
return new THREE.InstancedMesh(geometry, material, count);
}
function setInstancePositions(instances, startPos, counts, spacing) {
if(instances.count < counts.x * counts.y * counts.z) throw Error("counts exceeds max instanciated meshes");
let index = 0;
for (let x = 0; x < counts.x; x++) {
for (let y = 0; y < counts.y; y++) {
for (let z = 0; z < counts.z; z++) {
dummy.position.addVectors(startPos, new THREE.Vector3(x * spacing.x, y * spacing.y, z * spacing.z));
dummy.updateMatrix();
instances.setMatrixAt(index, dummy.matrix);
index++;
}
}
}
return instances;
}
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
camera.position.set(50, 75, 100);
renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
renderer.setClearColor(0xFFFFFF);
renderer.physicallyCorrectLights = true;
document.body.appendChild(renderer.domElement);
new THREE.RGBELoader()
.load('assets/enviroment.hdr', function ( texture ) {
texture.mapping = THREE.EquirectangularReflectionMapping;
scene.environment = texture;
});
let controls = new THREE.OrbitControls(camera, renderer.domElement);
const light1 = new THREE.AmbientLight(0xffffff, 0.3);
light1.name = 'ambient_light';
scene.add( light1 );
loadModel('assets/100-dollars.glb', (model) => {
let instances = generateInstances(model, 1500);
instances = setInstancePositions(instances, new THREE.Vector3(), new THREE.Vector3(5, 30, 10), new THREE.Vector3(27, 3, 13));
scene.add(instances);
});
renderer.setAnimationLoop(() => {
camera.lookAt(scene.position);
renderer.render(scene, camera);
});
}
init();
here is the hdr file: url
and here is the model: url
Using GLTFLoader requires a sRGB workflow which is not configured in your app. Add the following line and see if it fixes the color issue:
renderer.outputEncoding = THREE.sRGBEncoding;
Besides, consider to turn on antialiasing and the usage of setPixelRatio() for better quality:
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setPixelRatio(window.devicePixelRatio);
Related
I am trying to make the imported obj model to move with the help of three.js, but due to formatting problem, the obj object must be declared inside a function, and i am not able to access it outside the function, even if i pre-declared a variable outside the function to point to thee object. How can i access the object in this way?
import * as THREE from 'https://unpkg.com/three#0.126.1/build/three.module.js';
import { OrbitControls } from 'https://unpkg.com/three#0.126.1/examples/jsm/controls/OrbitControls.js';
import {OBJLoader} from "https://unpkg.com/three#0.126.1/examples/jsm/loaders/OBJLoader.js";
import {MTLLoader} from "https://unpkg.com/three#0.126.1/examples/jsm/loaders/MTLLoader.js";
import * as GUI from "https://unpkg.com/dat.gui#0.7.7/build/dat.gui.module.js";
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth,window.innerHeight);
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
var keyLight = new THREE.DirectionalLight(new THREE.Color('hsl(30,100%,75%)'),1.0);
var fillLight = new THREE.DirectionalLight(new THREE.Color('hsl(240,100%,75%)'),0.75);
var backLight = new THREE.DirectionalLight(0xffffff,1.0);
keyLight.position.set(-100,0,100);
fillLight.position.set(100,0,100);
backLight.position.set(100,0,-100).normalize();
scene.add(keyLight);
scene.add(fillLight);
scene.add(backLight);
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth/window.innerHeight,
0.1,
1000
);
const planeGeometry = new THREE.PlaneGeometry(100,100);
const planeMaterial = new THREE.MeshBasicMaterial({
color: 0xffffff,
wireframe: false,
});
var plane = new THREE.Mesh(planeGeometry,planeMaterial);
scene.add(plane);
plane.rotation.x = -0.5 * Math.PI;
const gridHelper = new THREE.GridHelper(100);
scene.add(gridHelper);
const gui = new GUI.GUI();
const options = {
planeColor: '#ffea00',
wireframe: false
};
gui.addColor(options,'planeColor').onChange(function(e){
plane.material.color.set(e);
});
gui.add(options,'wireframe').onChange(function(e){
plane.material.wireframe = e;
});
const orbit = new OrbitControls(camera,renderer.domElement);
camera.position.set(0,2,7.5);
orbit.update();
const spotLight = new THREE.SpotLight(0xffffff);
scene.add(spotLight);
spotLight.position.set(-50,50,0);
spotLight.castShadow = true;
spotLight.angle = 0.2;
const sLightHelper = new THREE.SpotLightHelper(spotLight);
scene.add(sLightHelper);
gui.add(spotLight,"angle",-1,1,0.01).name("angle");
gui.add(spotLight,"penumbra",0,1,0.01).name("penumbra");
gui.add(spotLight,"intensity",0,100,0.01).name("Intensity");
let house = undefined;
const mtlLoader = new MTLLoader();
mtlLoader.load(
'../source/MaryStanfordLifeboatHouse02.mtl',
(materials)=>{
materials.preload();
console.log(materials);
const objLoader = new OBJLoader()
objLoader.setMaterials(materials)
objLoader.load(
'../source/MaryStanfordLifeboatHouse02.obj',
function(object){
scene.add(object);
house = object;
house.rotation.x = 1/2 * Math.PI;
house.rotation.y = Math.PI;
},
function(xhr){
console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
},
function(error){
console.log("Object error")
}
)
},
(xhr) => {
console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
},
(error) => {
console.log("Material Eror")
}
)
const textureLoader = new THREE.TextureLoader();
textureLoader.load(
'../img/doge.jpg',
function ( texture ) {
scene.background = texture;
},
undefined,
function ( err ) {
console.error( 'An error happened.' );
}
);
function animate(){
// house.position.x += 1;
renderer.render(scene,camera);
sLightHelper.update();
}
renderer.setAnimationLoop(animate);
window.addEventListener('resize',function(){
camera.aspect = window.innerWidth/this.window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth,window.innerHeight);
});
// house.position.x += 1;
This line breaks because you access the variable too early. Keep in mind that the model is loaded asynchronously and you have to honor this circumstance when accessing it. As simple fix to avoid runtime errors is:
if ( house !== undefined ) house.position.x += 1;
Another option is that you only start animating when all assets have been loaded.
I am currently trying to change the geometry of a cube in three js to that of a sphere after a certain time interval or an event click. I have tried to change the property of geometry from Three.BoxGeometry to Three.SphereGeometry but have had no luck.
I have also tried to implement some "solutions" that I found, but have hit a wall there too.
Here is what I initially had:
export class ThreeJSService {
geometry: THREE.BoxGeometry;
camera: THREE.PerspectiveCamera;
cube: THREE.Mesh;
movingObject;
renderer: THREE.WebGLRenderer;
scene: THREE.Scene;
texture: THREE.Texture;
/**
* Setups scene for 3d objects
*/
constructor() {
this.scene = new THREE.Scene();
this.texture = new THREE.TextureLoader().load('assets/apartment_background.png');
this.scene.background = this.texture;
this.camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
this.renderer = new THREE.WebGLRenderer();
this.geometry = new THREE.BoxGeometry(0.5, 0.5, 0.5);
const material = new THREE.MeshBasicMaterial( {color: 0x348713} );
this.cube = new THREE.Mesh( this.geometry, material );
this.movingObject = {
object: this.cube,
geometry: this.geometry,
direction: {
x: 0.03,
y: 0,
},
};
}
/**
* Sets all the requirements needed for the scene
* #param {HTMLElement} parent The element to attach to
*/
setup(parent: HTMLElement) {
const canvas = this.renderer.domElement;
this.scene.add( this.cube );
this.camera.position.z = 5;
parent.appendChild(canvas);
}
// transform() {
// for ( var i = 0, l = this.geometry.vertices.length; i < l; i ++ ) {
//
// var vertex = this.geometry.vertices[ i ];
// vertex.normalize().multiplyScalar( 550 );
//
// // After a certain interval change the geometry from Cylinder to Sphere
//
// }
// }
/**
* Provides animation to the rendered object. Makes the cube move and sends it to another direction when getting to the border
* #param {number | undefined} headerHeight The height of the header
*/
animate() {
const header = document.getElementById('header')?.clientHeight;
this.renderer.setSize( window.innerWidth, window.innerHeight - (header ? header : 0));
this.movingObject.object.rotateX(0.01);
this.movingObject.object.rotateY(0.01);
requestAnimationFrame( this.animate.bind(this) );
this.renderer.render( this.scene, this.camera );
this.movingObject.object.position.x += this.movingObject.direction.x;
// Check if the position of the cube is on the border
if (this.cube.position.x > 7.3 || this.cube.position.x < -7.3) {
this.movingObject.direction.x = -this.movingObject.direction.x;
}
}
Any help would be greatly appreciated!
Here is a complete live example that shows a geometry is replaced after two seconds.
let camera, scene, renderer;
init();
render();
function init() {
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 10);
camera.position.set(2, 2, 2);
camera.lookAt(0, 0, 0);
scene = new THREE.Scene();
geometry = new THREE.BoxGeometry();
material = new THREE.MeshNormalMaterial();
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
setTimeout(function() {
mesh.geometry.dispose();
mesh.geometry = new THREE.SphereGeometry();
render();
}, 2000);
}
function render() {
renderer.render(scene, camera);
}
body {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.141/build/three.min.js"></script>
I managed to get it to work.
This is my solution:
changeShape() {
this.interval = (Math.floor(Math.random() * (400 + 1)) * 1000);
// this.interval = Math.floor((Math.random() * (20 - 10 + 10)) + 10) * 1000;
if (this.switch) {
setTimeout(() => {
this.movingObject.object.geometry.dispose();
this.movingObject.object.geometry = new THREE.CylinderGeometry(0.5, 0.5, 2);
this.switch = false;
// console.log(this.interval);
}, this.interval);
} else {
setTimeout(() => {
this.movingObject.object.geometry.dispose();
this.movingObject.object.geometry = new THREE.SphereGeometry(0.5, 8, 8);
this.switch = true;
// console.log(this.interval);
}, this.interval);
}
}
Thank you for the assist!
I am new to Three.js. I am having issues using a gltf model as the actual scene and not part of the scene in three.js. The gltf model is an apartment. I want the scene to load from inside the apartment and not outside the apartment. the controls should work within the apartment too. So far, I have loaded the model on the scene but I can't get the scene to render from inside the model.
Here is my code in Typescript and also JavaScript been at it for weeks now. Any help will be much appreciated. Thank you so much.
Typescript code
import * as THREE from '/build/three.module.js'
import { OrbitControls } from '/jsm/controls/OrbitControls'
import { GLTFLoader } from '/jsm/loaders/GLTFLoader'
import Stats from '/jsm/libs/stats.module'
const scene: THREE.Scene = new THREE.Scene()
const axesHelper = new THREE.AxesHelper(5)
//scene.add(axesHelper)
var light = new THREE.SpotLight();
light.position.set(5, 5, 5)
scene.add(light);
const camera: THREE.PerspectiveCamera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
camera.position.z = 2
const renderer: THREE.WebGLRenderer = new THREE.WebGLRenderer()
//renderer.physicallyCorrectLights = true
//renderer.shadowMap.enabled = true
renderer.outputEncoding = THREE.sRGBEncoding
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)
const controls = new OrbitControls(camera, renderer.domElement)
const loader = new GLTFLoader()
loader.load(
'apartment.glb',
function (gltf) {
// gltf.scene.traverse(function (child) {
// if ((<THREE.Mesh>child).isMesh) {
// let m = <THREE.Mesh>child
// m.receiveShadow = true
// m.castShadow = true
// }
// if ((<THREE.Light>child).isLight) {
// let l = <THREE.Light>child
// l.castShadow = true
// //l.shadow.bias = -.003
// l.shadow.mapSize.width = 2048
// l.shadow.mapSize.height = 2048
// }
// })
scene.add(gltf.scene);
},
(xhr) => {
console.log((xhr.loaded / xhr.total * 100) + '% loaded')
},
(error) => {
console.log(error);
}
);
window.addEventListener('resize', onWindowResize, false)
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
renderer.setSize(window.innerWidth, window.innerHeight)
render()
}
const stats = Stats()
document.body.appendChild(stats.dom)
var animate = function () {
requestAnimationFrame(animate)
controls.update()
render()
stats.update()
};
function render() {
renderer.render(scene, camera)
}
animate();
JavaScript code
import * as THREE from '/build/three.module.js';
import { OrbitControls } from '/jsm/controls/OrbitControls';
import { GLTFLoader } from '/jsm/loaders/GLTFLoader';
import Stats from '/jsm/libs/stats.module';
const scene = new THREE.Scene();
const axesHelper = new THREE.AxesHelper(5);
//scene.add(axesHelper)
var light = new THREE.SpotLight();
light.position.set(5, 5, 5);
scene.add(light);
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 2;
const renderer = new THREE.WebGLRenderer();
//renderer.physicallyCorrectLights = true
//renderer.shadowMap.enabled = true
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const controls = new OrbitControls(camera, renderer.domElement);
const loader = new GLTFLoader();
loader.load('apartment.glb', function (gltf) {
// gltf.scene.traverse(function (child) {
// if ((<THREE.Mesh>child).isMesh) {
// let m = <THREE.Mesh>child
// m.receiveShadow = true
// m.castShadow = true
// }
// if ((<THREE.Light>child).isLight) {
// let l = <THREE.Light>child
// l.castShadow = true
// //l.shadow.bias = -.003
// l.shadow.mapSize.width = 2048
// l.shadow.mapSize.height = 2048
// }
// })
scene.add(gltf.scene);
}, (xhr) => {
console.log((xhr.loaded / xhr.total * 100) + '% loaded');
}, (error) => {
console.log(error);
});
window.addEventListener('resize', onWindowResize, false);
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
render();
}
const stats = Stats();
document.body.appendChild(stats.dom);
var animate = function () {
requestAnimationFrame(animate);
controls.update();
render();
stats.update();
};
function render() {
renderer.render(scene, camera);
}
animate();
Finally was able to solve my issue.
firstly I had to use a plane model that is with no roof
secondly the pivot point was properly at the center and the model was on the plane grid, unlike the first model I was working with.
with the model opened the room was what was rendered in the scene and not the entire model itself and because the pivot point was in the middle and the model on the plane, not below or above it, I did not have to look for it in the scene when it rendered. Thank you for reading and trying to help.
because I had solved this problem I was able to load multiple glb models and place them where I wanted in the scene without hassle.
my advice if you want to use a model as your scene make sure the pivot point is at the center and the model is on the grid, not over or below it. also make sure its an open model so your light and camera can see inside.
here was my final code.
import * as THREE from '/build/three.module.js'
import { OrbitControls } from '/jsm/controls/OrbitControls'
import { GLTFLoader } from '/jsm/loaders/GLTFLoader'
// import Stats from '/jsm/libs/stats.module'
// import { GUI } from '/jsm/libs/dat.gui.module'
const scene: THREE.Scene = new THREE.Scene()
const axesHelper = new THREE.AxesHelper(5)
//scene.add(axesHelper)
const light = new THREE.SpotLight(0xffa95c,4);
light.position.set(-50,50,50);
light.castShadow = true;
scene.add( light );
var hemiLight = new THREE.HemisphereLight(0xffeeb1, 0x080820, 4);
scene.add(hemiLight);
var light3 = new THREE.DirectionalLight( 0xffffff );
light3.position.set( 0, 200, 100 );
light3.castShadow = true;
light3.shadow.mapSize.width = 2048;
light3.shadow.mapSize.height = 2048;
light3.shadow.camera.top = 3000;
light3.shadow.camera.bottom = -3000;
light3.shadow.camera.left = -3000;
light3.shadow.camera.right = 3000;
light3.shadow.camera.far = 3000;
scene.add( light );
const camera: THREE.PerspectiveCamera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
camera.position.z = 2
camera.position.y = 2
camera.position.x = 2
const renderer: THREE.WebGLRenderer = new THREE.WebGLRenderer()
//renderer.physicallyCorrectLights = true
//renderer.shadowMap.enabled = true
renderer.outputEncoding = THREE.sRGBEncoding
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)
// var mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2000, 2000 ), new THREE.MeshPhongMaterial( { color: 0x999999, depthWrite: false } ) );
// mesh.rotation.x = - Math.PI / 2;
// //mesh.position.y = -100;
// mesh.receiveShadow = true;
// //this.scene.add( mesh );
// var grid = new THREE.GridHelper( 2000, 40, 0x000000, 0x000000 );
// //grid.position.y = -100;
// // grid.material.opacity = 0.2;
// // grid.material.transparent = true;
const raycaster = new THREE.Raycaster();
const controls = new OrbitControls(camera, renderer.domElement)
controls.screenSpacePanning = true
controls.target.set(0, 1, 0)
controls.minDistance = 5;
controls.maxDistance = 10;
// const backGroundTexture = new THREE.CubeTextureLoader().load(["img/py_eso0932a.jpg", "img/ny_eso0932a.jpg", "img/py_eso0932a.jpg", "img/ny_eso0932a.jpg", "img/pz_eso0932a.jpg", "img/nz_eso0932a.jpg"]);
// scene.background = backGroundTexture;
const loader = new GLTFLoader()
loader.load(
'models3/untitled.glb',
function (gltf) {
scene.add(gltf.scene);
gltf.scene.position.set(0,-2,3)
},
(xhr) => {
console.log((xhr.loaded / xhr.total * 100) + '% loaded')
},
(error) => {
console.log(error);
}
);
loader.load(
'models3/man.glb',
function (gltf1) {
scene.add(gltf1.scene);
gltf1.scene.position.set(1,-1.3,0)
gltf1.scene.scale.set(2,2,2)
},
(xhr) => {
console.log((xhr.loaded / xhr.total * 100) + '% loaded')
},
(error) => {
console.log(error);
}
);
loader.load(
'models3/jack_daniels.glb',
function (gltf2) {
gltf2.scene.traverse(function (child) {
if ((<THREE.Mesh>child).isMesh) {
let m = <THREE.Mesh>child
m.receiveShadow = true
m.castShadow = true;
//(<THREE.MeshStandardMaterial>m.material).flatShading = true
//sceneMeshes.push(m)
}
if ((<THREE.Light>child).isLight) {
let l = <THREE.Light>child
l.castShadow = true
l.shadow.bias = -.003
l.shadow.mapSize.width = 2048
l.shadow.mapSize.height = 2048
}
scene.add(gltf2.scene);
gltf2.scene.position.set(-1,0.55,-1)
gltf2.scene.scale.set(0.15,0.15,0.15)})
},
(xhr) => {
console.log((xhr.loaded / xhr.total * 100) + '% loaded')
},
(error) => {
console.log(error);
}
);
// renderer.domElement.addEventListener('dblclick', onDoubleClick, false);
// renderer.domElement.addEventListener('mousemove', onMouseMove, false);
// function onMouseMove(event: MouseEvent) {
// const mouse = {
// x: (event.clientX / renderer.domElement.clientWidth) * 2 - 1,
// y: -(event.clientY / renderer.domElement.clientHeight) * 2 + 1
// }
// //console.log(mouse)
// raycaster.setFromCamera(mouse, camera);
window.addEventListener('resize', onWindowResize, false)
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
renderer.setSize(window.innerWidth, window.innerHeight)
render()
}
// const stats = Stats()
// document.body.appendChild(stats.dom)
var animate = function () {
requestAnimationFrame(animate)
// light.position.set(
// camera.position.x + 10,
// camera.position.y + 10,
// camera.position.z + 10,
// );
controls.update()
render()
// stats.update()
};
function render() {
renderer.render(scene, camera)
}
animate();
function onDoubleClick(arg0: string, onDoubleClick: any, arg2: boolean) {
throw new Error('Function not implemented.')
}
PLEASE FEEL FREE TO COMMENT IF THERE IS SOMETHING I NEED TO KNOW. I WILL HUMBLY TAKE CORRECTIONS. THANK YOU
Been futzing around with the three.js library a bit this past week, and I ran into a problem applying transformations to loaded models (gltf). Whenever I try to update the rotation I get "Uncaught TypeError: Cannot read property 'position' of undefined." I'm very confused; it seems like I can only access the .position/.rotation attributes in onLoad?
let container;
let camera;
let controls;
let renderer;
let scene;
let mesh;
const mixers = [];
const clock = new THREE.Clock();
function init() {
container = document.querySelector('#scene-container');
scene = new THREE.Scene();
scene.background = new THREE.Color(0x8FBCD4);
createCamera();
createLights();
loadModels();
createRenderer();
createControls();
renderer.setAnimationLoop(() => {
update();
render();
});
}
function createCamera() {
const fov = 35;
const aspect = container.clientWidth / container.clientHeight;
const near = 0.1; //near clipping plane
const far = 100; //far clipping plane
camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(-1.5, 1.5, 6.5);
}
function createLights() {
const ambientLight = new THREE.HemisphereLight(
0xddeeff, //bright sky color
0x202020, //dim ground color
3 //intensity
);
//this is a specular light
const mainLight = new THREE.DirectionalLight(0xffffff, 10);
mainLight.position.set(10, 10, 10);
scene.add(ambientLight, mainLight);
}
function createRenderer() {
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(container.clientWidth, container.clientHeight);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.gammaFactor = 2.2;
renderer.gammaFactor = true;
renderer.physicallyCorrectLights = true; //allows us to use lux, candela and lumens to set lighting
container.appendChild(renderer.domElement);
}
function loadModels() {
const loader = new THREE.GLTFLoader();
const onLoad = ( gltf, position ) => {
const model = gltf.scene.children[ 0 ]; //get reference to the model
model.position.copy( position ); //passes the position parameter into the models position value
const animation = gltf.animations[ 0 ];
const mixer = new THREE.AnimationMixer( model ); //instances a animation controller
mixers.push( mixer );
const action = mixer.clipAction( animation );
action.play();
mesh = model;
scene.add( model );
};
const onProgress = () => {};
const onError = (errorMessage) => { console.log(errorMessage); };
//loads a position the model and the position
const suzannePosition = new THREE.Vector3(0, 0, 2.5);
loader.load('models/test/suzanne.glb', gltf => onLoad(gltf, suzannePosition), onProgress, onError);
}
function update() {
const delta = clock.getDelta();
for (const mixer of mixers) {
mixer.update(delta);
}
/* ---THIS DOESN'T WORK---
mesh.rotation.x += .01;
console.log(mesh.rotation);
*/
}
function createControls() {
controls = new THREE.OrbitControls(camera, container);
}
function render() {
renderer.render(scene, camera);
}
function onWindowResize() {
camera.aspect = container.clientWidth / container.clientHeight;
//update camera's frustum
camera.updateProjectionMatrix();
renderer.setSize(container.clientWidth, container.clientHeight);
}
window.addEventListener('resize', onWindowResize);
init();
mesh = model;
This assignment happens in the onLoad() callback of GLTFLoader.load(). It's important to understand that this callback is executed asynchronously when the model is loaded.
In the meanwhile, mesh is undefined. So change your code to the following to get rid of the runtime error:
if ( mesh ) mesh.rotation.x += .01;
I want to set colors according to the height of my model, which is a .obj file. I want the colors to go from green to red, depending on the height, green for the minimum point, red for the maximum. This is my code currently:
loader.load(nombreMapa, function (object) {
loader.setMaterials(material);
escena.add(object);
object.position.y = -10;
if (object instanceof THREE.Object3D)
{
object.traverse (function (mesh)
{
if (! (mesh instanceof THREE.Mesh)) return;
mesh.material = new THREE.MeshNormalMaterial();
mesh.material.side = THREE.DoubleSide;
var geometry = new THREE.EdgesGeometry( mesh.geometry );
var material1 = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1000 } );
var edges = new THREE.LineSegments( geometry, material1 );
mesh.add( edges );
});
}});
You can do this trick, using THREE.Box3() and .lerp() method of THREE.Color() for setting colors of each vertex in each child's mesh's geometry.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 60, 250);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x404040);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.target.set(0, 60, 0);
controls.update();
var mat = new THREE.MeshBasicMaterial({
wireframe: true,
vertexColors: THREE.VertexColors
}); // the same material for all the children of the object
var loader = new THREE.OBJLoader();
loader.load('https://threejs.org/examples/models/obj/male02/male02.obj', function(obj) {
var size = new THREE.Vector3();
var box3 = new THREE.Box3().setFromObject(obj);
box3.getSize(size);
console.log(size);
var v3 = new THREE.Vector3(); // for re-use
var c = [
new THREE.Color(0x00ff00),
new THREE.Color(0xff0000)
];
var cTemp = new THREE.Color(); // for re-use
obj.traverse(child => {
if (child.isMesh) {
let colors = []; // array for color values of the current mesh's geometry
let pos = child.geometry.attributes.position;
for(let i = 0; i < pos.count; i++){
v3.fromBufferAttribute(pos, i);
obj.localToWorld(v3); // box3 is in world coords so we have to convert coortinates of the vertex from local to world
let a = (v3.y - box3.min.y) / size.y; // find the value in range 0..1
cTemp.copy(c[0]).lerp(c[1], a); // lerp the colors
colors.push(cTemp.r, cTemp.g, cTemp.b); // save values in the array
child.geometry.addAttribute("color", new THREE.BufferAttribute(new Float32Array(colors), 3)); // add a buffer attribute for colors
child.material = mat;
}
}
});
scene.add(obj);
})
renderer.setAnimationLoop(() => {
renderer.render(scene, camera)
});
body {
overflow: hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src="https://threejs.org/examples/js/loaders/OBJLoader.js"></script>
Also, take a look at this SO answer about other options of how to apply gradient.