I found an example online and in this example that shows a 3D model (a Ferris wheel) placed on a parking lot with a Google Street View Panorama as the background.
Now I want to replace the Ferris wheel with another 3d object — an asteroid — that I download as a 3DS and OBJ. file. I converted the 3DS file to JSON through Blender but when I replace the file it just shows a blank screen.
How can I do it? Here is my code:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Street View Overlay - EINA</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
margin: 0px;
overflow: hidden;
}
p {
font-family:sans-serif;
font-size:11px;
font-weight:bold;
color:#111111;
}
</style>
</head>
<body>
<div id="streetviewpano" style="position: absolute; top:0; bottom:0; left:0; right:0; z-index: 0">
</div>
<div id="container" style="position: absolute; top:0; bottom:100px; left: 0; right: 0; z-index: 100;">
</div>
<script type="text/javascript" src="https://maps.google.com/maps/api/js?sensor=false"></script>
<script src="lib/jquery-2.0.3.js"></script>
<script src="lib/jquery.mousewheel.js"></script>
<script src="lib/three.min.js"></script>
<script src="lib/Detector.js"></script>
<script src="src/streetviewoverlay.js"></script>
<script>
var METERS2DEGREES = 0.0000125;
var objectPosition = [48.804828,2.1203071];
function hackMapProjection(lat, lon, originLat, originLon) {
var lonCorrection = 1.5;
var rMajor = 6378137.0;
function lonToX(lon) {
return rMajor * (lon * Math.PI / 180);
}
function latToY(lat) {
if (lat === 0) {
return 0;
} else {
return rMajor * Math.log(Math.tan(Math.PI / 4 + (lat * Math.PI / 180) / 2));
}
}
var x = lonToX(lon - originLon) / lonCorrection;
var y = latToY(lat - originLat);
return {'x': x, 'y': y};
}
function latLon2ThreeMeters(lat, lon) {
var xy = hackMapProjection(lat, lon, objectPosition[0], objectPosition[1]);
return {'x': xy.x, 'y': 0, 'z': -xy.y};
}
var jsonLoader = new THREE.JSONLoader();
jsonLoader.load( "model3d/wheel.js", loadWheel );
function loadWheel(geometry, materials) {
var mesh;
mesh = new THREE.Mesh(geometry, new THREE.MeshFaceMaterial(materials));
meshPos = latLon2ThreeMeters(objectPosition[0], objectPosition[1]);
mesh.geometry.computeBoundingBox();
var xsize = mesh.geometry.boundingBox.max.x - mesh.geometry.boundingBox.min.x;
var ysize = mesh.geometry.boundingBox.max.y - mesh.geometry.boundingBox.min.y;
var zsize = mesh.geometry.boundingBox.max.z - mesh.geometry.boundingBox.min.z;
var desiredXSize = 10;
var desiredYSize = 10;
var desiredZSize = 10;
mesh.scale.x = desiredXSize / xsize;
mesh.scale.y = desiredYSize / ysize;
mesh.scale.z = desiredZSize / zsize;
mesh.position.x = meshPos.x;
mesh.position.y = meshPos.y - 2; // the parking lot is sligthly under the street level
mesh.position.z = meshPos.z;
mesh.rotation.y = Math.PI/2;
mesh.castShadow = true;
var streetViewOverlay = StreetViewOverlay();
streetViewOverlay.load({streetView: true, objects3D: true, webGL:true}, mesh,48.8049084,2.120357);
}
</script>
</body>
</html>
So here's the thing.. you can covert to three.json format, and that's fine, but the version of your conversion tools have to match the version of three you're using.. you also want to be on close to the most recent three.js version..
but a large issue is that the three.json format is still somewhat in flux between versions, so I have had situations in the past where previously exported models go stale.
If I we're you .. I would use the OBJLoader and load your OBJ directly, or use a format like GLTF or Collada, and their respective loaders. Those formats are less likely to age. Especially GTLF looks like its heading toward being widely supported and has a lot of nice features that make it very efficient for realtime 3d.
r.e. your specific problem: First I would ask if you see any errors in the console from when you load your model. Second, I would put a debug breakpoint on the line inside the loader, and visually inspect the scene and its .children,
OR log it in the code with a scene.traverse((elem)=>{console.log(elem.type,elem);});
If that doesn't show at least one "Mesh" it means your conversion may have had problems.. if it does show, it could mean the mesh is too tiny to see, too Huge to see, or maybe the material is accidently transparent or many other possibilities. At that point, you can look at the mesh.geometry and make sure it has vertices and elements within it...
Failing all that:
If you try with OBJLoader or some other loader, and still can't get it to work.. check back with us. :)
Related
So I'm coming from two years of teaching myself unity/c# and am starting to feel like I have the coding chops to move from an engine to a framework so I have more control over the environment. I've completed the first few steps of first person environment stuff and wanted to split up my code into seperate files. In c# this is very easy, you just include a:
class className = new className();
for whatever class is in the same folder, but it seems to be less easy in javascript to accomplish this. My attempts so far have led to me losing all three.js functionality.
//Edit://This is what I tried from my knowledge of c#:
initializeObjects(scene);// on the native html javascript function
function initializeObjects(scene){ code referring to 3js scene object}// on the satellite scripts
but it isn't reacting the way I'd imagine(as in no errors, but no functionality either). I need to figure out how to write to console on a website build. This is all new to me.
is the answer:
var currentMesh = mesh;//?
I don't have time to test it right now.
//end Edit//
Any tips? I will include all code below.
var mesh, floorMesh;
function initializeObjects(scene){
mesh = new THREE.Mesh(
new THREE.BoxGeometry(2,2,2, 4, 4, 4),
new THREE.MeshPhongMaterial({color:'green', wireframe:false})
);
mesh.position.y = 2;
mesh.receiveShadow = true;
mesh.castShadow = true;
scene.add(mesh);
floorMesh = new THREE.Mesh(
new THREE.PlaneGeometry(100, 100, 10, 10),
new THREE.MeshPhongMaterial({color:'grey', wireframe:false})
);
floorMesh.rotation.x -= Math.PI /2;
floorMesh.receiveShadow = true;
scene.add(floorMesh);
ambientLight = new THREE.AmbientLight('blue', .3);
scene.add(ambientLight);
light = new THREE.PointLight('white', 0.8, 18);
light.position.set(-3, 6, -3);
light.castShadow = true;
light.shadow.camera.near = 0.1;
light.shadow.camera.far = 25;
light.shadowMapHeight = 2048;
light.shadowMapWidth = 2048;
scene.add(ambientLight);
}
function objectUpdate(){
mesh.rotation.x += 0.01;
mesh.rotation.y += 0.01;
}
//this is the start of the first person script
var keyboard = {};
var player = { height:1.8, speed:1, turnSpeed:Math.PI * 0.02 };
var camera;
function initializeControls(scene){
camera = new THREE.PerspectiveCamera (90, window.innerWidth/window.innerHeight, 0.1, 1000);
camera.position.set(0, player.height,-4);
camera.lookAt(new THREE.Vector3(0,player.height,0));
scene.add(camera);
}
function checkInput(){
if(keyboard[87]){
camera.position.x -= Math.sin(camera.rotation.y) * player.speed;
camera.position.z -= -Math.cos(camera.rotation.y) * player.speed;
}
if(keyboard[83]){
camera.position.x += Math.sin(camera.rotation.y) * player.speed;
camera.position.z += -Math.cos(camera.rotation.y) * player.speed;
}
if(keyboard[65]){
camera.position.x += Math.sin(camera.rotation.y + Math.PI/2) * player.speed;
camera.position.z += -Math.cos(camera.rotation.y + Math.PI/2) * player.speed;
}
if(keyboard[68]){
camera.position.x += Math.sin(camera.rotation.y - Math.PI/2) * player.speed;
camera.position.z += -Math.cos(camera.rotation.y - Math.PI/2) * player.speed;
}
if(keyboard[37]){
camera.rotation.y -= player.turnSpeed;
}
if(keyboard[39]){
camera.rotation.y += player.turnSpeed;
}
}
function keyDown(event){
keyboard[event.keyCode] = true;
}
function keyUp(event){
keyboard[event.keyCode] = false;
}
window.addEventListener('keydown', keyDown);
window.addEventListener('keyup', keyUp);
<script src="https://github.com/mrdoob/three.js/blob/dev/build/three.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<title>Demo 1</title>
<meta charset="UTF-8">
<style>
body {
background-color: #000000;
margin: 0px;
overflow: hidden;
}
a {
color:#0078ff;
}
</style>
<script type="text/javascript" src = "https://github.com/mrdoob/three.js/blob/dev/build/three.min.js"></script>
<script type="text/javascript" src = "objectManager.js"></script>
<script type="text/javascript" src = "firstPersonController.js"></script>
</head>
<body>
</body>
<script>
var scene, renderer;
function init(){
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(window.innerWidth, window.innerHeight);
initializeControls(scene);
initializeObjects(scene);
renderer.shadowMap.enabled = true;
renderer.shadowMapSoft = true;
renderer.shadowMapType = THREE.PCFSoftShadowMap;
document.body.appendChild(renderer.domElement);
updateRenderer();
}
function updateRenderer(){
requestAnimationFrame(updateRenderer);
checkInput();
objectUpdate();
}
window.onload = init();
</script>
</html>
JavaScript does not (yet) have an implemented native module system. Its been ratified, but not implemented. Leaving you a few different options:
Option 1: Global namespace variables, aka the Revealing Module Pattern:
This is a pretty common approach. Looks like this in code:
// top-level name declaration
window.myNamespace = (function() {
// internal implementation stuff goes here
return {
// public API goes here, for example
fooMethod: function (n) {
return n + 'foo';
}
};
})();
Then in another file you can just say
// remember myNamespace is a global variable.
myNamespace.fooMethod('bar'); // 'barfoo'
This has a couple of disadvantages though. First, if you're using a lot of third-party libraries there's a pretty good chance of a name collision. This is particularly true if the code modifies a global object like Array or Object. It also requires a fair amount of effort from the developer to maintain.
Option 2 Third party module system. See this for a more in-depth discussion.
In Js only functions create a new scope, but global stuff is available everywhere. Classes and inheritance is different to most other languages.
Tutorials: scoping,
Prototypal inheritance.
Google will give you more infos.
By the way, you defined var keyboard = {}; and later used keyboard as array.
So ultimately what I did (this is contingent on the website thing I think, I wouldn't know how javascript compiles besides a website at this point) is put all of the variables on the first loaded script. It's definitely confusing to think about as a c# coder, but that was the thing that made everything work, and then from there I just broke up the code exactly as it was written already and placed it on separate files. It's working like a charm and I'm ready to start working through more functionality. Wanted to mark one of the answer's right, but there was a few extra steps I needed to take with the information I was given. Thanks everyone for your help.
I found a cool animation on codepen that takes a map (img) and reconstruct it with blocks. The js files needed is three.min.js and TweenMax.min.js I took the links from codepen and pasted it into my head within <script src=""></script>. After copying every css and html (not much) it apears that three.min.js got an error(?).
I opened google chrome console and saw three.min.js:536 Uncaught TypeError: Cannot read property 'width' of null.
heres the codepen animation im reffering to:
http://codepen.io/Mamboleoo/pres/JYJPJr
My code:
<!DOCTYPE html>
<html>
<head>
<?php include $_SERVER["DOCUMENT_ROOT"] . "/assets/head.php"; ?>
<title><?php echo $address; ?> - Credits</title>
</head>
<body>
<?php include $_SERVER["DOCUMENT_ROOT"] . "/navigationbar.php"; ?>
<script>
var renderer, scene, camera, ww, wh, particles;
ww = window.innerWidth,
wh = window.innerHeight;
var centerVector = new THREE.Vector3(0, 0, 0);
var previousTime = 0;
var getImageData = function(image) {
var canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0);
return ctx.getImageData(0, 0, image.width, image.height);
}
var drawTheMap = function() {
var geometry = new THREE.Geometry();
var material = new THREE.PointsMaterial({
size: 3,
color: 0x313742,
sizeAttenuation: false
});
for (var y = 0, y2 = imagedata.height; y < y2; y += 2) {
for (var x = 0, x2 = imagedata.width; x < x2; x += 2) {
if (imagedata.data[(x * 4 + y * 4 * imagedata.width) + 3] > 128) {
var vertex = new THREE.Vector3();
vertex.x = Math.random() * 1000 - 500;
vertex.y = Math.random() * 1000 - 500;
vertex.z = -Math.random() * 500;
vertex.destination = {
x: x - imagedata.width / 2,
y: -y + imagedata.height / 2,
z: 0
};
vertex.speed = Math.random() / 200 + 0.015;
geometry.vertices.push(vertex);
}
}
}
particles = new THREE.Points(geometry, material);
scene.add(particles);
requestAnimationFrame(render);
};
var init = function() {
THREE.ImageUtils.crossOrigin = '';
renderer = new THREE.WebGLRenderer({
canvas: document.getElementById("map"),
antialias: true
});
renderer.setSize(ww, wh);
renderer.setClearColor(0x1d1f23);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(50, ww / wh, 0.1, 10000);
camera.position.set(-100, 0, 220);
camera.lookAt(centerVector);
scene.add(camera);
texture = THREE.ImageUtils.loadTexture("http://mamboleoo.be/lab/transparentMap.png", undefined, function() {
imagedata = getImageData(texture.image);
drawTheMap();
});
window.addEventListener('resize', onResize, false);
};
var onResize = function(){
ww = window.innerWidth;
wh = window.innerHeight;
renderer.setSize(ww, wh);
camera.aspect = ww / wh;
camera.updateProjectionMatrix();
};
var render = function(a) {
requestAnimationFrame(render);
for (var i = 0, j = particles.geometry.vertices.length; i < j; i++) {
var particle = particles.geometry.vertices[i];
particle.x += (particle.destination.x - particle.x) * particle.speed;
particle.y += (particle.destination.y - particle.y) * particle.speed;
particle.z += (particle.destination.z - particle.z) * particle.speed;
}
if(a-previousTime>100){
var index = Math.floor(Math.random()*particles.geometry.vertices.length);
var particle1 = particles.geometry.vertices[index];
var particle2 = particles.geometry.vertices[particles.geometry.vertices.length-index];
TweenMax.to(particle, Math.random()*2+1,{x:particle2.x, y:particle2.y, ease:Power2.easeInOut});
TweenMax.to(particle2, Math.random()*2+1,{x:particle1.x, y:particle1.y, ease:Power2.easeInOut});
previousTime = a;
}
particles.geometry.verticesNeedUpdate = true;
camera.position.x = Math.sin(a / 5000) * 100;
camera.lookAt(centerVector);
renderer.render(scene, camera);
};
init();
</script>
<style>
canvas{width:100%;height:100%;padding:0;margin:0;overflow: hidden;}
</style>
<div class="wrapper">
<canvas id="map"></canvas>
</div>
<div style="position:relative; clear:both;"></div>
<!--</body>-->
<?php include $_SERVER["DOCUMENT_ROOT"] . "/footer.php"; ?>
</body>
</html>
The problem was worked out in the comments, but for the sake of not leaving a question technically unanswered I will explain the process for anyone stumbling across this page after searching for the error posted in the question.
In the example which was posted in the question (which is utilizing PHP to load the Javascript, but that matters little for the actual problem at hand) the Javascript relating to ThreeJS is being executed before the DOM has loaded the canvas element. Obviously ThreeJS requires the Canvas element, as it attaches its various listeners and objects to it, so when attempting to access members related to the canvas element it was simply getting undefined.
The fix for this was to load ThreeJS and all code related to it after the DOM had loaded the elements, there are multiple methods of doing that (which you should search for, as I'm afraid I don't have the time to explain them all), but I will highlight one which I deem the easiest. The method is to put all of your DOM specific code (Javascript that interacts with the DOM) at the bottom of your body tag (not below it, inside it at the very bottom. As Vikas Kapadiya pointed out, it would not be valid HTML if it was below it)
The below snippet shows how Javascript is loaded in relation to the DOM:
<!DOCTYPE html>
<html lang="en">
<head>
<title></title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script>
var p = document.getElementById('example');
console.log("In head " + p);
</script>
</head>
<body>
<p id="example">Hello</p>
<script>
var p = document.getElementById('example');
console.log("In body " + p.innerHTML);
</script>
</body>
</html>
Output:
In head null
In body Hello
As dictated by the above, the code within the head tag could not access the innerHTML (refering to the text content of the p tag) due to being executed before the DOM was loaded. The code found at the bottom of the body tag could, as the DOM was loaded and then the browser stumbled upon the Javascript.
Here are some related links which could shed more light than I have:
Where should I put <script> tags in HTML markup?
Where to place JavaScript functions: <head>? <body>? or, after </html>?
Just move wrapper div to just after body tag . then include all js .
Like this
<body>
<div class="wrapper">
<canvas id="map"></canvas>
</div>
Well, been on html 5 apis and about two days ago stumbled on babylon js for 3d on html 5 using webgl; but the issue is that it is a new technology and not much work has been done with it and also not much videos tutorials as expected on it. So with three days using the technology, I have been able to try a little with the physics engine.
I want to rotate box 2 after adding the physics state but I can't do that. I can only rotate the object before adding the physics state.
I know in modern games, even objects on air can rotate and yet fall due to gravity. What can I do about this, will I have to remove the physics property, rotate object and re rotate the object. Below is my code:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
html, body {
overflow: hidden;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
#renderCanvas {
width: 100%;
height: 100%;
touch-action: none;
}
</style>
<script src="../js/babylon.2.0.js"></script>
<script src="../js/hand-1.3.8.js"></script>
<script src="../js/cannon.js"></script> <!-- optional physics engine -->
<!-- <script src="../js/Oimo.js"></script> New physics engine -->
</head>
<body>
<canvas id="renderCanvas"></canvas>
<script type="text/javascript">
// Get the canvas element from our HTML below
var canvas = document.querySelector("#renderCanvas");
// Load the BABYLON 3D engine
var MyScene = function(){
console.log("MyScene Activated: Trying to test Object Oriented Javascript With Babylon js")
};
MyScene.prototype.engine = new BABYLON.Engine(canvas, true);
MyScene.prototype.createScene = function(){
// Now create a basic Babylon Scene object
var scene = new BABYLON.Scene(this.engine);
scene.enablePhysics(null,new BABYLON.CannonJSPlugin());
scene.setGravity(new BABYLON.Vector3(0,-10,0));
// Change the scene background color to green.
scene.clearColor = new BABYLON.Color3(200, 1, 0.3);
var camera = new BABYLON.ArcRotateCamera("camera",1,1.4,53,new BABYLON.Vector3(0,0,0),scene);
// This attaches the camera to the canvas
camera.attachControl(canvas, false);
// This creates a light, aiming 0,1,0 - to the sky.
var light = new BABYLON.PointLight("light1", new BABYLON.Vector3(0, 0, 10), scene);
// Dim the light a small amount
light.intensity = .5;
MyScene.prototype.ball = BABYLON.Mesh.CreateSphere("sphere1", 16, 2, scene);
MyScene.prototype.ball.position.y = 10;
MyScene.prototype.ball.setPhysicsState({ impostor : BABYLON.PhysicsEngine.BoxImpostor, friction : 0.5 , mass: 10, restitution : 0.7});
MyScene.prototype.box1 = BABYLON.Mesh.CreateBox("box1",3,scene);
MyScene.prototype.box1.position.x = 3;
MyScene.prototype.box1.scaling.x = 1;
MyScene.prototype.box1.position.y = -6;
MyScene.prototype.box1.setPhysicsState({ impostor : BABYLON.PhysicsEngine.BoxImpostor, friction : 0.5 , mass: 10, restitution : 0.7});
MyScene.prototype.box2 = BABYLON.Mesh.CreateBox("box2",3,scene);
MyScene.prototype.box2.position.x = 6;
MyScene.prototype.box2.position.y = 10;
MyScene.prototype.box2.setPhysicsState({ impostor : BABYLON.PhysicsEngine.BoxImpostor, friction : 0.5 , mass: 10, restitution : 0.7});
MyScene.prototype.box3 = BABYLON.Mesh.CreateBox("box3",3,scene);
MyScene.prototype.box3.position.x = 1;
MyScene.prototype.box3.setPhysicsState({ impostor : BABYLON.PhysicsEngine.BoxImpostor, friction : 0.5 , mass: 10, restitution : 0.7});
MyScene.prototype.ground = BABYLON.Mesh.CreateBox("box",50,scene);
MyScene.prototype.ground.position.y = -10;
MyScene.prototype.ground.scaling.y = 0.1;
MyScene.prototype.ground.setPhysicsState({ impostor : BABYLON.PhysicsEngine.BoxImpostor, friction : 0.5 , mass: 0, restitution : 0.7});
// Leave this function
return scene;
};
MyScene.prototype.getEngine = function(){
return this.engine;
};
MyScene.prototype.scale = function(){
counter = 0;
while(counter <= 10){
MyScene.prototype.box2.rotate(BABYLON.Axis.X,counter,BABYLON.Space.LOCAL);
MyScene.prototype.box2.rotate(BABYLON.Axis.Y,counter,BABYLON.Space.LOCAL);
MyScene.prototype.box2.rotate(BABYLON.Axis.Z,counter,BABYLON.Space.LOCAL);
++counter;
}
}
MyScene.prototype.pos = function(){
this.box1.position.x += 0.2;
this.box1.scaling.x += 0.2;
this.box2.position.x += 0.2;
this.box2.scaling.x += 0.2;
this.box3.position.x += 0.2;
this.box3.scaling.x += 0.2;
};
var Myscene = new MyScene();
var scene = Myscene.createScene();
// Register a render loop to repeatedly render the scene
Myscene.getEngine().runRenderLoop(function () {
scene.render();
Myscene.scale();
});
// Watch for browser/canvas resize events
window.addEventListener("resize", function () {
Myscene.getEngine().resize();
});
</script>
</body>
</html>
when a mesh is under the control of the physics engine, you have to use this specific code after applying rotation changes: mesh.updatePhysicsBodyPosition()
This function will keep the physics simulation updated
I'm experiencing an odd issue while trying to load an OBJ and MTL file in Three.js using it's OBJMTLLoader() function and just can't seem to figure it out, or find a solution on Google. I have my index.html file inside of a folder, and also in that same folder is my js folder, which includes all external js files that I wrote for my project along with the three.js r68 library. Also in my root project folder is a folder named 'obj', which includes all of my obj files and their corresponding mtl files.
I initially started my project under a Windows system and was able to load everything just fine, no problem at all, but now I switched to my personal Linux system and I started seeing this problem and am unable to load any of my obj/mtl files any longer.
The error I am receiving is 'Uncaught TypeError: undefined is not a function' and I've tried printing out my 'loader' variable and it simply shows me in the console that it's an object of type OBJMTLLoader. Any thoughts on this?
EDIT: The first file is js/main.js, and the next one is index.html.
const WIDTH = 1200;
const HEIGHT = 700;
const VIEW_ANGLE = 45;
const ASPECT_RATIO = WIDTH / HEIGHT;
const NEAR = 0.1;
const FAR = 10000;
var renderer,
camera,
scene;
var pointLight, pointLight2;
var xrot = 0.0025,
yrot = 0.0025;
$(document).ready(function() {
// setup renderer, camera, perspective, etc.
initScene();
$('#loadfile').change(getLoadedFile);
$('input[type=range]').eq(0).change(showYRot);
// lights
pointLight = new THREE.PointLight(0xffffff);
pointLight.position.x = -10;
pointLight.position.y = 50;
pointLight.position.z = 130;
scene.add(pointLight);
pointLight2 = new THREE.PointLight(0xffffff);
pointLight2.position.x = 0;
pointLight2.position.y = 50;
pointLight2.position.z = 500;
scene.add(pointLight2);
var render = function() {
window.requestAnimationFrame(render);
$(scene.children).each(function() {
if (this !== camera && this !== pointLight) {
this.rotation.x = xrot;
this.rotation.y += yrot;
}
});
renderer.render(scene, camera);
};
render();
});
function initScene() {
renderer = new THREE.WebGLRenderer({
antialias: true
});
camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT_RATIO, NEAR, FAR);
scene = new THREE.Scene();
scene.add(camera);
camera.position.z = 250;
renderer.setSize(WIDTH, HEIGHT);
$('div#container').append(renderer.domElement);
}
function getLoadedFile(evt) {
var fileList = evt.target.files;
var filename = fileList[0].name;
if (filename.substring(filename.length - 4, filename.length) == '.obj') {
var obj = filename;
var mtl = filename.substring(0, filename.length - 4) + '.mtl';
console.log('adding ' + filename + ' to scene.');
loadOBJMTLModel(obj, mtl);
}
}
function loadOBJMTLModel(obj, mtl) {
var loader = new THREE.OBJMTLLoader();
loader.load('obj/' + obj, 'obj/' + mtl, function(object) {
scene.add(object);
});
}
<script src="https://threejs.org/examples/js/loaders/OBJMTLLoader.js"></script>
<script src="https://threejs.org/examples/js/loaders/OBJLoader.js"></script>
<script src="https://threejs.org/examples/js/loaders/MTLLoader.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/85/three.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>OBJ Model Previewer</title>
<style>
body {
background-color: lightgrey;
}
div#container {
width: 1200px;
height: 700px;
border: 1px solid grey;
}
</style>
<!-- <script src="js/main.js"></script> //-->
<body>
<h3>Choose file to load</h3>
<input id="loadfile" type="file" />
<br />
<div id="container"></div>
<br />
<span></span><br />
<span></span><br />
<br />
<span>Y Rotation: </span><input type="range" min="0.0" max="0.1" step="0.001" />
<span id="yrot"></span>
</body>
</html>
As requested.
OBJMTLLoader is deprecated. you must use MTLLoader and OBJLoader together. You can view a traditional example here: view-source:threejs.org/examples/webgl_loader_obj_mtl.html
There have also been numerous updates to objloader2.js available # https://github.com/mrdoob/three.js/blob/dev/examples/js/loaders/OBJLoader2.js
For a little more digging, see my previous answer for automated MTL loading here: Is there a way to load a mtl using the path in the obj file?
I am trying to apply a simple clustering stategy to my OpenLayers v2.13 map, but it is not working.
Here is my code so far, it all loads correctly but the random points on the map do not cluster, they just overlap horribly...
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8">
<title>OpenLayers 2.13.x Clustered Markers</title>
<script src="../OpenLayers.js"></script>
</head>
<body onload="run()" style="position: absolute; top: 0; bottom: 0; left: 0; right: 0;">
<div id='map' style="width: 100%; height: 100%">
</div>
<script>
function run(){
// create the map
var map = new OpenLayers.Map("map");
// add a google maps layer to the map
var layer = new OpenLayers.Layer.WMS("OpenLayers WMS", "http://vmap0.tiles.osgeo.org/wms/vmap0", {
layers: "basic"
});
map.addLayers([layer]);
// set up cluster strategy and vector layer
var strategy = new OpenLayers.Strategy.Cluster({
distance: 15,
clustering: true
});
var markersLayer = new OpenLayers.Layer.Vector("Clustered markers", {strategies: [strategy]});
// create and add all markers randomly
var markers = [];
for (var i = 0; i < 700; i++) {
var r1 = Math.random();
var r2 = Math.random();
var r3 = Math.random();
var r4 = Math.random();
var px = r1 * 180 * ((r2 < 0.5) ? -1 : 1);
var py = r3 * 90 * ((r4 < 0.5) ? -1 : 1);
var p = new OpenLayers.Geometry.Point(px, py);
var clazz = (i % 10 === 0) ? 4 : Math.ceil(r4 * 3);
var f = new OpenLayers.Feature.Vector(p, {clazz: clazz});
markers.push(f);
}
markersLayer.addFeatures(markers);
// add markers layer to the map
map.addLayer(markersLayer);
map.zoomToMaxExtent();
}
</script>
</body>
</html>
Note: OpenLayers is locally on my machine and is version 2.13.1
I have looked at several examples, none have helped me solve this issue. I have looked at several stack overflow answers, the best of them was about marker clustering, but also didn't help.
I must be missing something obvious but I cant see what?
[UPDATE]
Taking advice from the answers below, here is the code snippet (from above) edited to run correctly, adding the markers after the layer has been added to the map and not including the clustering flag...
// set up cluster strategy and vector layer
var strategy = new OpenLayers.Strategy.Cluster({
distance: 15 // <-- removed clustering flag
});
var markersLayer = new OpenLayers.Layer.Vector("Clustered markers", {strategies: [strategy]});
// add markers layer to the map
map.addLayer(markersLayer); // <-- adding layer before adding features
// create and add all markers randomly
var markers = [];
for (var i = 0; i < 700; i++) {
var r1 = Math.random();
var r2 = Math.random();
var r3 = Math.random();
var r4 = Math.random();
var px = r1 * 180 * ((r2 < 0.5) ? -1 : 1);
var py = r3 * 90 * ((r4 < 0.5) ? -1 : 1);
var p = new OpenLayers.Geometry.Point(px, py);
var clazz = (i % 10 === 0) ? 4 : Math.ceil(r4 * 3);
var f = new OpenLayers.Feature.Vector(p, {clazz: clazz});
markers.push(f);
}
markersLayer.addFeatures(markers); // <-- now can add features
// zoom to extent
map.zoomToMaxExtent();
It looks like maybe a good practice to follow is to make sure that you add a layer to the map before adding/removing features to it.
I removed "clustering" from the cluster strategy options
// set up cluster strategy and vector layer
var strategy = new OpenLayers.Strategy.Cluster({
distance: 15
});
and then added the markers after I'd added the layer to the map
// add markers layer to the map
map.addLayer(markersLayer);
markersLayer.addFeatures(markers);
map.zoomToMaxExtent();
then all seemed to work.
Mailed similar to Angela to you internally.
Not sure why removing clustering has any affect, I think its true by default anyway.
As for the order of adding the points, I seem to remember reading something about the fact your points are replaced by the clusters so adding the layer to map after adding points to layer may mean that process doesn't happen. Or something. ;)
Cheers
Ian