Threejs add labels - javascript

Following some previous post on stackoverflow I am trying to add labels in my canvas.
I made a second scene and second camera to overlap my labels on first scene.
this.sceneOrtho = new THREE.Scene();//for labels
this.scene = new THREE.Scene();// for Geometry
//camera for geometry
var SCREEN_WIDTH = window.innerWidth-5, SCREEN_HEIGHT = window.innerHeight-5;
var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20;
this.camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
var r = 4, phi = Math.PI/4, theta = Math.PI/4;
this.camera.position.set(r*Math.cos(phi)*Math.sin(theta),r*Math.sin(phi), r*Math.cos(phi)*Math.cos(theta));
this.camera.lookAt(new THREE.Vector3(0, 0, 0));
// camera for labels
this.cameraOrtho = new THREE.OrthographicCamera( VIEW_ANGLE, ASPECT, NEAR, FAR );
this.cameraOrtho.position.z = 10;
I also added THREE.Sprite object to the scene sceneOrtho.add(spritey);
and rendered this.model.clearScene(this.scene);
this.model.populateScene(this.scene,this.sceneOrtho);//<--------
this.renderer.clear();
this.renderer.render(this.scene, this.camera);
this.renderer.clearDepth();
this.renderer.render( this.sceneOrtho, this.cameraOrtho );
but I can see only the geometries and not my labels.
Here there is a live example click on button test to see it.

I guess scene is rendering right, but your orthographic camera is looking in bad direction. I don't see setting lookAt for your ortho camera.
And yes as #westlangley write, this is not useful for others.

Related

Rendering Complicated Models in Three.js

if some rockstar could look through my code real quick and tell me why I cant render/see my three.js model I'd be forever in your debt!
I'll post the whole script, but I think some preliminary info is important. Basically, I have thousands of points that look like this:
472232.14363148 2943288.56768013 200.129142"
472237.03086105 2943289.62356560 200.119496"
472241.91809061 2943290.67945108 200.109851"
472246.80532018 2943291.73533656 200.100205"
...and so on...
and a bunch of faces that look like this:
["1021 1020 1061", "640 754 641", "1534 1633 1535", "4701 27 26", "654 753 655", ...and so on...
When I extracted all the data and configured it correctly I then push it to the geometry and try to add it to the scene but with no success. Here's the whole script:
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.set( 0, 50, 50 );
camera.lookAt( 0, 0, 0 );
var scene = new THREE.Scene();
var material = new THREE.MeshStandardMaterial( { color : 0x00cc00 } );
var geometry = new THREE.Geometry();
var points = bigData['LandXML']['Surfaces']['Surface']['Definition']['Pnts']['P']
var faces = bigData['LandXML']['Surfaces']['Surface']['Definition']['Faces']['F']
for(i=0;i<points.length;i++){
var [point1,point2,point3] = points[i]['__text'].split(' ').map(Number)
//point1 *= .00001
//point2 *= .00001
//point3 *= .00001
geometry.vertices.push(new THREE.Vector3(point1,point2,point3))
}
for(i=0;i<faces.length;i++){
console.log(faces[i]);
var [face1,face2,face3] = faces[i].split(' ').map(Number)
var face = new THREE.Face3(face1 - 1,face2 - 1, face3 - 1)
geometry.faces.push(face)
}
scene.add( new THREE.Mesh( geometry, material ) );
You can see that in the for loop for the points, I have multiplied them by .00001 to scale the model because otherwise the numbers are so huge, if that makes sense. And I subtract 1 from each face because the data was not zero indexed. Anyways, if any coding superhero took the time to read this and has some insight, please help me out! Thanks!
So, I found your model on scene, the code missed those parts:
Your model has big coordinates, but small dimension. After dividing
all coordinates by 100.000 it has boundingSphere center at (4.72;
29,432; 0,00192) and boundingSphere radius 0,00480, So you need
to either translate model so it has center at (0;0;0) or move camera
target to it's center;
geometry.computeFaceNormals() must be called after building faces
in order to make faces resposive to lighting and shading;
Scene needs some light in it. In curent state it will not show
anything
Render loop or at least single call after adding mesh is required.
Here is fixed code, additionally I played with camera distance and added simple rotation animation. Also I used geometry translation approach to have an adequate rotation:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>DXF Test</title>
</head>
<body>
<script src="three.min.js"></script>
<script type="text/javascript" src="JFM.js"></script>
<script>
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000);
camera.position.set(0, 650, 650);
camera.lookAt(0, 0, 0);
var scene = new THREE.Scene();
var material = new THREE.MeshStandardMaterial({color: 0x00cc00});
var geometry = new THREE.Geometry();
//geometry.vertices.push(new THREE.Vector3(4.72227256402, 29.4328751179, 0.00200138787));
//geometry.vertices.push(new THREE.Vector3(3, 3, 0));
//geometry.vertices.push(new THREE.Vector3(5, 6, 0));
//var line = new THREE.Line( geometry, material );
//scene.add( line );
//renderer.render( scene, camera );
var points = bigData['LandXML']['Surfaces']['Surface']['Definition']['Pnts']['P'];
var faces = bigData['LandXML']['Surfaces']['Surface']['Definition']['Faces']['F'];
console.log('Complete XML file');
console.log(bigData);
console.log('POINTS');
console.log(points);
console.log('FACES');
console.log(faces);
for (i = 0; i < points.length; i++) {
var [point1, point2, point3] = points[i]['__text'].split(' ').map(Number);
geometry.vertices.push(new THREE.Vector3(point1, point2, point3));
}
for (i = 0; i < faces.length; i++) {
var [face1, face2, face3] = faces[i].split(' ').map(Number);
var face = new THREE.Face3(face1 - 1, face3 - 1, face2 - 1);
geometry.faces.push(face)
}
geometry.computeFaceNormals();
geometry.computeBoundingSphere();
// translate model so it's real center will be the same as mesh pivot
geometry.translate(
-geometry.boundingSphere.center.x,
-geometry.boundingSphere.center.y,
-geometry.boundingSphere.center.z
);
// compute bounding sphere again, because it was broken during translation
geometry.computeBoundingSphere();
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
var sunLight = new THREE.DirectionalLight(0xffffff);
sunLight.position.set(200, 600, 1000);
scene.add(sunLight);
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
mesh.rotation.y += 0.01;
mesh.rotation.x += 0.01;
}
animate();
</script>
</body>
</html>
If you don't like translation, you can remove it, remove rotation and after computeBoundingSphere do like this:
camera.position.set(
geometry.boundingSphere.center.x + geometry.boundingSphere.radius,
geometry.boundingSphere.center.y + geometry.boundingSphere.radius,
geometry.boundingSphere.center.z + geometry.boundingSphere.radius,
);
camera.lookAt(
geometry.boundingSphere.center.x,
geometry.boundingSphere.center.y,
geometry.boundingSphere.center.z,
);
Hope it will help.

How to set vertical angle of spherebuffergeometry? Why Orbit controls don't work properly when mesh is rotated?

I am having issues trying to set the default view of a panoramic image inside spherebuffergeometry. I have a mesh that makes use of this geometry and the material is an equirectangle panorama image. During runtime, the default view of the image is somewhere towards the right. I want the initial angle to be at the bottom of the camera. I tried changing the Phi angle and theta angle parameters of spherebuffergeometry. While I am able to move the default horizontal angle by changing Phi angle, the panoramic image looks weird when I change the theta angle.
I took the first two snapshots when phi angle was 0 and 100 respectively and theta angle was 0. I took the last snapshot when phi angle was 100 and theta angle was 1.
Any help would be appreciated.
Thanks
sphereBufferGeometry = new THREE.SphereGeometry(100,100,100,0,Math.PI*2,0,Math.PI); sphereBufferGeometry.scale( 1, 1, -1 );
var material = new THREE.MeshBasicMaterial( {
map: new THREE.TextureLoader().load([image] )
});
mesh = new THREE.Mesh( sphereBufferGeometry, material );
I have tried this as well.
init();
var scene,renderer,camera;
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 100);
var light = new THREE.PointLight(0xffffff, 0.8);
var light2 = new THREE.DirectionalLight( 0xffddcc, 1 );
light.position.set( 1, 0.75, 0.5 );
scene.add( light2 );
var sphereBufferGeometry = new THREE.SphereGeometry(100, 100, 100, 0, Math.PI * 2, 0, Math.PI);
sphereBufferGeometry.scale(1, 1, -1);
var material = new THREE.MeshBasicMaterial({
map: new THREE.TextureLoader().load('https://threejs.org/examples/textures/2294472375_24a3b8ef46_o.jpg')
});
var mesh = new THREE.Mesh(sphereBufferGeometry, material);
mesh.rotation.x=1.6;
scene.add(camera);
scene.add(light);
scene.add(mesh);
renderer = new THREE.WebGLRenderer({
antialias: true,
preserveDrawingBuffer: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
var orbitControls = new THREE.OrbitControls(camera, renderer.domElement);
camera.position.set(0, 0, 0.001);
orbitControls.update();
var container = document.getElementById('container');
var canvas = renderer.domElement;
canvas.setAttribute("class", "frame");
container.appendChild(canvas);
document.body.appendChild(container);
animate();
}
function animate()
{
requestAnimationFrame(animate);
renderer.render( scene, camera );
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/105/three.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<div id="container"></div>
. As you can see, I've rotated the mesh so that the default view is looking at the floor.. if we click and drag the mouse upwards such that the window in the view is horizontal and then click and drag left or right, orbit controls don't seem to work properly in that it doesn't give a proper panoramic experience.. I would like to know how can this be fixed

Why am I not able to scale or set position of a mesh in three.js?

As you can see below, I added a mesh to the scene but everytime I try to scale it or set position, I get an error that the mesh is null.
mesh2.position.set(0,0,-5);
mesh2.scale.set(0.2, 0.3, 0.2);
Uncaught TypeError: Cannot read property 'position' of null
check it out at testing2.site44.com
Please help as I have wasted hours trying to get this to work.
function init()
{
var scene = new THREE.Scene();//CREATE NEW THREE JS SCENE
var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
var renderer = new THREE.WebGLRenderer({antialias:true}); //INIT NEW THREE JS RENDERER
renderer.setPixelRatio( window.devicePixelRatio ); //SET PIXEL RATIO FOR MOBILE DEVICES
renderer.setClearColor(new THREE.Color('#005b96'), 1) //SET BG COLOR
renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT); // SET SIZE
document.body.appendChild( renderer.domElement ); //APPLY CANVAS TO BODY
renderer.domElement.id = "canvas_threeJS";//ADD ID TO CANVAS
//ADD CAMERA TO THE SCENE
var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR =1000;
var camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
camera.position.set(0,3,8); //SET CAMERA POSITION
camera.lookAt(new THREE.Vector3(0,0,-5));
scene.add(camera);
//ADD AMBIENT LIGHT
var ambientLight = new THREE.AmbientLight("#6497b1");
scene.add(ambientLight);
//HANDLE WINDOW RESIZE
//ADD MAIN LIGHT
var light = new THREE.PointLight("#b3cde0",.6);
light.position.set(-5,13,-1);
scene.add(light);
var mesh2 = null;
var loader = new THREE.JSONLoader();
loader.load('assets/models/spaceship001.json', function(geometry) {
mesh2 = new THREE.Mesh(geometry);
scene.add(mesh2);
console.log("done loading model");
});
mesh2.position.set(0,0,-5);
// mesh2.scale.set(0.2, 0.3, 0.2);
//START POSITION OF A LEVEL GROUP
var levelSpawn = -100;
//GET VISIBLE WIDTH AT levelSpawn POSITION
var vFOV = camera.fov * Math.PI / 180; // convert vertical fov to radians
var height = 2 * Math.tan( vFOV / 2 )*levelSpawn; // visible height
var aspect = window.innerWidth / window.innerHeight;
var width = height * aspect;// visible width
//START RENDER
update();
function update()
{
//UPDATE 3D SCENE
renderer.render( scene, camera );
//KEEP RENDERING
requestAnimationFrame( update );
}
}
The problem is that javascript is an asynchronous language. Depending on your background you should read up on that. Try putting a console.log("setting scale and postion") just under or above those two lines. What you'll notice is that the position and scale is set before the mesh is loaded.
What you need to do is set the position and scale inside the callback function that you pass to the load function, just under the console.log("done loading model"); line.
You can also read up on javascript Promises to understand it better.

Orbiting around the origin using a device's orientation

I am trying to replicate the functionality of Google's Cardboard Demo "Exhibit" with three.js. I took the starting example straight from the Chrome Experiments web page and just dropped in code to draw a simple triangular pyramid in the init method:
function init() {
renderer = new THREE.WebGLRenderer();
element = renderer.domElement;
container = document.getElementById('example');
container.appendChild(element);
effect = new THREE.StereoEffect(renderer);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(90, 1, 0.001, 700);
camera.position.set(0, 0, 50);
scene.add(camera);
controls = new THREE.OrbitControls(camera, element);
controls.rotateUp(Math.PI / 4);
controls.noZoom = true;
controls.noPan = true;
var geometry = new THREE.CylinderGeometry( 0, 10, 30, 4, 1 );
var material = new THREE.MeshPhongMaterial( { color:0xffffff, shading: THREE.FlatShading } );
var mesh = new THREE.Mesh( geometry, material );
mesh.updateMatrix();
mesh.matrixAutoUpdate = false;
scene.add( mesh );
var light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 1, 1, 1 );
scene.add( light );
light = new THREE.DirectionalLight( 0x002288 );
light.position.set( -1, -1, -1 );
scene.add( light );
light = new THREE.AmbientLight( 0x222222 );
scene.add( light );
function setOrientationControls(e) {
if (!e.alpha) {
return;
}
controls = new THREE.DeviceOrientationControls(camera);
controls.connect();
controls.update();
element.addEventListener('click', fullscreen, false);
window.removeEventListener('deviceorientation', setOrientationControls, true);
}
window.addEventListener('deviceorientation', setOrientationControls, true);
window.addEventListener('resize', resize, false);
setTimeout(resize, 1);
}
The OrbitControls method on desktop works perfectly: by dragging with the mouse, the screen orbits around the pyramid. On mobile using DeviceOrientationControls however, this effect is entirely lost and instead the camera moves freely at (0, 0, 0). I tried doing as a previous question suggested and replacing the camera with scene such that:
controls = new THREE.DeviceOrientationControls(scene);
however this does not work at all and nothing moves when the device is rotated. What do I need to change to replicate OrbitControls behavior with the motion captured by DeviceOrientationControls?
To create a deviceorientation orbit controler, like you see on this demo, http://novak.us/labs/UmDemo/; It involves modifying the existing OrbitControls.js.
The file changes can be seen in this commit on github: https://github.com/snovak/three.js/commit/f6542ab3d95b1c746ab4d39ab5d3253720830dd3
I've been meaning to do a pull request for months. Just haven't gotten around to it. Needs a bunch of clean up.
You can download my modified OrbitControls.js here (I haven't merged in months either, results may vary): https://raw.githubusercontent.com/snovak/three.js/master/examples/js/controls/OrbitControls.js
Below is how you would implement the modified OrbitControls in your own scripts:
this.controls = new THREE.OrbitControls( camera, document.getElementById('screen') ) ;
controls.tiltEnabled = true ; // default is false. You need to turn this on to control with the gyro sensor.
controls.minPolarAngle = Math.PI * 0.4; // radians
controls.maxPolarAngle = Math.PI * 0.6; // radians
controls.noZoom = true ;
// How far you can rotate on the horizontal axis, upper and lower limits.
// If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ].
controls.minAzimuthAngle = - Math.PI * 0.1; // radians
controls.maxAzimuthAngle = Math.PI * 0.1; // radians
this.UMLogo = scene.children[1];
controls.target = UMLogo.position;
I hope that gets you where you want to be! :-)
To use the DeviceOrientationControls You must call controls.update() during your animation loop or the control will not update it's position based on device info.

Drawing a Line3 in Threejs

I want to draw a Line3 in a Threejs and here is my code for it:
start = new THREE.Vector3(20, 10, 0);
end = new THREE.Vector3(200, 100, 0);
var line = new THREE.Line3(start, end);
scene.add(line);
The code doesn't give any error but it doesn't draw the line either.
In the same program, I also have a sphere:
var initScene = function () {
window.scene = new THREE.Scene();
window.renderer = new THREE.WebGLRenderer({
alpha: true
});
window.renderer.setClearColor(0x000000, 0);
window.renderer.setSize(window.innerWidth, window.innerHeight);
window.renderer.domElement.style.position = 'fixed';
window.renderer.domElement.style.top = 0;
window.renderer.domElement.style.left = 0;
window.renderer.domElement.style.width = '100%';
window.renderer.domElement.style.height = '100%';
document.body.appendChild(window.renderer.domElement);
var directionalLight = new THREE.DirectionalLight( 0xffffff, 1 );
directionalLight.position.set( 0, 0.5, 1 );
window.scene.add(directionalLight);
window.camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
window.camera.position.fromArray([0, 150, 700]);
window.camera.lookAt(new THREE.Vector3(0, 160, 0));
window.addEventListener('resize', function () {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.render(scene, camera);
}, false);
scene.add(camera);
// set up the sphere vars
var radius = 50,
segments = 16,
rings = 16;
// create a new mesh with
// sphere geometry - we will cover
// the sphereMaterial next!
var sphereMaterial =
new THREE.MeshLambertMaterial(
{
color: 0xCC0000
});
var sphere = new THREE.Mesh(
new THREE.SphereGeometry(
radius,
segments,
rings),
sphereMaterial);
// add the sphere to the scene
scene.add(sphere);
start = new THREE.Vector3(20, 10, 0);
end = new THREE.Vector3(200, 100, 0);
var line = new THREE.Line3(start, end);
scene.add(line);
renderer.render(scene, camera);
};
initScene();
I only see the sphere on the screen. Can you please tell me where I am wrong?
ADLADS (A Day Late and A Dollar Short):
From http://threejs.org/docs/
Line3 is one of many math objects of three.js that can be used to compute geometric stuff. Others are:
Box2 Box3 Color Euler Frustum Line3 Math Matrix3 Matrix4 Plane Quaternion Ray Sphere Spline Triangle Vector2 Vector3 Vector4
Say you had your "line", a Line3 object and "plane", a Plane object. You could check if the line intersected the plane by doing plane.intersectsLine(line). Would give true or false.
NONE OF THESE MATH OBJECTS (including Line3's) are Object3D's, the things to be rendered.
Here's the scoop:
1) Make the scene, the camera, and the renderer.
2) Add Object3D's to the scene.
2a) Object3D's can be Points, Lines, or Meshes.
2b) Points, Lines, and Meshes are made of Geometries and Materials.
2c1) for Points and Lines, the Geometries contain vertices(Vector3's) and faces(Face3's). Do "vertices.push" or "faces.push".
2c2) for Meshes, Geometries can be: Box Circle Cylinder Dodecahedron Extrude Icosahedron Lathe Octahedron Parametric Plane Polyhedron Ring Shape Sphere Tetrahedron Text Torus TorusKnot Tube
3) Do "renderer.render(scene, camera)".
Thanks for the question. It straightened me out.
For the sphere, you create a geometry (SphereGeometry) and pass it as argument to create a mesh (sphere) that has a material, so it can be drawed. Your line is a 2-vertices geometry, you need to create the corresponding mesh :
var lineMesh=new THREE.Line(
line,//the line3 geometry you have yet
new THREE.LineBasicMaterial({color:0x0000ff})//basic blue color as material
);
scene.add(lineMesh);

Categories

Resources