Cesium - why is scene.pickPositionSupported false - javascript

I'm ultimately trying to draw a polygon on top of my house. I can do that.
The problem is that on zoom-out, zoom-in, and rotation (or camera move) the polygon doesn't stick to the top of my house. I received great help from this answer. So, now I'm trying to go through the sample code but there is a lot of Cesium methods and functionality that I need to learn.
The sample code I am trying to follow is located in the gold standard that appears to be baked into the existing camera controller here.
I call testMe with the mousePosition as Cartesian3 and the SceneMode is 3D, so pickGlobe is executed.
Here is my code:
var pickedPosition;
var scratchZoomPickRay = new Cesium.Ray();
var scratchPickCartesian = new Cesium.Cartesian3();
function testMe(mousePosition) {
if (Cesium.defined(scene.globe)) {
if(scene.mode !== Cesium.SceneMode.SCENE2D) {
pickedPosition = pickGlobe(viewer, mousePosition, scratchPickCartesian);
} else {
pickedPosition = camera.getPickRay(mousePosition, scratchZoomPickRay).origin;
}
}
}
var pickGlobeScratchRay = new Cesium.Ray();
var scratchDepthIntersection = new Cesium.Cartesian3();
var scratchRayIntersection = new Cesium.Cartesian3();
function pickGlobe(viewer, mousePosition, result) {
var globe = scene.globe;
var camera = scene.camera;
if (!Cesium.defined(globe)) {
return undefined;
}
var depthIntersection;
if (scene.pickPositionSupported) {
depthIntersection = scene.pickPosition(mousePosition, scratchDepthIntersection);
}
var ray = camera.getPickRay(mousePosition, pickGlobeScratchRay);
var rayIntersection = globe.pick(ray, scene, scratchRayIntersection);
var pickDistance;
if(Cesium.defined(depthIntersection)) {
pickDistance = Cesium.Cartesian3.distance(depthIntersection, camera.positionWC);
} else {
pickDistance = Number.POSITIVE_INFINITY;
}
var rayDistance;
if(Cesium.defined(rayIntersection)) {
rayDistance = Cesium.Cartesian3.distance(rayIntersection, camera.positionWC);
} else {
rayDistance = Number.POSITIVE_INFINITY;
}
var scratchCenterPosition = new Cesium.Cartesian3();
if (pickDistance < rayDistance) {
var cart = Cesium.Cartesian3.clone(depthIntersection, result);
return cart;
}
var cart = Cesium.Cartesian3.clone(rayIntersection, result);
return cart;
}
Here is my problem:
Here is the result:
Here are my questions to get this code working:
1. How do I get the scene.pickPositionSupported set to true? I'm using Chrome on Windows 10. I cannot find in the sample code anything about this and I haven't had much luck with the documentation or Google.
2. Why is rayIntersection not getting set? ray and scene have values and scratchRayIntersection in an empty Cartesian3.
I think if I can get those two statements working, I can probably get the rest of the pickGlobe method working.
WebGLGraphics Report:
I clicked on Get WebGL and the cube is spinning!

Picking positions requires that the underlying WebGL implementation support depth textures, either through the WEBGL_depth_texture or WEBKIT_WEBGL_depth_texture extensions. scene.pickPositionSupported is returning false because this extension is missing. You can verify this by going to http://webglreport.com/ and looking at the list of extensions; I have both of the above listed there. There is nothing you can do in your code itself to make it suddenly return true, it's a reflection of the underlying browser.
That being said, I know for a fact that Chrome supports the depth texture and it works on Windows 10, so this sounds like a likely video card driver issue. I full expect downloading and installing the latest drivers for your system to solve the problem.
As for rayIntersection, from a quick look at your code I only expect it to be defined if the mouse is actually over the globe, which may not always be the case. If you can reduce this to a runnable Sandcastle example, it would be easier for me to debug.

OK. So it turned out that I had a totally messed up Cesium environment. I had to delete it and reinstall it in my project (npm install cesium --save-dev). Then I had to fix a few paths and VOILA! It worked. Thanks to both of you for all your help.

Related

Three.js : Box3 from an object not in scene

I have a problem adding a Bounding Box from an object in a different module. Right now, it is working fine as long as I write everything in my main function, but as soon as I create my function in a different file, and import in in the main file, it's not working anymore.
The error code I get :
Uncaught TypeError: Cannot read properties of undefined (reading 'updateWorldMatrix')
at Box3.expandByObject (three.module.js:4934:10)
at Box3.setFromObject (three.module.js:4852:15)
at camCollision (camColliders.js:68:37)
at HTMLDocument.<anonymous> (World.js:355:7)
camColliders.js being the file I'm trying to put the function in, and World.js my main file.
Here is the function :
function camCollision() {
const camBB = new Box3().setFromObject(camSphereDetector);
const boule1BB = new Box3().setFromObject(boule1Obj);
boule1BB.name = 'first';
const boule2BB = new Box3().setFromObject(boule2Obj);
boule2BB.name = 'second';
const boule3BB = new Box3().setFromObject(boule3Obj);
boule3BB.name = 'third';
const boulesBB = [boule1BB, boule2BB, boule3BB];
boulesBB.forEach((bbs) => {
if (bbs.intersectsBox(camBB)) {
console.log('got it');
}
});
}
document.addEventListener('mouseup', () => {
camCollision();
});
When I'm doing this in a separate file, i'm first importing the objects from another file and they are all Mesh.
I believe the problem is that I can't create the Bounding Boxes in a separate file, because it needs to be added to the scene first, and I'm only adding them in the scene in World.js. Yet, the error is leading me to line 68, the variable for 'boule1BB', which is weird because 'camBB' should have the problem first ?
Here is how I'm creating the Box3 (these are just copying some GLTF objects position and size, cause I can't manage to get a Box3 from it) :
const boule1Obj = new Mesh(
new SphereGeometry(2, 32, 16),
new MeshBasicMaterial({ color: 'red', transparent: true, opacity: 0 }),
);
boule1Obj.position.set(10, -3.5, 0);
Then, I would like to know, if I got the problem right : is there a way to create a Box3 in a different js file, from an object that is not added to the scene yet (even if it should when the function is being called) ? With a different way than 'setFromObject' maybe ? Or am I not understanding the real problem.
For a bit of context, the aim is to provide some informations about each model when the user clicks on it, and I'm planning on putting the informations as '.name' for each Mesh corresponding to a model. So I don't want to write all this stuff in the main file, but rather on a separate one.
I hope this is clear enough, and I've given enough content for a solution to be found. I couldn't find anyone else having this problem. If you need anything else, please tell me !
Thanks already for your help !
I believe the problem is that I can't create the Bounding Boxes in a separate file, because it needs to be added to the scene in World.js.
Not so. Since a constructed THREE.Mesh has a shape with extents (from its geometry) and a transform (by default, translated to the origin, with no scaling or rotation), Three.js can and will determine a bounding box from that information as though the mesh were in the scene. I've posted a demo of this on CodePen.
Nor should defining the object in one file and referencing it another make any difference, as long as the object is in scope and initialized at the time it's bound to.
Here, I suspect that you're assigning boule1Obj, boule2Obj, and boule3Obj in World.js. In that case, the imported function is being hoisted before the variables are assigned, and the function is seeingbinding to them as unassignedundefined.
Try changing camCollision() to accept the bouleXObjs as arguments.
function camCollision(...objs) {
const camBB = new Box3().setFromObject(camSphereDetector);
for(let i = 0; i < objs.length; i++) {
const objBB = new Box3().setFromGeometry(objs[i]);
objBB.name = `Bounding Box ${i + 1}`;
if(objBB.intersectsBox(camBB)) {
console.log("Got it!");
}
}
}
And then call it as
document.addEventListener("mouseup", () => {
camCollision(boule1Obj, boule2Obj, boule3Obj);
});

Disable collision of body in Cannon.js

I have a bunch of planes that fit together to form terrain. Each individual plane has it's own cannon.js body (I use three.js for rendering visuals) for collision. Due to memory constraints I de-render each object when the player moves to far away from the object. I can de-render objects easily in three.js just by turning them invisible, but there's no clear way to do this in cannon.js. Basically I want to disable a cannon.js object without deleting it outright.
I've already looked through the docs and there's basically nothing on how to do this. I've also seen no questions on any form on this topic.
Example code below to show you how I want to implement this.
//terrain generation
for (z=0; z<6; z++) {
for (x=0; x<6; x++) {
//cannon.js hitbox creation
var groundShape = new CANNON.Box(new CANNON.Vec3(2,0.125,2));
var groundBody = new CANNON.Body({ mass: 0, material: zeromaterial});
groundBody.addShape(groundShape);
groundBody.position.set(x*4,0,z*4);
world.addBody(groundBody);
maparray.push(groundBody);
//three.js plane creation
grassmesh = new THREE.Mesh(grassgeometry, grassmaterial);
grassmesh.castShadow = true;
grassmesh.receiveShadow = true;
grassmesh.position.set(x*4,0,z*4);
scene.add(grassmesh);
maparray.push(grassmesh);
}
}
...
function animate() {
//detect if player is outside of loadDistance of object
for(i=0; i<maparray; i++){
if(Math.abs(maparray[i].position.x - player.position.x) <
loadDistance && Math.abs(maparray[i].position.z -
player.position.z) < loadDistance) {
//code here magically turns off collisions for object.
}
}
}
animate();
To exclude a CANNON.Body from the simulation, run the following:
world.removeBody(groundBody);
To add it back again, run:
world.addBody(groundBody);
It’s perfectly fine to remove and add it back like this. It will help you get better performance when running word.step().

javascript games ThreeJS and Box2D conflicts?

I've been trying to experiment with box2d and threejs.
So box2d has a series of js iterations, I've been successful at using them so far in projects as well as threejs in others, but I'm finding when including the latest instance of threejs and box2dweb, threejs seems to be mis-performing when just close to box2dweb but maybe I'm missing something really simple, like a better way to load them in together, or section them off from one another?
I've tried a few iterations of the box2d js code now and I always seemed to run into the same problem with later versions of threejs and box2d together! - currently version 91 threejs.
The problem I'm seeing is very weird.
I'm really hoping someone from either the box2d camp or threejs camp can help me out with this one, please?
Below is a very simple example where I don't initialize anything to do with box2d, but just by having the library included theres problems and you can test by removing that resource, then it behaves like it should.
The below demo uses threejs 91 and box2dweb. It is supposed to every couple of seconds create a box or a simple sphere each with a random colour. Very simple demo, you will see the mesh type never changes and the colour seems to propagate across all mesh instances. However if you remove the box2dweb resource from the left tab then it functions absolutely fine, very odd :/
jsfiddle link here
class Main {
constructor(){
this._container = null;
this._scene = null;
this._camera = null;
this._renderer = null;
console.log('| Main |');
this.init();
}
init(){
this.initScene();
this.addBox(0, 0, 0);
this.animate();
}
initScene() {
this._container = document.getElementById('viewport');
this._scene = new THREE.Scene();
this._camera = new THREE.PerspectiveCamera(75, 600 / 400, 0.1, 1000);
this._camera.position.z = 15;
this._camera.position.y = -100;
this._camera.lookAt(new THREE.Vector3());
this._renderer = new THREE.WebGLRenderer({antialias:true});
this._renderer.setPixelRatio( 1 );
this._renderer.setSize( 600, 400 );
this._renderer.setClearColor( 0x000000, 1 );
this._container.appendChild( this._renderer.domElement );
}
addBox(x,y,z) {
var boxGeom = new THREE.BoxGeometry(5,5,5);
var sphereGeom = new THREE.SphereGeometry(2, 5, 5);
var colour = parseInt(Math.random()*999999);
var boxMat = new THREE.MeshBasicMaterial({color:colour});
var rand = parseInt(Math.random()*2);
var mesh = null;
if(rand == 1) {
mesh = new THREE.Mesh(boxGeom, boxMat);
}
else {
mesh = new THREE.Mesh(sphereGeom, boxMat);
}
this._scene.add(mesh);
mesh.position.x = x;
mesh.position.y = y;
mesh.position.z = z;
}
animate() {
requestAnimationFrame( this.animate.bind(this) );
this._renderer.render( this._scene, this._camera );
}
}
var main = new Main();
window.onload = main.init;
//add either a box or a sphere with a random colour every now and again
setInterval(function() {
main.addBox(((Math.random()*100)-50), ((Math.random()*100)-50), ((Math.random()*100)-50));
}.bind(this), 4000);
so the way im including the library locally is just a simple...
<script src="js/vendor/box2dweb.js"></script>
So just by including the box2d library threejs starts to act weird, I have tested this across multiple computers too and multiple version of both box2d (mainly box2dweb) and threejs.
So with later versions of threejs it seems to have some comflicts with box2d.
I found from research that most of the box2d conversions to js are sort of marked as not safe for thread conflicts.
Im not sure if this could be the cause.
I also found examples where people have successfully used box2d with threejs but the threejs is always quite an old version, however you can see exactly the same problems occurring in my example, when I update them.
So below is a demo I found and I wish I could credit the author, but here is a copy of the fiddle using threejs 49
jsfiddle here
.....and then below just swapping the resource of threejs from 49 to 91
jsfiddle here
its quite an odd one and maybe the two libraries just don't play together anymore but would be great if someone can help or has a working example of them working together on latest threejs version.
I have tried a lot of different box2d versions but always found the same problem, could this be a problem with conflicting libraries or unsafe threads?
but also tried linking to the resource include in the fiddles provided.
Any help really appreciated!!

Colors are different in literally-drawing a real time collaborative board

I'm using Literally-Drawing which is real time collaborative drawing board.
Here is the Github and Demo link:
Github Literally-Drawing
Demo Link
This Repository is using two different libraries, one is Fabricjs and the second one is togetherjs, Initially there is only one default "PencilBrush" tool I wanted to add more tools into this but before that I was testing if I can dynamically change the color to "#ccc" or anything and brush type to "CircleBrush" They have connected together both the above mentioned libraries in the "Fabric-Whiteboard.js" file. There are two major functions WB.Core and WB.Collabrative. Core is creating the canvas and collabtive is pushing the data to Togetherjs server so that other browsers who are in the session can listen.
I have made some changes into Core.prototype._createCanvas function within WB.Core function originally it was only creating the canvas so I changed it to add "CircleBrush"
Originally
Core.prototype._createCanvas = function(id)
{
return new fabric.Canvas(id);
};
Changed to
Core.prototype._createCanvas = function(id)
{
var canvasCreate = new fabric.Canvas(id);
canvasCreate.freeDrawingBrush = new fabric['CircleBrush'](canvasCreate);
canvasCreate.freeDrawingBrush.color = "#CCCCCC";
return canvasCreate;
};
Now this part is working fine i guess because it is giving any error also i have made some change in the "drawStart" within WB.Collaborate function.
Originally
this.TJS.hub.on('drawStart', function(data)
{
var _base, _name;
if ((_base = _this.client)[_name = data.clientId] == null)
{
_base[_name] = new fabric['PencilBrush'](canvas); // origianlly
}
return _this.client[data.clientId].onMouseDown(data.point);
});
Problem:
The problem is I want the same drawing to be broadcasted to other sessions and if I add following two lines it gives me an error of "Cannot set property 'color' of undefined" where as I can override the default value within WB.core successfully.
Tried to Change it to:
this.TJS.hub.on('drawStart', function(data)
{
var _base, _name;
if ((_base = _this.client)[_name = data.clientId] == null)
{
var testCanvas = new fabric['CircleBrush'](canvas); // origianlly
testCanvas.freeDrawingBrush.color = "#ccc";
_base[_name] = testCanvas;
}
return _this.client[data.clientId].onMouseDown(data.point);
});
JSFiddle:
Here is the JsFiddle I tried to make but for some reason real time collabration is not working on both my version and original one
MyJsFiddle: https://jsfiddle.net/mwgi2005/p7cwu9ao/7/
This is what it looks like, I have set the color to grey and tool type to "CircleBrush". When I draw in parent Window to the left, it is drawing in grey color where as the child window is drawing in the black which is the default color defined in the fabric library, and vice versa.
Thanks

VisualStudio Intellisense issues with JavaScript object that are part of a namespace

I'm giving it my best shot at categorizing this correctly. I'm running into an intellisense issue where VisualStudio2013 (VS) won't suggest internal variables in certain situations.
Example: (This one works just fine)
function foo(){
this._someVar = true;
}
var bar = new foo();
bar._someVar // Autocomplete is working here.
Example (This one is not suggesting ._someVar)
var namespace = {};
namespace.foo = function(){
this._someVar = true;
}
var bar = new namespace.foo();
bar._som- // Autocomplete is not woking here.
Has anyone else run across this issue? How did you get around it or fix it? I've been searching for a fix for about an hour now. Thanks.

Categories

Resources