Snouto

ArcCamera wierdness

Recommended Posts

Hi

 

So i've been doing a lot of testing lately and have had some excellent support from the experts on this board.

One of the things that's been bugging me all this time that I didnt mention was regarding the ArcCamera.

In my setup, when I create and activate an ArcCamera, I can rotate around a point with the left mouse button okay for a short while. If I happen to click the left or right button though, the camera moves in to pan mode and then I'm stuck and can not get out of it. When this happens the scene will zoom whenever I move the mouse, that's to say all movement of the mouse are reflected as zoom operations. Really strange, and this is with the code in place to stop the right click context menu appearing.

Unfortunately I can't replicate this in the PG because it never happens there - so i'm wondering if the PG is doing some specific setup outside of CreateScene that prevents the ArcCamera going mental?

 

Share this post


Link to post
Share on other sites

:) You wish.  heh.   Nope, the PG runs a clean ArcRotate with no special processing.  It's .inputs are default.

Almost for sure, you have something bound to the mousebuttons... that does SOMETHING to the camera, or switches cameras, or modifies the camera.inputs, or changes the camera's "up" vector.  Or, something happening on a setTimeout timer... that affects camera after some amount of time.

If you have animations on the camera, clean them off or make sure they don't auto-start or start with a click.

Try something like this... somewhere late in your code...

scene.beforeRender = function() {
    console.log(camera.alpha, camera.beta, camera.radius, camera.position);
}

When the change happens, does it happen on its own?  Or did you click a mouse button, and THEN it happens?

You KNOW that something has happened to your camera... when that sudden change happens.  Some code ran, and it attacked your cam.  It WAS working right, then it went broken.

Watch those 4 values being constantly sent to JS console.  Watch IF/HOW they change... when camera goes from normal... to crazy mode.

Make sure there is no mention of 'pointerLock' anywhere in your code.  If the camera has ANY animations, remove those.  See if the problem leaves.

I can't think of anything that would make an ArcCam go retarded... after a certain amount of usage-time.  SOMETHING is attacking your cam when you do SOMETHING.  Make sure no events such as onPointerEnter or onPick/onClick... are wired to the camera in ANY ways.   Try making  a 2nd arcCam named "test"... and set IT as scene.activeCamera... and attach it to canvas... see if IT has the same problem.

You can find the reason... I have faith in you.  :)  Simplify the scene, strip-off the junk, turn things off and remark-out code chunks... until the camera works properly again.  Go slow.  It is very possible... that you are rushing to add features and power to your scene... without fully understanding HOW to add those features and power.  It is a common thing for all of us.  We tend to try to take over the world... without first learning how to open our front doors.   :)  Ideas and enthusiasm "move" much faster than eyes can read docs, and faster than fingers can type test scenes. 

In other words, we sometimes "get ahead of ourselves".  This might be happening to you.  Keep testing and learning, logging EVERYTHING to JS console.  The JS console is your "eyes into the scene".

Keep your goals small for now.  That little "beforeRender" code-block above... runs FAST and repeatedly.  It is a great place/way to monitor values/properties continuously.

Revert/back-out-of modifications that cause problems.  Study the thing you added that caused the problem.  You know how it goes.  Find the thing that attacked your cam.  :)  It's there.  Is your scene code too messy to make it easy to find?  ahem.  You just need a little encouragement from Wingy.  :)  You may not see it, but you have TRIPLED your knowledge of BJS... in the past 10 days.  That's... pretty impressive.  You're on your way to becoming a BJS "hot shot".  Alright!  Kick its butt, snoutski.  :)  Gun-down the dirty rotten scoundrel what done yer camera wrong.  heh

Share this post


Link to post
Share on other sites

Thanks for that, I was just preparing the code so I could share in one go here rather than PG when I discovered the issue was gone. Working backwards, it very much looks like a JS loading issue. I don't get the problem if I load hand.js from cdnjs, however the problem remains if I load it locally. So there must be some sort of race condition happening or something. Strange.

 

Here's the code anyway should it need looking in to:

 

<!doctype html>
<html class="no-js" lang="en">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="x-ua-compatible" content="ie=edge">
        <title>babylon test 8 mobile stadium</title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <style>
		    html, body {
		        overflow: hidden;
		        width   : 100%;
		        height  : 100%;
		        margin  : 0;
		        padding : 0;
		    }

		    #renderCanvas {
		        width   : 100%;
		        height  : 100%;
		        touch-action: none;
		    }
		    #btnMute{
		    	display: inline-block;position: absolute;left:0;top: 0;color: white;background-color: rgba(10,10,10,0.65);z-index: 100;
		    }
		</style>
    </head>
    <body>
    	<a id="btnMute" href="#">Animate</a>
    	<canvas id="renderCanvas"></canvas>
		<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/babylonjs/3.0.1-alpha/babylon.js"></script>
		<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/handjs/1.3.11/hand.min.js"></script>
    	<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    	<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js"></script>
	   	<script>

	   		document.getElementsByTagName("body")[0].setAttribute("oncontextmenu", "return false");

	   		Math.Deg2Rad = function(angle){
			    return angle * (Math.PI / 180);
			};

			// Number.prototype.Deg2Rad = function(){
			//     return this * (Math.PI / 180);
			// };
		    $(function(){
		    	$("#btnMute").hide();
		    	var canvas = document.getElementById("renderCanvas");
		    	var antialias = true;
		        var adaptive = true;
		        var paused = false;
		        var loaded = false;
		        var scene = null;
		        var last = -1;
		        var show = true;
		        var title="Loading...";
        		var folder = "scenes_stadium/";
        		var sceneFile = "Demo_scene_mobile_sml.babylon";
        		var camera, music, doneSecondLoop=false, stadiumMesh, boxTarget, cameraTarget;
        		var cameraPathAnimationDuration = 10;
				var rig;


		    	BABYLON.Scene.prototype.showFps = function(args){
					args = args || {};
					var ioSpeed = args.ioSpeed || 30;
					var location = args.location || 'tl';
					var top = args.top || 0;
					var right = args.right || 0;
					var offset = {};
					args.offset = args.offset || {};
					offset.x = args.offset.x || 0;
					offset.y = args.offset.y || 0;

					var font = args.font || "Arial";
					var color = args.color || 'rgba(180,180,180,0.65)';
					var size = args.size || '12px';
					var padding = args.padding || '0.2em;'
					var background = args.background || 'rgba(10,10,10,0.65)';
					var n = document.createElement('div');
					n.setAttribute('id', 'fps-block');
					n.setAttribute('style',
					'position:absolute;'+
					'display:block;'+
					'z-index:10001;'+
					'font-family:Arial, Helvetica, sans-serif;'+
					'pointer-events:none;'+
					 'color:'+color+';'+
					 'font-size:'+size+';'+
					 'padding:'+padding+';'+
						'background-color:' + background + ';' +
						'right:' + right + "px;" +
						'top:' + top + 'px;');
						//'transform:translate(' + offset.x + ',' + offset.y + ');' );

					 n.innerHTML = "##&nbsp;fps";

					 document.body.appendChild(n);

					 var self = this;
					 var pE = self._engine;
					 function getFps() {
						 var b = document.getElementById('fps-block');
						 if (b) {
							 b.innerHTML = pE.getFps().toFixed() + " fps";
							 setTimeout(function () { getFps() }, 1000 / ioSpeed);
						 }
					 }

					 getFps();


					return n;
				};


				BABYLON.Scene.prototype.showCameraStats = function(args){
					args = args || {};
					var ioSpeed = args.ioSpeed || 30;
					var location = args.location || 'tl';
					var top = args.top || 0;
					var left = args.left || 0;
					var offset = {};
					args.offset = args.offset || {};
					offset.x = args.offset.x || 0;
					offset.y = args.offset.y || 0;

					var font = args.font || "Arial";
					var color = args.color || 'rgba(180,180,180,0.65)';
					var size = args.size || '12px';
					var padding = args.padding || '0.2em;'
					var background = args.background || 'rgba(10,10,10,0.65)';
					var n = document.createElement('div');
					n.setAttribute('id', 'camerastats-block');
					n.setAttribute('style',
					'position:absolute;'+
					'display:block;'+
					'z-index:10001;'+
					'font-family:Arial, Helvetica, sans-serif;'+
					'pointer-events:none;'+
					 'color:'+color+';'+
					 'font-size:'+size+';'+
					 'padding:'+padding+';'+
						'background-color:' + background + ';' +
						'left:' + left + "px;" +
						'top:' + top + 'px;' +
						'transform:translate(' + offset.x + ',' + offset.y + ');' );

					 n.innerHTML = "Camera x:#, y:#, alpha:#, beta:#, radius:#, fov:#";

					 document.body.appendChild(n);

					 var self = this;
					 var cam = window.camera;
					 function getCameraStats() {
						 var b = document.getElementById('camerastats-block');
						 if (cam && b) {
						 // 	var alpha=cam.alpha;
						 // 	var beta=cam.beta;
						 // 	var radius=cam.radius;
						 // 	var fov=cam.fov;
						 	var alpha=cam.rotation.x;
						 	var beta=cam.rotation.y;
						 	var radius=cam.rotation.z;
						 	var fov=cam.fov;

							 b.innerHTML = "Camera x:"+cam.position.x.toFixed()+", y:" + cam.position.y.toFixed() + ", alpha:" + alpha+", beta:"+beta+", radius:"+radius+", fov:"+fov.toFixed();
							 setTimeout(function () { getCameraStats() }, 1000 / ioSpeed);
						 }
					 }

					 getCameraStats();


					return n;
				};

				// Start project scene loader
		        var engine = new BABYLON.Engine(canvas, antialias, null, adaptive);
		        engine.clear(new BABYLON.Color3(1.0,1.0,1.0), true, true);
		        scene = new BABYLON.Scene(engine);

	        
		        var initCamera = new BABYLON.FreeCamera('camera', new BABYLON.Vector3(0, 0, 0), scene);

		        var assetsManager = new BABYLON.AssetsManager(scene);
		        assetsManager.addMeshTask("scene", "", folder, sceneFile);

    			assetsManager.onFinish = function(tasks) {
    				console.log("assetsManager.onFinish");

                    loaded = true;

			        scene.showFps();

			        attachSceneObjects();
			        attachCameraRig();
			        attachSceneCamera();
			        scene.showCameraStats({left:$(window).width()/2,offset:{x:"-100px"}});
			        attachSceneLights();

			        loadMusic();


		        };
		        assetsManager.load();


		        var attachSceneObjects=function(){
    				console.log("attachSceneObjects");
					var faceUV = new Array(6);
					for (var i = 0; i < 6; i++) {
						faceUV[i] =  new BABYLON.Vector4(0,0,0,0);
					}
					faceUV[0] = new BABYLON.Vector4(0,0,1,1);
					// var faceColors = new Array(6);

				 //    faceColors[0] = new BABYLON.Color4(1,1,1,1);
				 //    faceColors[1] = new BABYLON.Color4(0,1,0,1);
				 //    faceColors[2] = new BABYLON.Color4(0,0,1,1);
				 //    faceColors[3] = new BABYLON.Color4(1,1,0,1);
				 //    faceColors[4] = new BABYLON.Color4(1,0,1,1);
				 //    faceColors[5] = new BABYLON.Color4(0,1,1,1);

				    var options = {
				        width: 4.3,
				        height: 2.5,
				        depth: 0.2,
				        //faceColors : faceColors,
				        faceUV: faceUV
				    };

				    // Create stadium "screen", which also serves as a target
				    boxTarget = BABYLON.MeshBuilder.CreateBox('rig', options, scene);
				    boxTarget.rotate(BABYLON.Axis.Y, Math.Deg2Rad(-90), BABYLON.Space.LOCAL); // rotate rig so face is flush against stadium
				    boxTarget.position=new BABYLON.Vector3(7.45,-32.31,-0.43);
					boxTarget.material = new BABYLON.StandardMaterial("screenMaterial", scene);
					boxTarget.material.diffuseTexture = new BABYLON.Texture(
				        "textures/img1.jpg",
				        scene,
				        false, // mipmaps?
				        false // invert?
				    );
				    boxTarget.material.diffuseColor = new BABYLON.Color4.FromHexString("#FFFFFFFF");


				    // Create an initial camera target to look at as it moves along the plane
				    cameraTarget = BABYLON.Mesh.CreateSphere("sphere", 1, 1, scene);
				    cameraTarget.position=new BABYLON.Vector3(1.36,-33.26,-0.25);
				    var material = new BABYLON.StandardMaterial(scene);
					material.alpha = 0;
					material.color = new BABYLON.Color3(1.0, 1, 1);
					cameraTarget.material = material;

		        };

		        var attachCameraRig=function(){
    				console.log("attachCameraRig");

		        	// for(var i=0;i<scene.meshes.length;i++){
		        	// 	console.log(i,scene.meshes[i].name,scene.meshes[i].animations.length,scene.meshes[i]);
		        	// }


				    var options = {
				        width: 2,
				        height: 2,
				        depth: 2
				    };

				    rig = BABYLON.MeshBuilder.CreateBox('rig', options, scene);
				    var materialPlane = new BABYLON.StandardMaterial("texturePlane", scene);
					materialPlane.alpha = 0;
				    rig.material = materialPlane;

				    var path = [
				        new BABYLON.Vector3(1.36, -10.92896, -27.48694),
				        new BABYLON.Vector3(-23.13, -10.92896, -11.92295),
				        new BABYLON.Vector3(-22.51167, -10.92896, 11.80345),
				        new BABYLON.Vector3(0.7018204, -10.92896, 21.47452),
				        new BABYLON.Vector3(26.91983, -10.92896, 12.60011),
				        new BABYLON.Vector3(27.21525, -10.92896, -14.28558),
				        new BABYLON.Vector3(1.329925, -22.6645, -26.54726),
				        new BABYLON.Vector3(-19.69823, -26.40913, -2.560067),
				        new BABYLON.Vector3(-0.8958044, -31.88766, 0),
				        ];

				    var catmullRom = BABYLON.Curve3.CreateCatmullRomSpline(
				        path,
				        50
				    );

				    var catmullRomSpline = BABYLON.Mesh.CreateLines("catmullRom", catmullRom.getPoints(), scene);
				    catmullRomSpline.color=new BABYLON.Color3(1,0,0);

				    // Create Path3D from array of points
				    rig.points = catmullRom.getPoints();

				    // Position the rig to the starting position of the path
				    TweenLite.to(rig.position, 0, {
				    		x:rig.points[0].x,
				    		y:rig.points[0].y,
				    		z:rig.points[0].z,
				            indexPoint: 0,
				            ease: Linear.easeNone});

				    
		        };


		        var attachSceneCamera=function(){
    				console.log("attachSceneCamera");


				    camera = new BABYLON.ArcRotateCamera("ArcRotateCamera", 1.5, 1.5, 10, new BABYLON.Vector3(0, 0, 0), scene);
				    //camera.fov = 68;
				    camera.checkCollisions = false;
    				camera.wheelPrecision = 100;
				    //camera.maxZ = 500;
				    camera.attachControl(canvas, true);
				    scene.activeCamera=camera;
				    camera.parent=rig;

				    window.camera=camera;

					// Set the camera to initially look at the cameraTarget before the animation begins
			        rig.lookAt(cameraTarget.position);

				    //stadiumMesh = scene.getMeshByName("Stadium");


					    


		        };

		        var attachSceneLights=function(){
    				console.log("attachSceneLights");
		        	var light0 = new BABYLON.HemisphericLight('light1', new BABYLON.Vector3(0,1,0), scene);
		        	var light1 = new BABYLON.PointLight("Omni", new BABYLON.Vector3(1, 1, 1), scene);
		        	light1.position = camera.position;
		        };

		        var loadMusic=function(){
    				console.log("loadMusic");
			        music = new BABYLON.Sound("Violons", "sounds/violons11.wav", scene,
						function() {
								// Sound has been downloaded & decoded
								//music.play();
								$("#btnMute").show();
							}
					);
			    };



			    var animateCamera=function(){
    				console.log("animateCamera");

			    	rig.indexPoint = 0;

			        TweenLite.to(rig, cameraPathAnimationDuration, {
			            indexPoint: rig.points.length - 1,
			            ease: Linear.easeInOut,
			            onComplete: function() {
			                camera.attachControl(canvas, true);
			            }.bind(rig),
			            onUpdate: function() {
			                rig.indexPoint = Math.round(rig.indexPoint);
			                rig.position = rig.points[rig.indexPoint];

			                if (rig.points[rig.indexPoint + 1] && rig.points.length - rig.indexPoint > 30){
			                	rig.lookAt(cameraTarget.position);
			                }
			                else{
			                	rig.lookAt(boxTarget.position);
			                }
			            }.bind(rig)
			        });

			    };
			    var animateDynamicMeshes=function(){
    				console.log("animateDynamicMeshes");
			    	var policeCar = scene.getMeshByName("Police_car");
			    	if(policeCar){
			    		var originalPosition=policeCar.position;
			    		TweenMax.fromTo(policeCar.position,4,{z:originalPosition.z},{z:-15, ease:Linear.easeNone, repeat:-1, repeatDelay:1});

			    	}else
			    		console.log("No PoliceCar found");
			    };




				scene.registerBeforeRender(function () {
			        //light2.position = camera.position;
			        //myAnimation();
			    });
				engine.runRenderLoop(function() {
			 		    scene.render();
			 		});
				window.addEventListener('resize', function() {
				    engine.resize();
				});






		        $("#btnMute").on("click",function(e){
					e.preventDefault();
					music.play();
					animateDynamicMeshes();
					animateCamera();
				});


		    });
		</script>
    </body>
</html>

 

Share this post


Link to post
Share on other sites

The situation you describe usually happens when you scroll outside of the canvas area while still clicking (or better yet - outside the browser window). If the browser never got the mouseup (or pointerup) event, it won't stop until you click once more and make sure to release it inside the canvas area.

This will happen in the playground as well if you really want it to :):

Go to a scene with an arc rotate (it is easier to test with arc rotate), start scrolling, then hold the right mouse button as well, move outside of the window, and release both buttons. When you are back - tada, the scene will still scroll without you holding the button.

EDIT*** -  just in case I haven't written that, this has nothing to do with babylon... the events are not being triggered.

Share this post


Link to post
Share on other sites
1 hour ago, RaananW said:

The situation you describe usually happens when you scroll outside of the canvas area while still clicking (or better yet - outside the browser window). If the browser never got the mouseup (or pointerup) event, it won't stop until you click once more and make sure to release it inside the canvas area.

This will happen in the playground as well if you really want it to :):

Go to a scene with an arc rotate (it is easier to test with arc rotate), start scrolling, then hold the right mouse button as well, move outside of the window, and release both buttons. When you are back - tada, the scene will still scroll without you holding the button.

EDIT*** - just in case I haven't written that, this has nothing to do with babylon... the events are not being triggered.

That all sounds logical and familiar, but I’m quite sure I was never outside of the window when clicking and releasing. Still think it’s a timing issue loading the scripts but don’t really know how to be sure or to delay execution correctly

Share this post


Link to post
Share on other sites

So :)

Engine already checks the focus event and will (should?) prevent problems from happening if you move your mouse out of the canvas. So this is not what @Snouto describes here as he mentions it was when the mouse was INSIDE the canvas.

 

Checking your code did not ring a bell, but here are some hints:

- Try to NOT parent the camera and see if the problem is still here

- Try to simplify the scene and just keep a sphere and your camera

- Remove Hand.js and see if things are better. If yes try to use jquery PEP instead

 

Hope something will work ;)

Share this post


Link to post
Share on other sites
6 hours ago, Deltakosh said:

So :)

Engine already checks the focus event and will (should?) prevent problems from happening if you move your mouse out of the canvas. So this is not what @Snouto describes here as he mentions it was when the mouse was INSIDE the canvas.

 

Checking your code did not ring a bell, but here are some hints:

- Try to NOT parent the camera and see if the problem is still here

- Try to simplify the scene and just keep a sphere and your camera

- Remove Hand.js and see if things are better. If yes try to use jquery PEP instead

 

Hope something will work ;)

I'll check that out thanks. It definitely seems to be related to hand.js. If I remove it completely, no problems on desktop. Soon as I put it back in (locally loaded), problem returns. Did you happen to try the code above locally yourself? I'm curious if other people get this problem too

Share this post


Link to post
Share on other sites

I don't believe it is. The ArcCamera is set as so:

camera = new BABYLON.ArcRotateCamera("ArcRotateCamera", 1.5, 1.5, 10, new BABYLON.Vector3(0, 0, 0), scene);

the target is zero, but as you can see the alpha & beta values are set to 1.5 and radius set to 10.

Share this post


Link to post
Share on other sites

Works fine in Chrome, but the issue is present in firefox for me.

I second Delta's suggestion of moving to PEP and seeing if that resolves the issue.

Share this post


Link to post
Share on other sites

Interesting, I hadn't considered it to be a browser-specific issue. I'm using Safari on the Mac and it always happens there, but not always for every scene I've tested. Do you know of any decent resources to follow to implement pep? I tried just adding in the js source a couple weeks ago and it was soon obvious there was more to it than that (whereas hand.js does everything automatically it seems)

Share this post


Link to post
Share on other sites

You should just be able to include it, and then add the touch-action attribute to the canvas (probably touch-action="none",  so that default actions aren't fired).

I think the readme of the github repo is the only resource I used when I started including pep in projects.

Share this post


Link to post
Share on other sites

I've been having the same problem in FireFox, but also have had issues in chrome as well. I'm generally not able to keep the camera rotating around (0,0,0). FYI

DB

Share this post


Link to post
Share on other sites

So are we suggesting there's a problem setting the ArcCamera's target to zero? I could probably get by just changing that ever so slightly if that's a bug in the camera causing my problems.

Share this post


Link to post
Share on other sites
26 minutes ago, Snouto said:

So are we suggesting there's a problem setting the ArcCamera's target to zero? I could probably get by just changing that ever so slightly if that's a bug in the camera causing my problems.

that would not make sense but a quick way to test it is like you say set it to like 0, 0.01, 0 or something and see if that fixes it... but I highly doubt it.
I can not recreate the error as of yet of the camera getting stuck in pan mode.

Share this post


Link to post
Share on other sites

Okay so after a project distraction I'm on this again. Just to confirm from the last comment - setting the target value to something other than zeros doesn't appear to make a difference. I'm going to try using PEP as suggested earlier in the thread

 

[edit 2 minutes later] First impressions are using PEP completely resolves the issue. Naturally I need to do more testing but if nothing changes, this is the way to go. I'm not sure if it's necessary to add the following to the element in the HTML or just to the CSS (I have both right now) but it does seem important:

 touch-action="none"

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.