Problems with Gropuing after a scaling matrix modification....

Well basically the problem is that when a texture(in my case “needle”) is suposed to rotate around the gropus center (wich is the resolution of the background image (in my case “speedo”) will have an incorrect pivot position…

This would normally not happen, but since I have a scaling matrix modification, the groups are not working properly…

Heres the code:

using UnityEngine;
using System.Collections;

public class HUD : MonoBehaviour {
	
	public Texture2D speedo;
	public Texture2D needle;
	
	// Internal	
	private Vector2 currentResolution;
	private Vector2 nativeResolution;
	private Vector3 nativeScale;
	private float aspectRatio;
	private float nativeRes = 720;
	
    private float rotAngle = 0;	
	Rect speedoRect;
	Vector2 speedoPivot;
	
	void OnGUI ()
	{		
		InitGUIMatrix();		
		
		if(speedo)
		{
			GUI.BeginGroup(new Rect(100,0,512,512)); // <---- Matrix gets messed up
			GUI.DrawTexture(new Rect(0,0,speedo.width,speedo.height),speedo); // Background
			Matrix4x4 prevMat = GUI.matrix;	
			pivotPoint = new Vector2(speedo.width/2, speedo.height/2);	// Correct.
			pivotPoint.x /= (screenRect.width)/(Screen.width);			// Needs a modifyer after gropued?
			pivotPoint.y /= (screenRect.height)/(Screen.height);		// ...
	        GUIUtility.RotateAroundPivot(rotAngle, pivotPoint); // <---- Fix me...
			
			rotAngle -= 100f*Time.deltaTime; // test rotation
			if(needle)
			{
				GUI.DrawTexture(new Rect(0,0,speedo.width,speedo.height),needle); // Needle (rotating tex)
			}
			GUI.EndGroup();
			GUI.matrix = prevMat;
		}
	}
	
	/// Inits the GUI matrix.
	void InitGUIMatrix()
	{
		aspectRatio = GetScreenAspectRatio();
		currentResolution = new Vector2(Screen.width,Screen.height); // Just store
		nativeResolution.x = (nativeRes*aspectRatio);
		nativeResolution.y = nativeRes;
		nativeScale.x = Screen.width / nativeResolution.x;
		nativeScale.y = Screen.height / nativeResolution.y;
		nativeScale.z = 1;		
		scaledMat = Matrix4x4.TRS (Vector3.zero, Quaternion.identity, nativeScale);
		GUI.matrix = scaledMat;
	}	
	
	float GetScreenAspectRatio()
	{
		return (Screen.width*(1.0f/Screen.height));
	}	
}

And I included some sample textures to test with.

1616134–98528–$nismo.rar (334 KB)

What is “screenRect”? It is not defined in the code you’re showing.

Anyway, this is a stab in the dark, but are you correctly taking into account whatever the group is doing to the current matrix? From memory, groups are heirachical and everything in a group is positioned, rotated and scaled relative to that group. It looks like you’re still calculating things based on the screen size and position, though. I’m not sure if that’s the right way to go about it.

Hey, sorry about the screen rect, screenRect is the scaled screen size.
screenRect = new Rect(0,0,nativeResolution.x,nativeResolution.y);
Anyway, the problem seems to be that RotateAroundPivot doesnt quite work with in a matrix. So I had to do some conversion’s to get the pivot correct,
like this:

pivotPoint.x /= (screenRect.width)/(Screen.width); // Needs a modifyer after gropued?
pivotPoint.y /= (screenRect.height)/(Screen.height); // …

but soon after I group it and try to realign, it gets broken :frowning:

Why is there a difference between native and your used resolution? If you’re trying to scale to different screen sizes then it’s much easier to just do the whole thing at your target resolution (no scaling), then apply the scaling all at once by essentially “pushing and popping” a matrix transformation at the start and end of the OnGUI call.

On that note, it seems that your issues are all related to that same kind of thing. Re-organise it so your math is as simple as possible, and make it all just work at a single, fixed size. After it’s working like that, then try and make it scale and such. One problem at a time.

Well, I dont understand this post, because this is exactly what I’m trying to do, the problem is that after the scaling, pivots get messed up, they are not in a logical position.

I tryed to backwards engineer the position but it leads to a strange position, Seems like a bug.

And about the resolutions, Native resolution is the desired resolution, like in consoles. Lets say my native resolution is 1920x1080 and my current resolution is 1280x720, then everything will be placed in the native resolution cordinates, but the gui itself is scaled down to 1280x720.
The whole point of this is to have everything in place when the user scales the screen. Otherwise id have to have different screen cordinates and scaling per “onscreenobject” for each resolution the user selects. Wich is not a smart solution.

So if you can, please explain me what you meant by:
“pushing and popping” a matrix transformation at the start and end of the OnGUI

Also my conversion math “pivotPoint.x /=…” can be replaced with GUIUtility.GUIToScreenPoint(pivotPoint)
so the code would look better, but still in a group the pivot point gets messed :confused:

hello Ravel try with this script
not is very advanced but it works

using UnityEngine;
using System.Collections;

[ExecuteInEditMode]
public class KMH : MonoBehaviour 
{

	// this is to acess the currentGear
	public Car car;

	public Texture2D dialTex;

	public Texture2D needleTex;


	[Range(20f, 730f)]
	// scale the speedometer
	public float aspectRatio = 200f;


	// the max speed we can go on the speedometer
	public float topSpeed = 320f;
	
	// the start position -125 to match the speedometer at zero!!!
	public float stopAngle = -125f;
	
	// the end position 125 to match the speedometer at 320!!!
	public float topSpeedAngle = 125f;
	

	// the kmh speedometer
	public float kmh = 0;

    
	private Vector2 pos = new Vector2(0f, 0f);
	private Vector2 size = new Vector2(0f, 0f);

	private Vector2 centre;
	private Vector2 offset;
	private Rect rect;


	[Range(0f, 1f)]
	// right and left screen!!
	public float setX = 0f;

	[Range(0f, 1f)]
	// up and down screen!!
	public float setY = 0f;


	[Range(10f, 730f)]
	//allow us to set the position of the gear....move left or right
	public float setGearX = 105f;
	
	[Range(17f, 730f)]
	//allow us to set the position of the gear....move up or down
	public float setGearY = 48f;
	



	void Start()
	{
		UpdateSettings();
	}

	void OnGUI()
	{

		// this is the offset of the speedometer to allow us to move left or right and up or down
		offset = new Vector2((Screen.width -aspectRatio) * setX,(Screen.height -aspectRatio) * setY);

		// allows to move the needle of  the speedometer
		float speed = car.rigidbody.velocity.magnitude * 2.237f;
		kmh = speed;
		
		// the position of the speedometer on the screen
		GUI.BeginGroup(new Rect((Screen.width -aspectRatio) -offset.x, (Screen.height -aspectRatio) -offset.y, aspectRatio, aspectRatio));

		
		if (Application.isEditor)
		{
			UpdateSettings();
		}
		
		// if it is valid draw the texture....and don't give annoying errors that i must assign the texture
		if(dialTex != null)
		{
			// draw the speedometer texture
			GUI.DrawTexture(rect, dialTex);
		}

		Matrix4x4 matrix = GUI.matrix;

		// current velocity divided by maximum velocity
		float speedFraction = kmh / topSpeed;
		float needleAngle = Mathf.Lerp(stopAngle, topSpeedAngle, speedFraction);
		
		// needle rotation
		GUIUtility.RotateAroundPivot(needleAngle, centre);

		// if it is valid draw the texture....and don't give annoying errors that i must assign the texture
		if(needleTex != null)
		{
			// draw the needle texture
			GUI.DrawTexture(rect, needleTex);
		}

		GUI.matrix = matrix;

		// just to don't give annoying errors
		if(car != null)
		{
			// draws the current gear of the car on screen
			GUI.Label(new Rect(aspectRatio -setGearX, aspectRatio -setGearY, aspectRatio, aspectRatio), string.Empty + (car.currentGear + 1));
		}
		GUI.EndGroup();
	}

	// update settings 
	void UpdateSettings()
	{
		size = new Vector2(aspectRatio, aspectRatio);
		pos = new Vector2(0f, 0f);
		rect = new Rect(pos.x - (size.x * 0f), pos.y - (size.y * 0f), size.x, size.y);
		centre = new Vector2(rect.xMin + (rect.width * 0.5f), rect.yMin + (rect.height * 0.5f));
	}
}

ps : you have to replace the public Car

Thanks for the code Xx77xX, but this is what I did before I went over to matrix scaling.
I think matrix scaling is a few ms faster because you dont have to do the math for each object. Lets say I have 10 dials and using this method would eventually result in slower results (atleast I think so). Currently I’m doing a mixture of both methods, thr grouping bit gets calculated, but everything else stays in the matrix. This could be counted as a hack. But after some research I found out that it’s a bug that has been there for ages.

yeah i understand

but i have examined your code and i think i found the problem.
the problem seems to be in this line of code …

GUI.BeginGroup(new Rect(100, 0, 512, 512)); // <---- Matrix gets messed up

when I removed the 100 of the x axis, the needle stayed in the middle

GUI.BeginGroup(new Rect(0, 0, 512, 512)); // <---- Matrix gets messed up

but if you want move the speedometer to the left / right or up / down
you may have problems

you have to find a way that does not affect the needle

this one is working … test and see if this is what you were looking for
I hope it helps you

using UnityEngine;
using System.Collections;

[ExecuteInEditMode]
public class HUD : MonoBehaviour
{
	
	public Texture2D speedo;
	public Texture2D needle;
	
	// Internal 
	private Vector2 currentResolution;
	private Vector2 nativeResolution;
	private Vector3 nativeScale;
	private float aspectRatio;
	private float nativeRes = 720;
	
	private float rotAngle = 0; 

	Rect screenRect;
	Vector2 pivotPoint;
	
	Matrix4x4 scaledMat;

	//Rect speedoRect;
	//Vector2 speedoPivot;


	void OnGUI ()
	{   

		InitGUIMatrix();       
	
		screenRect = new Rect(0, 0, nativeResolution.x, nativeResolution.y);

		if(speedo)
		{

			// if we add any valve to x axis or y axis the center of the needle is affected
			GUI.BeginGroup(new Rect(0, 0, 512, 512)); // <---- Matrix gets messed up


			GUI.DrawTexture(new Rect(0, 0, speedo.width, speedo.height), speedo); // Background
			Matrix4x4 prevMat = GUI.matrix; 
			pivotPoint = new Vector2(speedo.width/2, speedo.height/2);  // Correct.
			pivotPoint.x /= (screenRect.width)/(Screen.width);          // Needs a modifyer after gropued?
			pivotPoint.y /= (screenRect.height)/(Screen.height);        // ...
			GUIUtility.RotateAroundPivot(rotAngle, pivotPoint); // <---- Fix me...
			
			rotAngle -= 100f*Time.deltaTime; // test rotation
			if(needle)
			{
				GUI.DrawTexture(new Rect(0, 0, speedo.width, speedo.height), needle); // Needle (rotating tex)
			}
			GUI.EndGroup();
			GUI.matrix = prevMat;
		}
	}
	
	/// Inits the GUI matrix.
	void InitGUIMatrix()
	{
		aspectRatio = GetScreenAspectRatio();
		currentResolution = new Vector2(Screen.width, Screen.height); // Just store
		nativeResolution.x = (nativeRes * aspectRatio);
		nativeResolution.y = nativeRes;
		nativeScale.x = Screen.width / nativeResolution.x;
		nativeScale.y = Screen.height / nativeResolution.y;
		nativeScale.z = 1;     
		scaledMat = Matrix4x4.TRS (Vector3.zero, Quaternion.identity, nativeScale);
		GUI.matrix = scaledMat;
	}   
	
	float GetScreenAspectRatio()
	{
		return (Screen.width * (1.0f/Screen.height));
	}   
}

good luck Ravel!!

the 100 was just there to demonstrate the bug :slight_smile: