The Shimmering Cursor: Eliminating GUI.DrawTexture Jitter During Scaling
Developing custom editor tools in Unity often requires drawing textures directly onto the SceneView using GUI.DrawTexture. However, a common frustration for tool developers in 2026 is the noticeable "jitter" or "shimmering" effect that occurs when the texture is scaled or the SceneView camera zooms. This visual instability is rarely a bug in the engine's rendering pipeline; rather, it is a byproduct of sub-pixel floating-point math meeting a fixed-pixel display grid. When your calculated coordinates land between two physical pixels, the GPU’s anti-aliasing and sampling logic struggle to decide which pixel should host the texture's edge, leading to the "shaking" sensation as the scale changes. Mastering the bridge between world-space coordinates and integer-based screen-space rects is the key to creating professional, stable editor extensions.
Table of Content
- Purpose: Visual Stability and Tool Professionalism
- The Logic: Floating Point Math vs. Pixel Grids
- Step-by-Step: Implementing Pixel-Perfect GUI Drawing
- Use Case: Custom Selection Marquees
- Best Results: Handling High-DPI and Retinas
- FAQ
- Disclaimer
Purpose
Eliminating jitter in custom GUI drawing serves several critical functions in game development:
- User Experience: Reducing eye strain and "visual noise" for developers using your custom tools for long periods.
- Interaction Precision: Ensuring that the visual representation of a tool matches its underlying clickable "hitbox."
- Aesthetic Polish: Giving your editor extensions a "native" feel that matches Unity's own stable, jitter-free UI.
The Logic: Floating Point Math vs. Pixel Grids
The root of the jitter lies in Rounding Errors. When you scale a texture—perhaps based on the distance from the camera—your Rect values for width, height, X, and Y often result in numbers like 100.456.
Since a computer screen cannot draw "half a pixel," GUI.DrawTexture must interpolate. As you scale, that value might shift from 100.4 to 100.6. The sudden jump from pixel 100 to pixel 101 creates a one-pixel "snap" that looks like a jitter. To solve this, we must force the Rect into Integer Space before the draw call is executed.
Step-by-Step
1. Calculate Your Floating Point Rect
Start with your dynamic logic—calculating the texture size based on the SceneView's current zoom or scale factor.
float currentScale = GetDynamicScale();
Rect rawRect = new Rect(mousePos.x, mousePos.y, 64 currentScale, 64 currentScale);
2. Apply Integer Rounding
Before passing the rect to the draw call, use Mathf.Round or Mathf.Floor on all four components. This forces the texture to align perfectly with the screen's pixel grid.
Rect pixelPerfectRect = new Rect(
Mathf.Round(rawRect.x),
Mathf.Round(rawRect.y),
Mathf.Round(rawRect.width),
Mathf.Round(rawRect.height)
);
3. Handle Matrix Transformations
If you are using GUI.matrix to rotate or scale the entire GUI coordinate system, the jitter can become even worse. Always try to draw at Identity Matrix (no rotation/scale) and perform your math at the Rect level instead.
4. Execute the Draw Call
Pass the cleaned, rounded Rect into the GUI system.
GUI.DrawTexture(pixelPerfectRect, myTexture);
Use Case
A developer is building a custom "Brush Tool" for an terrain editor. As the user scrolls the mouse wheel to increase the brush size, the texture preview in the SceneView begins to shake violently.
- The Action: The developer wraps the brush
Rectcalculation in a rounding function. - The Implementation: Instead of the brush being 50.33 pixels wide, it is rounded to exactly 50 pixels.
- The Result: The scaling becomes a series of discrete, stable steps rather than a flickering mess, even when the user is zoomed far out in the SceneView.
Best Results
| Factor | Standard GUI Call | 2026 Best Practice |
|---|---|---|
| Coordinates | Floating Point (float) | Pixel-Rounded (int) |
| Sampling | Bilinear | Point (for pixel-art tools) |
| DPI Awareness | Ignored | Use EditorGUIUtility.pixelsPerPoint |
| Draw Call | GUI.DrawTexture | Graphics.DrawTexture (for complex blend modes) |
FAQ
Why does the jitter only happen in SceneView and not GameView?
The SceneView camera has a complex projection matrix that changes based on zoom level and "Handle" scaling. GameView usually has a fixed resolution, making sub-pixel errors less obvious. However, the fix remains the same for both.
Should I use Floor or Round?
Mathf.Round is generally better as it finds the "nearest" pixel. Mathf.Floor can sometimes cause a one-pixel "drift" where the texture feels slightly detached from the cursor.
What about High-DPI (4K) monitors?
On High-DPI screens, one "point" in the GUI system may equal 2 or 3 actual pixels. Unity's GUI system handles this abstraction, but rounding to the nearest integer point is still the most effective way to prevent shimmering across different screen densities.
Disclaimer
Force-rounding coordinates to integers can cause "stepped" movement if the scale speed is extremely slow. However, for most editor tools, this is preferred over the blurry shimmering caused by sub-pixel sampling. This tutorial is specific to the Unity IMGUI (Immediate Mode GUI) system and may not apply to the modern UIElements/UIToolkit frameworks which handle layout and pixel-snapping differently. Always ensure your OnSceneGUI logic is efficient to avoid performance drops. March 2026.
Tags: UnityEditor, GUIProgramming, TextureJitter, ToolDevelopment
