Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
5
Question by Kyu · Jan 13, 2014 at 11:07 AM · camera2dsmoothghosting

How to smoothly move a 2D camera without ghosting

Hello,

I've struggled with this problem for over a year, and now, nearing the end of the production cycle of our commercial game, I'm out of time and ideas.

For the life of me, I cannot smoothly move a 2D camera from one end of the screen to the other without ghosting.

Here's a simple code sample that shows the problem:

 using UnityEngine;
 using System.Collections;
 
 public class SmoothScroll : MonoBehaviour {
 
     [SerializeField]
     private float speed = 800.0f;
 
     private Vector3 position;
     private float screenRadius;
 
     private void Awake () {
         Application.targetFrameRate = 60;
 
         this.position = new Vector3 ();
         this.screenRadius = this.camera.orthographicSize * this.camera.aspect;
     }
 
     private void Update () {
         this.position = this.transform.position;
 
         this.position.x += this.speed * Time.deltaTime;
 
         if (this.position.x > this.screenRadius)
             this.position.x = - this.screenRadius;
 
         this.transform.position = this.position;
     }
 }
 

The target platform is iOS, but the problem remains the same in standalone MacOS and Windows. Here's a list of things I've tried:

  • Could be a response time issue, tried multiple screens.

  • Could be a vsync issue, tried turning it on, turning it off, setting it for every second blank.

  • Changed Application.targetFrameRate to 60, 30 and disabled.

  • Tried different types of movement, setting position directly, using translate, changing it on update, fixed update, late update, using Time.deltaTime, using Time.smoothDeltaTime, ignoring deltaTime completely (obviously, that last one was the worst)

  • Tried without a rigidbody, rigidbody with interpolation, and rigidbody with extrapolation

  • Tried moving the camera while the objects are still, tried moving the objects while the camera is still

  • Tried all settings of anti-alias

  • Could be distortion from stretching, so I tried having a pixel-perfect orthographic camera

  • Could be a floating point precision problem, so I tried using only rounded integer positions on a pixel-perfect camera (grasping at straws here)

  • Tried multiple combinations of the previous points

Nothing seems to work. I've been all over the web this past year searching for solutions for this problem, and I've come up empty.

Here's a demo, with the same code as above, that shows the problem (MacOS and Windows standalone builds).

Comment
Add comment · Show 15
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Kyu · Jan 13, 2014 at 10:57 AM 0
Share

The demo link is wrong, here you go: link

Any help will be greatly appreciated. Any miraculous solution will have me start a new religion around you.

avatar image Jeffom · Jan 13, 2014 at 01:54 PM 0
Share

Have you tried using coroutines or using the LateUpdated to update your camera? What's the camera configuration? It seems that the next frame is rendering while the previous frame is playing.

avatar image Kyu · Jan 13, 2014 at 04:07 PM 0
Share

On the actual game I'm using LateUpdate to move my camera, so everything else has finished moving before the camera does. On the demo above, however, only the camera moves. So I have the script above coupled to my orthographic camera, and all it's doing is moving horizontally forever. I agree that the next frame seems to be rendering before the previous frame is done, but shouldn't vsync take care of that? I also thought it might be a response time problem, so I tried on a screen with 2 ms response, but the problem is still there.

avatar image HappyMoo · Jan 13, 2014 at 04:36 PM 0
Share

Really? An exe? You expect everyone to execute some random exe from a stranger on the internet? Provide a unitypackage that shows the problem, if the code above isn't enough.

Your code could start with OpenPandorasBox() for all I know...

avatar image Kyu · Jan 14, 2014 at 01:48 PM 1
Share

That link looks promising @Happy$$anonymous$$oo, I will try that, thank you.

Show more comments

3 Replies

· Add your reply
  • Sort: 
avatar image
2
Best Answer

Answer by HappyMoo · Jan 14, 2014 at 02:48 AM

The problem is, there will always be interferences between the updatespeed and framerate - even with deltaTime, this is actually the Time from last Frame and with FixedUpdate, this is worse.

And some setups show the problem more than others.

What you actually would need to do, is Interpolated Fixed Timestep like it is explained in the article we all know and love: FIX YOUR TIMESTEP!.

But Unity chose to not implement this from the start and now it's hard to implement it yourself because of how the GameObjects include the data for simulation and for the gfx effects. One could try to copy all the positions around and implement the needed interpolation between OnPreRender and OnPostRender(or end of OnRenderImage), but this would probably mess up phyics.

Or we could try to separate invisible simulation GOs and simple visible ones that just get the transformation copied over as a first step, but then interpolates between the current and the last saved state, but that's of course working very hard to circumvent the way Unity is designed to work... You know what, I might actually give this a try one day, just to see if it can be done.

Comment
Add comment · Show 8 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Kyu · Jan 24, 2014 at 07:44 PM 0
Share

Deadlines started hitting me hard, and this problem got postponed for later on. I'm considering this to be the right answer, not because I confirmed it fixed my problem, but because I believe this is the most probable solution. If anyone runs into the same problem and finds this page, my recommendation is to follow what Happy$$anonymous$$oo suggested.

Thanks to Happy$$anonymous$$oo, and to everyone else who tried to help.

avatar image OP_toss · Jan 24, 2014 at 10:15 PM 1
Share

I tried implementing your solution, because I was curious. But it didn't work.

I think the issue is more related to Unity's basic drawing backend. It seems like a refresh-rate issue, or an optical illusion. Not jitters like an execution order issue, nor incorrect speed, like a time-step issue would cause. A render-texture looks fine when attached, as does a paused game-screen in the editor.

I don't honestly know how to fix this, but I'm casting a vote against this being the solution. I've also tried fixing it with execution order changes, render quality changes, etc.

Basically, fast moving things ghost in Unity. Could just be the screen refresh-rate... AFAI$$anonymous$$ there's no way to fix it but to use a motionblur post-effect, or pre-rendered animation.

avatar image HappyMoo · Jan 24, 2014 at 10:39 PM 0
Share

You implemented fixed timesteps with blending between current and last state based on the remainder frametime? Do you have a generic solution or just for one object. Can we see the code?

avatar image OP_toss · Jan 24, 2014 at 11:06 PM 0
Share

So feel free to correct me if I did this wrong. I'd love the input, and love more to truly crack this case. It was kind of a rushed job, frankly... States are just Vector3's for this example.

Here's the OP's class mixed with what you posted.

EDIT: Hmmm I may have glossed over the integration part of the article...

 using UnityEngine;
 using System.Collections;
 
 public class SmoothScroll : $$anonymous$$onoBehaviour {
 
     [SerializeField]
     private double speed = 1.0f;
     private float screenRadius;
     
     
     private double t = 0.0;
     private const double dt = 0.01;
     private double currentTime = 0.0;
 
     private double accumulator = 0.0;
 
     private Vector3 previousState;
     private Vector3 currentState;
 
 
     private void Awake () {
         Application.targetFrameRate = 60;
 
         this.currentState = new Vector3 ();
         this.previousState = new Vector3 ();
         this.currentTime = 0.0;
         this.screenRadius = this.camera.orthographicSize * this.camera.aspect + 500.0f;
     }
     
     private Vector3 UpdateCurrentPosition( Vector3 current, double time, double deltaTime )
     {
         current.x += (float)(this.speed * deltaTime);
 
         if (current.x > this.screenRadius)
             current.x = - this.screenRadius;
         
         return current;
     }
     
     /*
     private void OnGUI () {
         GUILayout.Label (this.speed.ToString ());
     }
     */
     
     private void LateUpdate () 
     {
         double newTime = Time.time;
         double frameTime = newTime - currentTime;
         if ( frameTime > 0.25 )
         frameTime = 0.25;      // note: max frame time to avoid spiral of death
         currentTime = newTime;
         
         accumulator += frameTime;
         
         while ( accumulator >= dt )
         {
             previousState = currentState;
             currentState = UpdateCurrentPosition( currentState, t, dt );
             t += dt;
             accumulator -= dt;
         }
         
         float alpha = (float)(accumulator / dt);
         Vector3 position = currentState*alpha + previousState*( 1.0f - alpha );
 
         this.transform.position = position;
     }
 }
avatar image HappyMoo · Jan 26, 2014 at 04:08 PM 0
Share

thanks, will take a look later, because I want to take time to look in detail into it and what's happening ti$$anonymous$$g-wise. $$anonymous$$aybe someone with access to the unity profiler who knows how to use it can also have a look.

Show more comments
avatar image
1

Answer by giudark · Jan 13, 2014 at 02:06 PM

I am at the beginning so don't think I can help a lot, but your problem sounds very strange to me ... have you tried to use Mathf.Lerp in combination with LateUpdate and Time.deltaTime?

 private float currentXPosition;
 //other and initialization ...

 private void LateUpdate () {
  this.position = this.transform.position;
  if (this.position.x > this.screenRadius)
   this.position.x = - this.screenRadius;
  else{
   float desiredXPosition = this.screenRadius; //or other ...
   currentXPosition = Mathf.Lerp(currentXPosition , desiredXPosition, Time.deltaTime * this.speed);
  this.position.x = currentXPosition;
  }
  
  this.transform.position = this.position;
 }


Or you can find many camera script controller here (3d but not is important i suppose).

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Kyu · Jan 13, 2014 at 04:19 PM 1
Share

$$anonymous$$oving the camera on LateUpdate is great if you have other moving objects in the scene, because then the camera only moves when the other objects finished moving. On the demo above, however, only the camera moves (the SmoothScrolling script is attached to the main camera). $$anonymous$$athf.Lerp is a good way to move from A to B smoothly over a consistent amount of time regardless of the distance between A and B, but because on the demo above the camera moves forever, it seems simpler to just add "Time.deltaTime * speed" to the position. I tried $$anonymous$$athf.Lerp anyway, just in case there was something I was missing, but sadly it didn't change anything.

Thank you for the link, but basically all the camera controllers at their core have to change it's position somehow. Regardless of whether they're moving it with Translate, $$anonymous$$athf.Lerp, Smooth.Damp [..], at the end of the day all they do is move a specific amount of distance multiplied by the time that has passed since the last frame (Time.deltaTime). So the code above is, as far as I know, the simplest way a camera can move smoothly, changing the calculation of the movement to a more complex solution won't solve this (though I have tried it over this past year :/ ).

avatar image
0

Answer by BenIvory · Oct 23, 2018 at 07:51 PM

Me and my friend had this issue and our case was fixed by putting both the camera and the target in FixedUpdate using .FixeddeltaTime, wish you the best of luck!

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

26 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

smooth follow 2d camera runner ios 0 Answers

The sprite that is being followed by thr camera is very jittery and doesn't look very nice at all. 2 Answers

Problems with 2D Camera Shaking 3 Answers

Unity smooth following 2D camera not working properly on different resolutions 0 Answers

2d camera help! 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges