boundingSphere is null - TextGeometry, ThreeJS - javascript

I'm new at ThreeJS and trying to learn so I have basically create a text which is rendered 3D and I'm using TextGeometry and I need that object's size like width/height to always center the object.
I'm trying like this;
var objToCenter = scene.getObjectById(textGeoID);
var hey = objToCenter.geometry.boundingSphere.center.x;
console.log(hey);
First, I find the object and then assign boundingSphere.center.x value to new variable.
But I get "boundingSphere is null" error.
When I try to console.log objectToCenter, object is there and also boundingSphere is NOT null but when I try objectToCenter.boundingSphere it says null.
And interestingly when I go console and write these lines it works perfectly.
My full Code: (somehow fontloader not load the font from source url but it works in localhost,so pls try code in localhost or you can't see the text here)
// Scene, Camera, Renderer, GUI
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer( { antialias:true } );
var gui = new dat.GUI({name: 'Control Panel'});
// Renderer and Camera Settings
renderer.setSize( window.innerWidth, window.innerHeight-4 );
renderer.shadowMap.enabled = false;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
document.body.appendChild( renderer.domElement );
camera.position.set( 10, 10, 500 );
// Axiss Helper and Orbit Controls
var axesHelper = new THREE.AxesHelper( 500 );
scene.add( axesHelper );
var controls = new THREE.OrbitControls( camera, renderer.domElement );
// Variables for TextGeometry
var textData = {
text: "Yunus Emre Uzun",
size: 40,
height: 5,
curveSegments: 12,
font: "helvetiker",
weight: "regular",
bevelEnabled: false,
bevelThickness: 1,
bevelSize: 0.5,
bevelOffset: 0.0,
bevelSegments: 3
};
var textGeoID = null;
function generateTextGeometry() {
if (textGeoID!=null) {
console.log('ID: ' + textGeoID);
var object = scene.getObjectById(textGeoID);
//console.log('Object:');
//console.log(object);
object.geometry.dispose();
scene.remove(object);
}
var loader = new THREE.FontLoader();
loader.load( 'https://clofro.com/cdn/fonts/helvetiker_regular.typeface.json', function ( font ) {
var textGeometry = new THREE.TextGeometry( textData.text, {
font: font,
size: textData.size,
height: textData.height,
curveSegments: textData.curveSegments,
bevelEnabled: textData.bevelEnabled,
bevelThickness: textData.bevelThickness,
bevelSize: textData.bevelSize,
bevelOffset: textData.bevelOffset,
bevelSegments: textData.bevelSegments
} );
var textMaterial = new THREE.MeshBasicMaterial( { color: 0x444444, wireframe: true } );
var meshedObject = new THREE.Mesh( textGeometry, textMaterial );
meshedObject.position.set(-212, -15, 20 /* 15 */);
scene.add(meshedObject);
textGeoID = meshedObject.id;
centerTheText();
} );
}
function centerTheText() {
var objToCenter = scene.getObjectById(textGeoID);
console.log('Object bellow is objToCenter and its id is: ' + objToCenter.id);
console.log(objToCenter);
console.log('Error bellow is for: objToCenter.geometry.boundingSphere.center.x');
var hey = objToCenter.geometry.boundingSphere.center.x;
console.log(hey);
}
generateTextGeometry();
gui.add(textData, 'text').onChange(generateTextGeometry);
gui.add(textData, 'size', 5, 100).onChange(generateTextGeometry);
// Add Point Light
var pointLight = new THREE.PointLight(0xffffff, 0.3); pointLight.position.set(50, 0, 150);
pointLight.castShadow = true;
pointLight.shadow.mapSize.width = 2048;
pointLight.shadow.mapSize.height = 2048;
scene.add(pointLight);
// Random colors
//pointLight.color.setHSL(Math.random(), 1, 0.5);
// Add Ambiant Light - halogen ambient light
var ambientLight = new THREE.AmbientLight(0xFFF1E0, 0.4);
scene.add(ambientLight);
var width = 450;
var height = 60;
var intensity = 0.8;
var rectLight = new THREE.RectAreaLight( 0xff0000, intensity, width, height );
rectLight.position.set( 0, 0, 14 );
rectLight.rotation.y = 6.28;
rectLight.lookAt( 0,0,0 );
scene.add( rectLight )
gui.add(rectLight, 'intensity', 0,5);
rectLightHelper = new THREE.RectAreaLightHelper( rectLight );
rectLight.add( rectLightHelper );
// Create BackBox Shape
var backBoxGeo = new THREE.BoxGeometry(500, 75, 10);
// Create BackBox Material, color, texture
var backBoxMat = new THREE.MeshStandardMaterial( { color: 0xdaf1f9, wireframe: false, flatShading: false } );
var backBox = new THREE.Mesh( backBoxGeo, backBoxMat );
backBox.receiveShadow = true;
scene.add(backBox);
backBox.position.set(0, 0, 0);
// Resize Renderer Function
window.addEventListener('resize', function() {
renderer.setSize( window.innerWidth, window.innerHeight-4 );
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
});
// Update scene
var update = function() {
controls.update();
};
// Draw scene
var render = function() {
renderer.render( scene, camera );
};
// Frame loop (update, render, repeat)
var frameLoop = function() {
requestAnimationFrame( frameLoop );
update();
render();
}
frameLoop();
* {
margin: 0;
padding: 0;
}
body { background-color: #000; }
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>threeJS</title>
</head>
<body>
<script src="https://clofro.com/cdn/three.js"></script>
<script src="https://clofro.com/cdn/dat.gui.min.js"></script>
<script src="https://clofro.com/cdn/OrbitControls.js"></script>
</body>
</html>
My explanations with SS;
Screenshot 1:
Screenshot 2:
Why it could be happening? or can I use something else to center my text.
(set position not a fix because 0,0,0 is different for box objects and texts)

When you create an instance of TextGeometry, the respective bounding sphere is not available yet. However, it is automatically computed by the renderer for view frustum culling.
So if you have to access the bounding sphere of the geometry right after its creation, call objToCenter.geometry.computeBoundingSphere();.
Live Demo: https://jsfiddle.net/zcn2tpqy/
three.js R107

I know this is too old to answer, but I just want to share my solution here.
First, I just added this code:
geometry.computeBoundingSphere()
Then, access the boundingSphere like so:
geometry.boundingSphere
Overall code
geometry.computeBoundingSphere()
console.log(geometry.boundingSphere.radius)

Related

How to load all models with the same size and the same camera position?

I'm setting up a website that loads 3d models in ply format, and I'm using Three.js with his PLYLOADER to do that.
My problem is that every model is loading in a different position. I've managed to make them load in a perpendicular way with the ground, but some of them are looking, some are looking far away from the camera and others look like they turn around a Y axis (not their center).
This is my HTML div:
<div id="WebGL-output"></div>
This is my JS code:
<script type="text/javascript">
var lesson7 = {
scene: null,
camera: null,
renderer: null,
container: null,
controls: null,
clock: null,
stats: null,
init: function() { // Initialization
// create main scene
this.scene = new THREE.Scene();
this.scene.fog = new THREE.FogExp2(0xcce0ff, 0.0003);
var SCREEN_WIDTH = '800',
SCREEN_HEIGHT = '600';
// prepare camera
var VIEW_ANGLE = 60, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;
this.camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
this.scene.add(this.camera);
this.camera.position.set(0, 0, 300);
this.camera.lookAt(new THREE.Vector3(0,0,0));
// prepare renderer
this.renderer = new THREE.WebGLRenderer({ antialias:true });
this.renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
this.renderer.setClearColor(this.scene.fog.color);
this.renderer.shadowMapEnabled = true;
this.renderer.shadowMapSoft = true;
// prepare container
this.container = document.getElementById('WebGL-output');
this.container.appendChild(this.renderer.domElement);
// events
THREEx.WindowResize(this.renderer, this.camera);
// prepare controls (OrbitControls)
this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
this.controls.target = new THREE.Vector3(0, 0, 0);
this.controls.maxDistance = 20000;
// prepare clock
this.clock = new THREE.Clock();
this.scene.add( new THREE.AmbientLight(0xFFFFFF) );
// light
var dirLight = new THREE.DirectionalLight(0x606060);
dirLight.position.set(200, 200, 1000).normalize();
this.camera.add(dirLight);
this.camera.add(dirLight.target);
// load models
this.loadModels();
},
loadModels: function() {
// prepare PLY loader and load the model
var scene = new THREE.Scene();
var oPlyLoader = new THREE.PLYLoader();
oPlyLoader.load("../models/{{ $analysis->three_d_model }}", function(geometry) {
var material = new THREE.MeshPhongMaterial( { color: 0xAAAAAA, specular: 0x111111, shininess: 0 } );
var meshMaterial = material;
// if (geometry.hasColors) { // to fix when models will have colors
meshMaterial = new THREE.MeshPhongMaterial({ opacity: 1, vertexColors: THREE.VertexColors });
// }
var mesh = new THREE.Mesh(geometry, meshMaterial);
// Solution: center mesh to world origin
mesh.geometry.computeBoundingBox();
var bbox = mesh.geometry.boundingBox;
var centerVec = new THREE.Vector3();
bbox.getCenter(centerVec); // get center of bbox into centerVec
// move mesh so that center of bbox is placed to world origin
mesh.applyMatrix(new THREE.Matrix4().makeTranslation(-centerVec.x, -centerVec.y, -centerVec.z));
// proceed doing stuff
// mesh.position.set(0, -6, 0);
// mesh.scale.set(5, 5, 5);
lesson7.scene.add(mesh);
});
}
};
// Animate the scene
function animate() {
requestAnimationFrame(animate);
render();
update();
}
// Update controls and stats
function update() {
lesson7.controls.update(lesson7.clock.getDelta());
// lesson7.stats.update();
}
// Render the scene
function render() {
if (lesson7.renderer) {
lesson7.renderer.render(lesson7.scene, lesson7.camera);
}
}
// Initialize lesson on page load
function initializeLesson() {
lesson7.init();
animate();
}
if (window.addEventListener)
window.addEventListener('load', initializeLesson, false);
else if (window.attachEvent)
window.attachEvent('onload', initializeLesson);
else window.onload = initializeLesson;
</script>
I need help to make them all load with the same camera position, looking centred and in the same size.
PS: If i can have better results loading in different extension, I'm up for it.
Thanks in advance
EDIT:
I updated the code with the help of #alex. Now my models are very well centered. The only thing missing now si a fixed camera position however the model was saved
Currently see two solutions here ( if i understand correctly )
You objects are not centered correctly. The solution would be to open the model files in a 3d editor and set them all to the same size and make their center points consistent.
Once you load the model add it to an Object3D and find its center.
Docs about that here: https://threejs.org/docs/#api/en/core/Object3D
the below code this.objectAll is the Object3D. Which is put into a box and we make the controls look at the center of that box. If all model are consistent then this should work.
this.boundingBox = new THREE.Box3();
this.boundingBox.setFromObject(this.objectAll);
this.boundingBox.center(this.controls.target);
Best of luck!

Change color of three.js mesh using gui.dat

I have a three.js mesh loaded from an STL file:
var loader = new THREE.STLLoader();
var materialmodel = new THREE.MeshPhongMaterial(
{
color: 0xFF0000,
specular: 0x222222,
shininess: 75
}
);
function model()
{
loader.load( 'models/stl/binary/model.stl', function ( geometry ) {
var meshMaterial = materialmodel;
var model = new THREE.Mesh( geometry, meshMaterial );
model.scale.set( 0.02, 0.02, 0.02 );
model.castShadow = true;
model.receiveShadow = true;
model.geometry.center();
scene.add(model);
render();
} );
}
model();
When I call the model function in my page, the model renders as expected.
I want to use dat.gui to as a lightweight interface for on the fly changes.
My first experiment is changing the color of the model.
The code I'm using is this:
var params = {
modelcolor: 0xff0000, //RED
};
var gui = new dat.GUI();
var folder = gui.addFolder( 'Model Colour' );
folder.addColor( params, 'modelcolor' )
.name('Model Color')
.listen()
.onChange( function() { materialmodel.MeshPhongMaterial.color.set( params.modelcolor); } );
folder.open();
DAT.GUIs color picker appears fine, and I can select a color from the picker and the new hex value will display.
However, the model/mesh itself doesn't update with the newly selected colour.
I'm wondering if it's something to do with how I'm changing the color materialmodel.MeshPhongMaterial.color.set( params.modelcolor); (I've tried different ways of doing this with no luck).
I've seen a post here (one of the answers) where they're doing this using model.material.color.set(params.color) in their example. My owen material properties are defined in a variable using a THREE.MeshPhongMaterial.....
Assuming this is where I've gone wrong, how can I change the color dynamically of a nested prroperty buried in a variable like this?
I didn't get why did you use .listen(), possibly there's a certain reason.
In .onUpdate function you're using materialmodel, which is a material itself, and then you're setting .MeshPhongMaterial property that doesn't exist. Looks like you simply overlooked it.
Here is a working example:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 0, 10);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var light = new THREE.DirectionalLight(0xffffff, 0.5);
light.position.setScalar(10);
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
var materialmodel = new THREE.MeshPhongMaterial({
color: 0xFF0000,
specular: 0x222222,
shininess: 75
});
var geometrymodel = new THREE.SphereBufferGeometry(5, 32, 16);
var model = new THREE.Mesh(geometrymodel, materialmodel);
scene.add(model);
var params = {
modelcolor: "#ff0000"
};
var gui = new dat.GUI();
var folder = gui.addFolder('Model Colour');
folder.addColor(params, 'modelcolor')
.name('Model Color')
.onChange(function() {
materialmodel.color.set(params.modelcolor);
});
folder.open();
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/96/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.2/dat.gui.min.js"></script>

Threejs text doesn't render

Sorry, noob question here but I'm stuck for a while on this. I'm trying to get basic Threejs text to render. Other questions asking this on StackOverflow seem to be using older Threejs APIs. The following only shows a black screen. Thanks in advance...
<html>
<head>
<title>Text Test</title>
<style>
body { margin: 0; }
canvas { width: 100%; height: 100% }
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/85/three.js"></script>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var loader = new THREE.FontLoader();
var font = loader.load(
// resource URL
'helvetiker_bold.typeface.json',
// Function when resource is loaded
function ( font ) {
var geometry = new THREE.TextGeometry( 'Hello three.js!', {
font: font,
size: 80,
height: 5,
curveSegments: 12,
bevelEnabled: true,
bevelThickness: 10,
bevelSize: 8,
bevelSegments: 5
} );
var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
var textMesh = new THREE.Mesh( geometry, material );
scene.add( textMesh );
camera.position.z = 5;
var render = function () {
requestAnimationFrame( render );
renderer.render(scene, camera);
};
render();
},
// Function called when download progresses
function ( xhr ) {
console.log( (xhr.loaded / xhr.total * 100) + '% loaded' );
},
// Function called when download errors
function ( xhr ) {
console.log( 'An error happened' );
}
);
</script>
</body>
There's possible 2 issues.
You mentioned a warning WARNING: 0:1: extension 'GL_ARB_gpu_shader5' is not supported. That looks like it might be a bug in Firefox and Safari.
Otherwise your text is huge and your camera is too close.
Use
camera.position.z = 500;

Cannot initialize dat.GUI in Three.js

When i run my code, i get the following error in this line:
var gui = new dat.GUI();
error: Unable to get the 'getItem' property null reference or undefined.
I imported the library, i don't know what is wrong, here is my code:
<html>
<head>
<title>Stack Overflow</title>
<style>
body { margin: 0; }
canvas { width: 100%; height: 100% }
</style>
</head>
<body>
<div id="container"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="js/three.min.js"></script>
<script src="js/optimer_regular.typeface.js"></script>
<script src="js/TrackballControls.js"></script>
<script src="js/stats.min.js"></script>
<script src="js/threex.dynamictexture.js"></script>
<script src="js/dat.gui.min.js"></script>
<script>
//Basic Three components
var scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000 );
//position camera
camera.position.z = 700;
//Set camera controls
var controls = new THREE.TrackballControls( camera );
controls.rotateSpeed = 1.0;
controls.zoomSpeed = 1.2;
controls.panSpeed = 0.8;
controls.noZoom = false;
controls.noPan = false;
controls.staticMoving = true;
controls.dynamicDampingFactor = 0.3;
controls.keys = [ 65, 83, 68 ];
//Set the renderer
var renderer = new THREE.WebGLRenderer( { antialias: false } );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
//Set the lights
var light;
scene.add( new THREE.AmbientLight( 0x404040 ) );
light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 0, 1, 1 );
scene.add( light );
//Let's add a cute cube
var object;
var map = THREE.ImageUtils.loadTexture( 'images/UV_Grid_Sm.jpg' );
map.wrapS = map.wrapT = THREE.RepeatWrapping;
map.anisotropy = 16;
var material = new THREE.MeshLambertMaterial( { ambient: 0xbbbbbb, map: map, side: THREE.DoubleSide } );
object = new THREE.Mesh( new THREE.BoxGeometry( 100, 100, 100, 4, 4, 4 ), material );
object.position.set( 400, 20, 50 );
scene.add( object );
//Let's add a GUI
var API = {
'show model' : true,
'show skeleton' : false
};
var gui = new dat.GUI();
function animate() {
requestAnimationFrame( animate );
render();
}
//Render scene
function render() {
controls.update();
renderer.render( scene, camera );
}
animate();
</script>
</body>
</html>
Solution: Don't use Internet Explorer, i run the same code in Firefox and it works.
Follow this steps
First Close your existing project and open a new folder.
then go to this folder location in terminal by {cd [path]}
Run this commands:
1.https://github.com/designcourse/threejs-webpack-starter.git
2.npm install
3.npm run dev
4.npm run build
after no.3 execution you may face some warnings try to ignore or if you see some fatal issues then run
npm audit fix
not solved yet ....run..
npm audit fix --force [couple of time if need]
after running no.3 if you browser opens then all is fine.
you can dat.gui is installed in your folder just use it customize as you want.
you will find all the required files in your newly created folder.

Multi-platform (Chrome, IE, Firefox)

I don't undestand why this script doesn't work in IE, while it works in Firefox and Chrome. When I try to use this script in IE, I get this message "ACTIVEX stop script".
Please help me.
<!DOCTYPE html>
<html>
<head>
<title>Getting Started with Three.js</title>
<script type="text/javascript" src="http://www.html5canvastutorials.com/libraries/Three.js"></script>
<script type="text/javascript">
window.onload = function() {
var renderer = new THREE.WebGLRenderer();
renderer.setSize( 800, 600 );
document.body.appendChild( renderer.domElement );
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(
35, // Field of view
800 / 600, // Aspect ratio
0.1, // Near plane
10000 // Far plane
);
camera.position.set( 15, 10, 10 );
camera.lookAt( scene.position );
scene.add( camera );
var cube = new THREE.Mesh(
new THREE.CubeGeometry( 5, 5, 5 ),
new THREE.MeshLambertMaterial( { color: 0xFF0000 } )
);
scene.add( cube );
var light = new THREE.PointLight( 0xFFFF00 );
light.position.set( 10, 0, 10 );
scene.add( light );
renderer.render( scene, camera );
};
</script>
</head>
<body></body>
The Three.js WebGLRenderer doesn't work in IE (no WebGL support)
try
var renderer = new THREE.CanvasRenderer()
instead
As an alternative to the very simple solution above you can utilize alteredq and mrdoob's great Detector.js script that is included with the examples for three.js. If you use code like below you can use the WebGLRenderer as default and use canvas only if WebGL is not available. You can also use a flag like webglEnabled in order to set other options depending on your renderer later in your code.
var webglEnabled = false;
var webglReq = false;
if (Detector.webgl) {
renderer = new THREE.WebGLRenderer(
{
antialias: true,
preserveDrawingBuffer: true
}); // allow screenshot
webglEnabled = true; // set flag
}
else if (webglReq) { Detector.addGetWebGLMessage(); return false; }
else {
renderer = new THREE.CanvasRenderer();
}
renderer.setClearColorHex(0x000000, 1);
renderer.setSize(window.innerWidth, window.innerHeight);

Categories