I'm interested in AR applications of mobile devices and naturally I would like to make better use of the compass.
The only issue I've been having to work against isn't how twitchy the compass is. (Angular Smoothing seems to solve this issue just fine) My main issue is that when the device is held Vertical the compass values start freaking out. Causing an on screen compass to flip about all over the place. I don't have a lot of experience with mobile application development so I'm not sure what would be causing this issue, if its a Unity issue or if its just a limitation of the digital compass. I know other apps do seem to be able to use the compass fine in any orientation, but this is all stupidly new to me.
I've definitely tried moving the phone in a figure of 8. The device I have to play around with is a Nexus 4.
using UnityEngine;
using System.Collections;
public class Compass : MonoBehaviour {
// Use this for initialization
void Start () {
Input.location.Start ();
Input.compass.enabled = true;
}
// Update is called once per frame
void Update ()
{
var heading = Input.compass.trueHeading;
transform.eulerAngles = new Vector3 (0, 0, heading);
}
}
Preamble :)
First of, I'm not an expert (unfortunately) in subjects that I will talk about. But still, I've decided to share my thoughts.
Theory
The problem can be generalized in the following way. You want to have some continuous function that takes a 3D vector (which is device orientation in your case) and returns another vector that is orthogonal to original vector. Theory says (see hairy ball theorem) that for some arguments that function will return zero vectors. In case when such a function is compass, zero vectors are returned when device is oriented vertical (and this fells quite natural if you have ever used an ordinary compass).
Practice
Sometimes you want your app to tell which side of the world does phone back (rear camera) is pointing to.
Or maybe even you want combined approach:
If the phone is oriented flat, show what is the phone's top pointing to.
If the phone is oriented vertical, show what is the phone's back pointing to.
In both cases you need to use gyroscope in addition to compass.
Related
The ARCore sceneform sample project "hellosceneform" is cool and works really well.
Problem is the requirement to move the phone around in order to get a surface on which to place anchors. It's too slow.
My application does not require anything to show up on a vertical plane (a wall), but only ever on the floor. Is there anyway I can skip the "move the phone around" step or at least speed it up?
I've tried:
session.getConfig().setPlaneFindingMode(Config.PlaneFindingMode.HORIZONTAL);
Thinking that if I remove the need to look for vertical planes then it would all work faster..... not quite fast enough it seems.
Thanks!
Unfortunately the framework is limited by (read: enabled by) the computer vision models that it uses to detect planes. The plane discovery controller (i.e. the "move the phone around" step) is a nudge to the user to provide the models with the depth information through the camera that they need to detect those planes. Removing this step won't speed up the process, it'll just leave the user without any instructions.
Without improvements to the core plane detection models I wouldn't expect that there's a way to make this faster. The best that we can do is come up with UX nudges that encourage the user to move the phone laterally more efficiently.
To hide the animation that shows users how they should move their phone
use
arFragment.planeDiscoveryController.hide()
arFragment.planeDiscoveryController.setInstructionView(null)
To speed up plane detection in ARCore is quite easy. Here's a code snippet:
class MainActivity : AppCompatActivity() {
lateinit var arFrag: ArFragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_ux)
arFrag = supportFragmentManager.findFragmentById(R.id.ux_fragment) as ArFragment
arFrag.planeDiscoveryController.hide()
arFrag.planeDiscoveryController.setInstructionView(null)
arFrag.arSceneView.planeRenderer.isEnabled = false
arFrag.arSceneView.scene.setOnUpdateListener(::onFrame)
}
// ........................................................
}
Hope this helps.
Attempt to measure distance based acceleration (accelerometer mobile). If that's true
Accelerometer {
id: accel
dataRate: 1000 / 25
onReadingChanged: {
console.log(reading.x, reading.y, reading.z);
}
}
In console
D/libsensor.so(16533): qrc:/main.qml:20 (onReadingChanged): qml: 1.359906554222107,8.791508674621582,-0.4405331015586853
Now when you display information and having the mobile completely still (motionless). Shows acceleration in all axes, which is absurd! You have any idea why?
That's certainly not absurd.
According to Einstein's widely accepted (but still disturbing) theories, your phone can't tell if it's sitting still on planet Earth or accelerating inside a spaceship in deep space - that's called the "equivalence principle". So it's just assuming it's in an accelerating spaceship, because why not ? And that's so much cooler, don't you think ?
If you're near (or on) a planet and reading a zero acceleration, that's bad news, because that means you're freefalling in the distorted spacetime around the planet, and you're probably about to hit something.
You're reading an acceleration of about 9m/s^2, which is close to Earth's g value, so that's approximatively right, depending on your phone orientation. Maybe the accerelometer calibration is not quite right, you can test it with a dedicated application, if you've not done it already. NB Some apps will compensate for the gravity of Earth.
Of course, there's also the possibility of bugs in the phone or in Qt or in your code, or hardware failure, but you have to know what to expect.
Hope that helps.
I am developing a sniper game for android using Google card board unity SDK. Now there is the need to tweak the camera's FOV which leads me to interact a variable named 'mockFieldOfView' in CardBoard.cs. Tweaking that value in the Unity editor is fine but as soon as I make a build for Android it doesn't take effect at all. I'm unable to figure out the issue. Any idea or suggestion would be highly appreciated.
Apologize for the late reply, so ouflak you can see complete Cardboard.cs here Cardboard.cs
You don't want to change "mockFieldOfView". That only affects the in-editor FOV. The value you want to change is "matchMonoFOV" on the StereoController. You also have to set a "CenterOfInterest" game object on the StereoController. It makes the stereo FOV attempt to match the FOV on the Main Camera (or whichever camera has the StereoController script).
See StereoController.cs
Update: v0.4.5 of Cardboard SDK supports your use case. Use "matchByZoom" and set the FOV you want on the StereoController's camera. No center of interest is needed.
I had the same issue and in my case it helped to put the MainCamera closer to the object which was the Cockpit of a car in my case.
In order to put the MainCamera closer than 1 real-world-meter to the object you must change the default-minimum-value in Cardboard.cs - I use the following setting:
private readonly Vector2 defaultComfortableViewingRange = new Vector2(0.0f, 100000.0f);
I'm currently almost done developing my first app on android, except the human jump detection seems to be too slow/inaccurate for my desire. I have used a seekbar for changing the sensitivity, however I just believe my algorithm for detection is inefficient. I tried searching everywhere for proper jump detection, but had no luck. It seems to boil down to some good ol' physics and math.
This is my algorithm (from inside the onSensorChangeListener()) for when the phone in the pocket is upwards, by the way, sensitivity is 0-100, but defaults at 50:
if(phonePosition=="UP"){
if(event.values[1]>(15-(sensitivity-50)/10)){
inAir=true;
}
if(inAir&&event.values[1]<(5+(sensitivity-50)/10)){
freeFall=true;
}
if(freeFall&&event.values[1]>(13-(sensitivity-50)/10)){
rebound=true;
}
if(rebound&&event.values[1]<(10+(sensitivity-50)/10)&&event.values[1]>(1-(sensitivity-50)/10))
{
sp.play(beep1,1,1,0,0,1);
jumpCount++;
inAir=false;
freeFall=false;
rebound=false;
}
jumps.setText(Integer.toString(jumpCount));
}
Here is a chart of xyz values of some jumps if it may help: http://pastebin.com/DtTC3DnL
I try to create game for Android and I have problem with high speed objects, they don't wanna to collide.
I have Sphere with Sphere Collider and Bouncy material, and RigidBody with this param (Gravity=false, Interpolate=Interpolate, Collision Detection = Continuous Dynamic)
Also I have 3 walls with Box Collider and Bouncy material.
This is my code for Sphere
function IncreaseBallVelocity() {
rigidbody.velocity *= 1.05;
}
function Awake () {
rigidbody.AddForce(4, 4, 0, ForceMode.Impulse);
InvokeRepeating("IncreaseBallVelocity", 2, 2);
}
In project Settings I set: "Min Penetration For Penalty Force"=0.001, "Solver Interation Count"=50
When I play on the start it work fine (it bounces) but when speed go to high, Sphere just passes the wall.
Can anyone help me?
Thanks.
Edited
var hit : RaycastHit;
var mainGameScript : MainGame;
var particles_splash : GameObject;
function Awake () {
rigidbody.AddForce(4, 4, 0, ForceMode.Impulse);
InvokeRepeating("IncreaseBallVelocity", 2, 2);
}
function Update() {
if (rigidbody.SweepTest(transform.forward, hit, 0.5))
Debug.Log(hit.distance + "mts distance to obstacle");
if(transform.position.y < -3) {
mainGameScript.GameOver();
//Application.LoadLevel("Menu");
}
}
function IncreaseBallVelocity() {
rigidbody.velocity *= 1.05;
}
function OnCollisionEnter(collision : Collision) {
Instantiate(particles_splash, transform.position, transform.rotation);
}
EDITED added more info
Fixed Timestep = 0.02 Maximum Allowed Tir = 0.333
There is no difference between running the game in editor player and on Android
No. It looks OK when I set 0.01
My Paddle is Box Collider without Rigidbody, walls are the same
There are all in same layer (when speed is normal it all works) value in PhysicsManager are the default (same like in image) exept "Solver Interation Co..." = 50
No. When I change speed it pass other wall
I am using standard cube but I expand/shrink it to fit my screen and other objects, when I expand wall more then it's OK it bouncing
No. It's simple project simple example from Video http://www.youtube.com/watch?v=edfd1HJmKPY
I don't use gravity
See:
Similar SO Question
A community script that uses ray tracing to help manage fast objects
UnityAnswers post leading to the script in (2)
You could also try changing the fixed time step for physics. The smaller this value, the more times Unity calculates the physics of a scene. But be warned, making this value too small, say <= 0.005, will likely result in an unstable game, especially on a portable device.
The script above is best for bullets or small objects. You can manually force rigid body collisions tests:
public class example : MonoBehaviour {
public RaycastHit hit;
void Update() {
if (rigidbody.SweepTest(transform.forward, out hit, 10))
Debug.Log(hit.distance + "mts distance to obstacle");
}
}
I think the main problem is the manipulation of Rigidbody's velocity. I would try the following to solve the problem.
Redesign your code to ensure that IncreaseBallVelocity and every other manipulation of Rigidbody is called within FixedUpdate. Check that there are no other manipulations to Transform.position.
Try to replace setting velocity directly by using AddForce or similar methods so the physics engine has a higher chance to calculate all dependencies.
If there are more items (main player character, ...) involved related to the physics calculation, ensure that their code runs in FixedUpdate too.
Another point I stumbled upon were meshes that are scaled very much. Having a GameObject with scale <= 0.01 or >= 100 has definitely a negative impact on physics calculation. According to the docs and this Unity forum entry from one of the gurus you should avoid Transform.scale values != 1
Still not happy? OK then the next test is starting with high velocities but no acceleration. At this phase we want to know, if the high velocity itself or the acceleration is to blame for the problem. It would be interesting to know the velocities' values at which the physics engine starts to fail - please post them so that we can compare them.
EDIT: Some more things to investigate
6.7 m/sec does not sound that much so that I guess there is a special reason or a combination of reasons why things go wrong.
Is your Maximum Allowed Timestep high enough? For testing I suggest 5 to 10x Fixed Timestep. Note that this might kill the frame rate but that can be dfixed later.
Is there any difference between running the game in editor player and on Android?
Did you notice any drops in frame rate because of the 0.01 FixedTimestep? This would indicate that the physics engine might be in trouble.
Could it be that there are static colliders (objects having a collider but no Rigidbody) that are moved around or manipulated otherwise? This would cause heavy recalculations within PhysX.
What about the layers: Are all walls on the same layer resp. are the involved layers are configured appropriately in collision detection matrix?
Does the no-bounce effect always happen at the same wall? If so, can you just copy the 1st wall and put it in place of the second one to see if there is something wrong with this specific wall.
If not to much effort, I would try to set up some standard cubes as walls just to be sure that transform.scale is not to blame for it (I made really bad experience with this).
Do you manipulate gravity or TimeManager.timeScale from within a script?
BTW: are you using gravity? (Should be no problem just