how to convert 3D obj file to particles in three.js - javascript

I'm trying to play around with particles in three.js but, there's a problem with converting obj file (3D model) into particles in three.js. The following is the code snippets. I tried but, all failed.
Is there anyone who can help correcting the errors or provide with any examples of getting vertices/particles from a 3D model in obj?
Thanks a lot.
var p_geom = new THREE.Geometry();
var p_material = new THREE.ParticleBasicMaterial({
color: 0xFFFFFF,
size: 1.5
});
var loader = new THREE.OBJLoader();
loader.load( 'human.obj',function(object){
object.traverse( function(child){
if ( child instanceof THREE.Mesh ) {
// child.material.map = texture;
var scale = 10.0;
object.attributes.position.array.forEach(function() {
p_geom.vertices.push(new THREE.Vector3(this.x * scale, this.y * scale, this.z * scale));
})
}
});
scene.add(p)
});
p = new THREE.ParticleSystem(
p_geom,
p_material
);

You are using an outdated code reference. With recent three.js version, the code looks more like the following:
const loader = new THREE.OBJLoader();
loader.load('human.obj', function(object) {
const vertices = [];
object.traverse(function(child) {
if (child.isMesh) {
vertices.push(...child.geometry.attributes.position.array);
}
});
const p_geom = new THREE.BufferGeometry();
const p_material = new THREE.PointsMaterial({
color: 0xFFFFFF,
size: 1.5
});
p_geom.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
const p = new THREE.Points(p_geom, p_material);
p.scale.set(10, 10, 10);
scene.add(p)
});

Related

Raycasting not working on imported OBJ model,but working on object created with the program

I am new to three.js, and i am trying to use raycasting, i am quite confused with how raycasting would work on imported 3d models. Here i imported an obj model, and when i try to detect whether i touch with the imported 3D model, the funciton is not working as i expect. But when i change it to detect a box object i create with three.js, is working as i expected, can someone help with this problem?
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";
//Set Up Enviroment for 3D model
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth,window.innerHeight);
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
//Set up Lighting
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);
//Set up Camera
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth/window.innerHeight,
0.1,
1000
);
const orbit = new OrbitControls(camera,renderer.domElement);
camera.position.set(0,2,7.5);
orbit.update();
//Set up base
const planeGeometry = new THREE.PlaneGeometry(100,100);
const planeMaterial = new THREE.MeshBasicMaterial({
color: 0xffffff,
wireframe: false,
side: THREE.DoubleSide
});
var plane = new THREE.Mesh(planeGeometry,planeMaterial);
scene.add(plane);
plane.rotation.x = -0.5 * Math.PI;
//Model for testing
const boxGeometry = new THREE.BoxGeometry(10,10,10);
const boxMaterial = new THREE.MeshBasicMaterial({color: 0x0000ff})
var box = new THREE.Mesh(boxGeometry,boxMaterial);
scene.add(box);
box.position.x += 20;
//Set up GUI for controlling base
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;
});
//Set up Background image
const textureLoader = new THREE.TextureLoader();
textureLoader.load(
'../img/doge.jpg',
function ( texture ) {
scene.background = texture;
},
undefined,
function ( err ) {
console.error( 'An error happened.' );
}
);
//Import obj and mtl file to build 3D model
var building;
const mtlLoader = new MTLLoader();
mtlLoader.load(
'../source/building_04.mtl',
(materials)=>{
materials.preload();
console.log(materials);
const objLoader = new OBJLoader()
objLoader.setMaterials(materials)
objLoader.load(
'../source/building_04.obj',
(object)=>{
scene.add(object)
building = object;
object.position.y +=1;
},
(xhr) => {
console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
},
(error) => {
console.log("Object error")
}
)
},
(xhr) => {
console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
},
(error) => {
console.log("Material Eror")
}
)
//Set up raycasting environment
const raycaster = new THREE.Raycaster();
const mousePosition = new THREE.Vector2();
window.addEventListener('mousemove', function(e){
mousePosition.x = (e.clientX/this.window.innerWidth)*2 - 1;
mousePosition.y = -(e.clientY/this.window.innerHeight)*2 + 1;
});
//Function making sure everything to be up to date
function animate(){
//Raycasting
raycaster.setFromCamera( mousePosition, camera );
const intersects = raycaster.intersectObjects( scene.children,true);
if(intersects.length > 0){
for ( let i = 0; i < intersects.length; i ++ ) {
if(building != undefined){
if(intersects[0].object.id === building.id){
console.log("Touched!");
}
else{
console.log("did not touch!");
}
}
else{
console.log("Not reeady!");
}
console.log(intersects[i].object.id);
}
}
else{
console.log("did not touched")
}
console.log("finished")
renderer.render(scene,camera);
}
renderer.setAnimationLoop(animate);
//Make the screen to resize following the browser size
window.addEventListener('resize',function(){
camera.aspect = window.innerWidth/this.window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth,window.innerHeight);
});
The problem is that the object you get from OBJLoader and assign to your building variable is an instance of THREE.Group. Groups do not have an own geometry or material. They are more or less containers holding other 3D objects (like meshes, point clouds, lines or other groups) and representing them as a logical group.
That means they are never the result of a raycasting evaluation which means if(intersects[0].object.id === building.id) always fails.
I suggest you do this after the loading process which tags your objects:
building.traverse( function( object ) {
object.userData.tag = 'building';
} );
You can then use the tag property in your raycasting routine for detecting the building.

OBJLoader and MTLLoader aren't rendering png/texture in ThreeJS

I imported the 3D model that contains .obj .mtl and bunch of jpeg and pngs
trying to load the model with /images like this
But, I'm getting is only a black model like his
I wonder what I have missed as I followed the guidelines for using the two loaders.
here is my code.
//loader
var MTTLoader = new THREE.MTLLoader();
MTTLoader.setPath( '/assets/HotAirBalloonIridesium/' );
MTTLoader.load('Air_Balloon.mtl',(materials) => {
console.log(materials);
materials.preload()
var objLoader = new THREE.OBJLoader();
objLoader.load('/assets/HotAirBalloonIridesium/Air_Balloon.obj', (object) => {
console.log(materials)
objLoader.setMaterials(materials)
scene.add(object);
})
})
I wonder what i'm missing as my asset folder contains all the model files
try loading obj using
var loader = new THREE.OBJLoader( manager );
loader.load( 's_v1.obj', function ( object ) {
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh )
{
// child.material.map = texture2;
// child.material.specularMap=texture;
// child.material.map=texture;
}
} );
// object.position.x = - 60;
// object.rotation.x = 0; //20* Math.PI / 180;
// object.rotation.z = 0;//20* Math.PI / 180;
object.scale.x = 80;
object.scale.y = 80;
object.scale.z = 80;
obj = object
scene.add( obj );
animate(obj);
} );
okay quick update, there was nothing wrong with the loader but I was using the wrong lighting as Phong Material needed
var hemiLight = new THREE.HemisphereLight(0xffffff, 0xffffff, 0.50);
var dirLight = new THREE.DirectionalLight(0xffffff, 0.50);
to be apparent.
You must call "setMaterials" before load obj.
//loader
var MTTLoader = new THREE.MTLLoader();
MTTLoader.setPath( '/assets/HotAirBalloonIridesium/' );
MTTLoader.load('Air_Balloon.mtl',(materials) => {
console.log(materials);
materials.preload()
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials(materials); // "setMaterials" must before "load"
objLoader.load('/assets/HotAirBalloonIridesium/Air_Balloon.obj', (object) => {
console.log(materials)
scene.add(object);
})
})

Three.JS + OOP in javascript, can't pass a 3D JSON object to other class

It was hard to describe the problem in a single line so this is the situation.
I am going to build a big Javascript project with Three.js so I'm trying to grasp it's OOP concepts.
1) I created a 3D world Object
2) A base 3D_object class with child classes
3) In the sample bellow you see an option 1 and an option 2 these should produce the same result, but somehow they don't. Any idea why ? The complete source is in the snippet.
(Three.js should be included before the script and I am assuming there is a 'resources/object.json' file )
Here is a github link of the project, maybe someone will find it this way. (probably need to run it on a local python server for example to bypass the cross-origin file loading problem in chrome)
//create world
var myWorld = new World(500,500);
myWorld.AddWorldToPage();
//load simple model in the world
var cube = new Cube();
myWorld.addToScene(cube);
// load json model in the world
//option 1
// myWorld.addToSceneTemp();
//option 2 OO (not working)
var jsonObject = new Object_3D_JSON();
function afterModelLoaded(){
console.log("after loading is done");
myWorld.addToScene(jsonObject);
}
jsonObject.loadModel(afterModelLoaded);
myWorld.render();
// Inhertit convencience method
//=====================================================================================================
function inheritsF / rom(child, parent) {
child.prototype = new parent();
child.prototype.constructor = child;
}
// 3D Objects
//=====================================================================================================
// 3D object class
//=====================================================================================================
function Object_3DClass() {
this._geometry = new THREE.BoxGeometry(1, 1, 1);
this._material = new THREE.MeshBasicMaterial({
color: 0xff00ff
});
this._mesh = new THREE.Mesh(this._geometry, this._material);
}
//Get 3D mesh
Object_3DClass.prototype.getMesh = function() {
return this._mesh;
}
//Animate Object
Object_3DClass.prototype.animateFrame = function() {
this._mesh.rotation.x += 0.01;
this._mesh.rotation.y += 0.01;
}
Object_3DClass.prototype.setPosition = function(x, y, z) {
this._mesh.position.set(x, y, z);
}
// END 3D object class
//===================================================================================================
// 3D Cube class
//=====================================================================================================
function Cube() {
this._geometry = new THREE.BoxGeometry(1, 1, 1);
this._material = new THREE.MeshBasicMaterial({
color: 0x00ff00
});
this._mesh = new THREE.Mesh(this._geometry, this._material);
}
inheritsFrom(Cube, Object_3DClass)
// END OF 3D Cube class
//=====================================================================================================
// 3D JSON Model class
//=====================================================================================================
function Object_3D_JSON() {
// instantiate a loader
this._loader = new THREE.JSONLoader();
this._mesh = null;
}
inheritsFrom(Object_3D_JSON, Object_3DClass);
//loadModel
Object_3D_JSON.prototype.loadModel = function(whenReady_Fn) {
// _geometry = this._geometry;
var self = this;
// load a resource
this._loader.load(
// resource URL
'resources/object.json',
// Function when resource is loaded
function(geometry, materials) {
console.log("loading");
// this._material = new THREE.MultiMaterial( materials );
self._material = new THREE.MeshBasicMaterial({
color: 0xffffff
});
self._mesh = new THREE.Mesh(geometry, materials);
self._geometry = geometry;
whenReady_Fn();
// scene.add( this._mesh );
},
//onProgress
function() {},
//onError
function() {
console.log("resource not found");
}
);
}
// END OF 3D JSON Model class
//=====================================================================================================
// World class
//=====================================================================================================
var World = (function() {
// World constructor
function World(width, height) {
//private members
//===========================
this._width = width;
this._height = height;
this._scene = new THREE.Scene();
this._camera = new THREE.PerspectiveCamera(75, this._width / this._height, 0.1, 1000);
this._camera.position.set(6.8, 9.5, 12.2);
this._camera.lookAt(new THREE.Vector3(0, 0, 0));
this._renderer = new THREE.WebGLRenderer();
this._renderer.setSize(this._width, this._height);
this._worldName = "Tubrines";
this._object_3DList = [];
return _privatePrintMessage.call(this, "message");
}
//public
//===========================
//functions
World.prototype.AddWorldToPage = function() {
document.body.appendChild(this._renderer.domElement);
}
World.prototype.render = function() {
//zichzelf meegeven aan AnimationFrame
requestAnimationFrame(this.render.bind(this));
this._object_3DList[0].animateFrame();
this._renderer.render(this._scene, this._camera);
}
World.prototype.addToScene = function(object_3DClass) {
this._scene.add(object_3DClass.getMesh());
this._object_3DList.push(object_3DClass);
}
World.prototype.addToSceneTemp = function() {
_scene = this._scene;
_object_3DList = this._object_3DList;
// instantiate a loader
var loader = new THREE.JSONLoader();
// load a resource
loader.load(
// resource URL
'resources/object.json',
// Function when resource is loaded
function(geometry, materials) {
// var material = new THREE.MultiMaterial( materials );
var material = new THREE.MeshBasicMaterial({
color: 0xff00ff
});
var mesh = new THREE.Mesh(geometry, material);
_scene.add(mesh);
_object_3DList.push(mesh);
});
}
//private functions
//===========================
function _privatePrintMessage(message) {
// return prefix + this._foo;
console.log("World class: " + this._worldName + " " + message);
}
return World;
})();
// END OF World class
//=====================================================================================================
//create world
var myWorld = new World(500, 500);
myWorld.AddWorldToPage();
//load simple model in the world
var cube = new Cube();
myWorld.addToScene(cube);
// load json model in the world
//option 1
// myWorld.addToSceneTemp();
//option 2 OO (not working)
var jsonObject = new Object_3D_JSON();
function afterModelLoaded() {
console.log("after loading is done");
myWorld.addToScene(jsonObject);
}
jsonObject.loadModel(afterModelLoaded);
myWorld.render();
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<title>My first three.js app</title>
<style>
body {
margin: 0;
}
canvas {
width: 100%;
height: 100%
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<body>
<script src="script.js"></script>
</body>
</html>
You are trying to pass a list of materials without telling three.js it's a multimaterial.
Change this line:
self._mesh = new THREE.Mesh( geometry , materials );
to:
var materialSet = new THREE.MultiMaterial( materials );
self._mesh = new THREE.Mesh( geometry , materialSet );
And now that you're using the proper json supplied material, you need to add a light to the scene, otherwise the lambert materials in your model will not show. (lambert materials require lights, basic materials do not, which is why the cube worked).
this._scene = new THREE.Scene();
var spotLight = new THREE.SpotLight( 0xffffff );
spotLight.position.set( 100, 1000, 100 );
spotLight.castShadow = true;
spotLight.shadow.mapSize.width = 1024;
spotLight.shadow.mapSize.height = 1024;
spotLight.shadow.camera.near = 500;
spotLight.shadow.camera.far = 4000;
spotLight.shadow.camera.fov = 30;
this._scene.add( spotLight );

errors extruding shapes with three.js

I'm just getting started with three.js, and having some issues extruding some 2d shapes.
I have a GeoJSON file containing all the counties in the US. I'm using d3.js and a d3.geo.albersUSa() projection to convert each latitude/longitude into a list of X/Y coordinates to make a THREE.Shape that I'm then extruding and drawing. This seems to work OK for most counties.
The issue I'm seeing is that some subset of counties either fail to extrude or extrude incorrectly with the following sequences of warnings:
Warning, unable to triangulate polygon!
Duplicate point 653.4789181355854:204.0166729191409
Either infinite or no solutions!
Its finite solutions.
Either infinite or no solutions!
Too bad, no solutions.
I'm not sure I understand exactly what the issue is -- as far as I can tell, there's nothing special about these particular shapes. Am I doing something wrong, or is this an issue with the extrusion code in three.js?
For example here are some missing counties:
Also notice the triangular 'hourglass' missing pieces in Texas: these look like some counties which were only half rendered (they ended up as triangles instead of rectangles or squares?)
Larger
Apologies for the huge code dump, I tried to pare it down as much as possible.
setup:
/* initialize the scene, camera, light, and background plane */
var Map = function(params) {
this.width = params.width;
this.height = params.height;
this.container = params.target || document.body;
this.renderer = new THREE.WebGLRenderer({antialias: true});
this.renderer.setSize(this.width, this.height);
this.renderer.setClearColorHex(0x303030, 1.0);
this.container.appendChild(this.renderer.domElement);
this.camera = new THREE.PerspectiveCamera(45, this.width / this.height,
1, 10000);
this.scene = new THREE.Scene();
this.scene.add(this.camera);
this.camera.position.z = 550;
this.camera.position.x = 0;
this.camera.position.y = 550;
this.camera.lookAt(this.scene.position);
this.projection = d3.geo.albersUsa()
.scale(1000)
.translate([250, 0]);
var pointLight = new THREE.PointLight(0xFFFFFF);
pointLight.position.x = 800;
pointLight.position.y = 800;
pointLight.position.z = 800;
var plane = new THREE.Mesh(
new THREE.PlaneGeometry(10000, 10000, 10, 10),
new THREE.MeshLambertMaterial({color: 0xffffff})
);
plane.rotation.x = -Math.PI/2;
this.scene.add(pointLight);
this.scene.add(plane);
};
rendering:
/* given a GeoJSON Feature, return a list of Vector2s
* describing where to draw the feature, using the provided projection. */
function path(proj, feature) {
if (feature.geometry.type == 'Polygon') {
return polygonPath(proj, feature.geometry.coordinates);
} else if (feature.geometry.type == 'MultiPolygon') {
return multiPolygonPath(proj, feature.geometry.coordinates);
}
}
/* a GeoJSON Polygon is a set of 'rings'. The first ring is the shape of the polygon.
* each subsequent ring is a hole inside that polygon. */
function polygonPath(proj, rings) {
var list = [];
var cur = [];
$.each(rings, function(i, ring) {
cur = [];
$.each(ring, function(i, coord) {
var pts = proj(coord);
cur.push(new THREE.Vector2(pts[0], pts[1]));
});
list.push(cur);
});
return list;
}
/* a GeoJSON MultiPolgyon is just a series of Polygons. */
function multiPolygonPath(proj, polys) {
var list = [];
$.each(polys, function(i, poly) {
list.push(polygonPath(proj, poly));
});
return list;
}
/* for each feature, find it's X/Y Path, create shape(s) with the required holes,
* and extrude the shape */
function renderFeatures(proj, features, scene, isState) {
var color = 0x33ccff;
$.each(features, function(i, feature) {
var polygons = path(proj, feature);
if (feature.geometry.type != 'MultiPolygon') {
polygons = [polygons];
}
$.each(polygons, function(i, poly) {
var shape = new THREE.Shape(poly[0]);
if (poly.length > 1) {
shape.holes = poly.slice(1).map(function(item) { return new THREE.Shape(item); });
}
var geom = new THREE.ExtrudeGeometry(shape, { amount: 20, bevelEnabled: false });
var c = new THREE.Mesh(geom, new THREE.MeshLambertMaterial({color: color}) );
c.rotation.x = Math.PI/2;
c.translateX(-290);
c.translateZ(50);
c.translateY(5);
scene.add(c);
});
});
}
Map.prototype.renderCounties = function() {
$.getJSON('/data/us-counties.json', function(json) {
renderFeatures(this.projection, json.features, this.scene, false);
this.renderer.render(this.scene, this.camera);
}.bind(this));
}
It looks like the points of the polygon are in the wrong order.

Using textures in THREE.js

I am starting with THREE.js, and I am trying to draw a rectangle with a texture on it, lit by a single source of light. I think this is as simple as it gets (HTML omitted for brevity):
function loadScene() {
var world = document.getElementById('world'),
WIDTH = 1200,
HEIGHT = 500,
VIEW_ANGLE = 45,
ASPECT = WIDTH / HEIGHT,
NEAR = 0.1,
FAR = 10000,
renderer = new THREE.WebGLRenderer(),
camera = new THREE.Camera(VIEW_ANGLE, ASPECT, NEAR, FAR),
scene = new THREE.Scene(),
texture = THREE.ImageUtils.loadTexture('crate.gif'),
material = new THREE.MeshBasicMaterial({map: texture}),
// material = new THREE.MeshPhongMaterial({color: 0xCC0000});
geometry = new THREE.PlaneGeometry(100, 100),
mesh = new THREE.Mesh(geometry, material),
pointLight = new THREE.PointLight(0xFFFFFF);
camera.position.z = 200;
renderer.setSize(WIDTH, HEIGHT);
scene.addChild(mesh);
world.appendChild(renderer.domElement);
pointLight.position.x = 50;
pointLight.position.y = 50;
pointLight.position.z = 130;
scene.addLight(pointLight);
renderer.render(scene, camera);
}
The problem is, I cannot see anything. If I change the material and use the commented one, a square appears as I would expect. Note that
The texture is 256x256, so its sides are power of two
The function is actually called when the body is loaded; indeed it works with a different material.
It does not work even if I serve the file from a webserver, so it is not an issue of cross-domain policy not allowing to load the image.
What I am I doing wrong?
By the time the image is loaded, the renderer has already drawn the scene, hence it is too late. The solution is to change
texture = THREE.ImageUtils.loadTexture('crate.gif'),
into
texture = THREE.ImageUtils.loadTexture('crate.gif', {}, function() {
renderer.render(scene);
}),
Andrea solution is absolutely right, I will just write another implementation based on the same idea.
If you took a look at the THREE.ImageUtils.loadTexture() source you will find it uses the javascript Image object. The $(window).load event is fired after all Images are loaded ! so at that event we can render our scene with the textures already loaded...
CoffeeScript
$(document).ready ->
material = new THREE.MeshLambertMaterial(map: THREE.ImageUtils.loadTexture("crate.gif"))
sphere = new THREE.Mesh(new THREE.SphereGeometry(radius, segments, rings), material)
$(window).load ->
renderer.render scene, camera
JavaScript
$(document).ready(function() {
material = new THREE.MeshLambertMaterial({ map: THREE.ImageUtils.loadTexture("crate.gif") });
sphere = new THREE.Mesh(new THREE.SphereGeometry(radius, segments, rings), material);
$(window).load(function() {
renderer.render(scene, camera);
});
});
Thanks...
In version r75 of three.js, you should use:
var loader = new THREE.TextureLoader();
loader.load('texture.png', function ( texture ) {
var geometry = new THREE.SphereGeometry(1000, 20, 20);
var material = new THREE.MeshBasicMaterial({map: texture, overdraw: 0.5});
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
});
In version r82 of Three.js TextureLoader is the object to use for loading a texture.
Loading one texture (source code, demo)
Extract (test.js):
var scene = new THREE.Scene();
var ratio = window.innerWidth / window.innerHeight;
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight,
0.1, 50);
var renderer = ...
[...]
/**
* Will be called when load completes.
* The argument will be the loaded texture.
*/
var onLoad = function (texture) {
var objGeometry = new THREE.BoxGeometry(20, 20, 20);
var objMaterial = new THREE.MeshPhongMaterial({
map: texture,
shading: THREE.FlatShading
});
var mesh = new THREE.Mesh(objGeometry, objMaterial);
scene.add(mesh);
var render = function () {
requestAnimationFrame(render);
mesh.rotation.x += 0.010;
mesh.rotation.y += 0.010;
renderer.render(scene, camera);
};
render();
}
// Function called when download progresses
var onProgress = function (xhr) {
console.log((xhr.loaded / xhr.total * 100) + '% loaded');
};
// Function called when download errors
var onError = function (xhr) {
console.log('An error happened');
};
var loader = new THREE.TextureLoader();
loader.load('texture.jpg', onLoad, onProgress, onError);
Loading multiple textures (source code, demo)
In this example the textures are loaded inside the constructor of the mesh, multiple texture are loaded using Promises.
Extract (Globe.js):
Create a new container using Object3D for having two meshes in the same container:
var Globe = function (radius, segments) {
THREE.Object3D.call(this);
this.name = "Globe";
var that = this;
// instantiate a loader
var loader = new THREE.TextureLoader();
A map called textures where every object contains the url of a texture file and val for storing the value of a Three.js texture object.
// earth textures
var textures = {
'map': {
url: 'relief.jpg',
val: undefined
},
'bumpMap': {
url: 'elev_bump_4k.jpg',
val: undefined
},
'specularMap': {
url: 'wateretopo.png',
val: undefined
}
};
The array of promises, for each object in the map called textures push a new Promise in the array texturePromises, every Promise will call loader.load. If the value of entry.val is a valid THREE.Texture object, then resolve the promise.
var texturePromises = [], path = './';
for (var key in textures) {
texturePromises.push(new Promise((resolve, reject) => {
var entry = textures[key]
var url = path + entry.url
loader.load(url,
texture => {
entry.val = texture;
if (entry.val instanceof THREE.Texture) resolve(entry);
},
xhr => {
console.log(url + ' ' + (xhr.loaded / xhr.total * 100) +
'% loaded');
},
xhr => {
reject(new Error(xhr +
'An error occurred loading while loading: ' +
entry.url));
}
);
}));
}
Promise.all takes the promise array texturePromises as argument. Doing so makes the browser wait for all the promises to resolve, when they do we can load the geometry and the material.
// load the geometry and the textures
Promise.all(texturePromises).then(loadedTextures => {
var geometry = new THREE.SphereGeometry(radius, segments, segments);
var material = new THREE.MeshPhongMaterial({
map: textures.map.val,
bumpMap: textures.bumpMap.val,
bumpScale: 0.005,
specularMap: textures.specularMap.val,
specular: new THREE.Color('grey')
});
var earth = that.earth = new THREE.Mesh(geometry, material);
that.add(earth);
});
For the cloud sphere only one texture is necessary:
// clouds
loader.load('n_amer_clouds.png', map => {
var geometry = new THREE.SphereGeometry(radius + .05, segments, segments);
var material = new THREE.MeshPhongMaterial({
map: map,
transparent: true
});
var clouds = that.clouds = new THREE.Mesh(geometry, material);
that.add(clouds);
});
}
Globe.prototype = Object.create(THREE.Object3D.prototype);
Globe.prototype.constructor = Globe;
Without Error Handeling
//Load background texture
new THREE.TextureLoader();
loader.load('https://images.pexels.com/photos/1205301/pexels-photo-1205301.jpeg' , function(texture)
{
scene.background = texture;
});
With Error Handling
// Function called when download progresses
var onProgress = function (xhr) {
console.log((xhr.loaded / xhr.total * 100) + '% loaded');
};
// Function called when download errors
var onError = function (error) {
console.log('An error happened'+error);
};
//Function called when load completes.
var onLoad = function (texture) {
var objGeometry = new THREE.BoxGeometry(30, 30, 30);
var objMaterial = new THREE.MeshPhongMaterial({
map: texture,
shading: THREE.FlatShading
});
var boxMesh = new THREE.Mesh(objGeometry, objMaterial);
scene.add(boxMesh);
var render = function () {
requestAnimationFrame(render);
boxMesh.rotation.x += 0.010;
boxMesh.rotation.y += 0.010;
sphereMesh.rotation.y += 0.1;
renderer.render(scene, camera);
};
render();
}
//LOAD TEXTURE and on completion apply it on box
var loader = new THREE.TextureLoader();
loader.load('https://upload.wikimedia.org/wikipedia/commons/thumb/9/97/The_Earth_seen_from_Apollo_17.jpg/1920px-The_Earth_seen_from_Apollo_17.jpg',
onLoad,
onProgress,
onError);
Result:
https://codepen.io/hiteshsahu/pen/jpGLpq/
Use TextureLoader to load a image as texture and then simply apply that texture to scene background.
new THREE.TextureLoader();
loader.load('https://images.pexels.com/photos/1205301/pexels-photo-1205301.jpeg' , function(texture)
{
scene.background = texture;
});
Result:
https://codepen.io/hiteshsahu/pen/jpGLpq?editors=0011
See the Pen Flat Earth Three.JS by Hitesh Sahu (#hiteshsahu) on CodePen.

Categories