FreshRSS

Normální zobrazení

Jsou dostupné nové články, klikněte pro obnovení stránky.
PředevčíremHlavní kanál

Converting a Rendered Canvas from Overlay to World Space while facing camera

I'm working on converting a 3D game to VR. I've made some progress, but the UI has been challenging. From my understanding (and use) a canvas rendered in world space is recommended in VR.

Here is a video of what I see after converting the overlay canvas to world space. The two arrow sprites follow the hand correctly, but from some angles, we end up looking at them edge-on like this:

Arrows at an angle

But I want them to always face the player's head flat-on like this:

Arrows flat-on

I feel I have identified the issue, but my programming is a work in progress. I'm wondering if this could be the problem:

public static float Atan2(float y, float x);

Description
Returns the angle in radians whose Tan is y/x.

Return value is the angle between the x-axis and a 2D vector starting at zero and terminating at (x,y).

using System.Collections;
using System.Collections.Generic;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.SocialPlatforms;

public class UIManager : MonoBehaviour
{
    public GameObject WindVectorUI;
    public GameObject SailDirectionUI;
    public GameObject ApparentWindUI;


    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        UpdateWindVectorUI();
        UpdateSailDirectionUI();
        UpdateApparentWindUI();
    }

    // calculates the angle of the wind vector using Mathf.Atan2() which returns the angile in radians between the x-axis and the vector pointing to (x,y)
    void UpdateWindVectorUI()
    {
        float AngleInRad = Mathf.Atan2(WindManager.instance.CurrentTrueWind.y, WindManager.instance.CurrentTrueWind.x);
        WindVectorUI.transform.rotation = Quaternion.Euler(0, 0, AngleInRad * Mathf.Rad2Deg);

    }

    void UpdateSailDirectionUI()
    {
        SailDirectionUI.transform.rotation = Quaternion.Euler(0, 0, -BoatManager.Player.Sail.transform.localRotation.eulerAngles.y + 90 - BoatManager.Player.transform.localRotation.eulerAngles.y);
    }

    void UpdateApparentWindUI()
    {
        float AngleInRad = Mathf.Atan2(BoatManager.Player.ApparentWind.y, BoatManager.Player.ApparentWind.x);
        ApparentWindUI.transform.rotation = Quaternion.Euler(0, 0, AngleInRad * Mathf.Rad2Deg);
    }
}

How can I use `UnityEngine.UIElements.PopupWindow` for a custom PropertyDrawer targeting an array with UI Toolkit?

I'm following the "Create a Custom Inspector" car and tire example that Unity has in their documentation for UI Toolkit, but I'm trying to modify it in a specific way and I'm coming up short (whether or not it is a "good" way is beyond the scope of the question). Essentially, I'd like to take the editor display for an array and make it accessible by a single button that opens a PopupWindow in the editor, displaying the information for all four tires. I'd also like to make sure that the array is not reorderable, and if possible, I'd like to have it not act like a foldout in the PopupWindow.

I've managed to get this so far:

a sort-of functional popup behind a Button that does not display the information from TireSpecs.cs

In Car.cs, I have the following:

using UnityEngine;
using UnityEngine.UIElements;
using UnityEditor;
using UnityEditor.UIElements;

public class Car : MonoBehaviour
{
    public string myMake = "Ford";
    public int myYearBuilt = 2001;
    public Color myColor = new Color(0.5725f, 0.525f, 0.3875f, 1.0f);

    public TireSpecsArrayWrapper myTires = new TireSpecsArrayWrapper()
    {
        Tires = new TireSpecs[4]
    };

    public ActualTireDetails tireOptions;
}

In TireSpecs.cs, I have the following:

using System;
using UnityEngine;

[Serializable]
public class TireSpecs
{
    public float myAirPressure = 35.0f;
    public int myProfileDepth = 4;

    public TireSpecs(float airPressure, int profileDepth)
    {
        myAirPressure = airPressure;
        myProfileDepth = profileDepth;
    }
}

In TireSpecsArrayWrapper.cs, I have the following:

using System;
using UnityEngine;

[Serializable]
public class TireSpecsArrayWrapper
{
    public TireSpecs[] Tires; 
}

And my PropertyDrawer, TirePropertyDrawer.cs, is structured like this (has been edited to reflect changes below):

using UnityEngine;
using UnityEngine.UIElements;
using UnityEditor;
using UnityEditor.UIElements;
using System.Collections.Generic;

[CustomPropertyDrawer(typeof(TireSpecsArrayWrapper))]
public class TirePropertyDrawer : PropertyDrawer
{
    public override VisualElement CreatePropertyGUI(SerializedProperty property)
    {
        var container = new VisualElement();

        SerializedProperty tireProperties = property.FindPropertyRelative("Tires");

        var button = new Button(() => ShowPopup(container, tireProperties)) { text = "View Tire Specifications" };
        container.Add(button);

        return container;
    }

    void ShowPopup(VisualElement anchor, SerializedProperty property)
    {
        UnityEngine.UIElements.PopupWindow popup = new UnityEngine.UIElements.PopupWindow();
        popup.style.flexGrow = 200;
        popup.style.height = new StyleLength(Length.Percent(100));
        popup.style.flexDirection = FlexDirection.Column;

        if (property != null && property.isArray)
        {
            Debug.Log($"Array Size: {property.arraySize}");

            for (int i = 0; i < property.arraySize; i++)
            {
                Debug.Log($"Array index = {i}");
                SerializedProperty arrayElement = property.GetArrayElementAtIndex(i);
                VisualElement arrayElementContainer = new VisualElement();
                arrayElementContainer.style.flexDirection = FlexDirection.Column;

                arrayElementContainer.Add(new Label($"Tire #{i + 1}: "));

                CreatePropertyField(arrayElementContainer, arrayElement, "airPressure", "Air Pressure (psi):");
                CreatePropertyField(arrayElementContainer, arrayElement, "profileDepth", "Profile Depth (mm):");

                arrayElementContainer.style.paddingTop = 8;
                arrayElementContainer.style.paddingRight = 8;
                arrayElementContainer.style.paddingBottom = 8;
                arrayElementContainer.style.paddingLeft = 8;

                popup.Add(arrayElementContainer);
            }
        }

        var button = new Button(() => anchor.Remove(popup)) { text = "Close Popup" };
        popup.Add(button);
        anchor.Add(popup);
    }

    private void CreatePropertyField(VisualElement elementContainer, SerializedProperty parentProperty, string propertyName, string label)
    {
        SerializedProperty property = parentProperty.FindPropertyRelative(propertyName);
        PropertyField field = new PropertyField(property, label);
        field.BindProperty(property);
        field.style.flexGrow = 1;
        field.style.paddingTop = 2;
        field.style.paddingRight = 2;
        field.style.paddingBottom = 2;
        field.style.paddingLeft = 2;
        field.style.minHeight = 16;
        field.style.flexDirection = FlexDirection.Column;
        elementContainer.Add(field);
    } 
}

EDIT: After consulting with some folks, I've managed to get it to this stage:

an update of the .gif above, where the popup window now properly displays some text, but not the fields from TireSpecs.cs

EDIT 2: I've now managed to get close to what I'm looking for visually and functionally, but I'm not certain that what I have is behaving entirely as intended. Getting to this point involved creating a wrapper class for TireSpecs.cs to allow the PropertyDrawer to target the array directly. Scripts have been updated to reflect changes; the styling especially could use some work, but outside of that, is there a way to improve my script(s)?

a close visual match for the sort of thing that I'm trying to make with the popup window and array; there is now only one button which, when clicked, displays the array information

How would I make minimap of racing track where dot follows track progress in Unity?

I would like to show race progress in my UI. My minimap is like sketch below: enter image description here

Blue dot represents progress and red dot is finish line. I would like this to work in UI so only blue dot would move. If it was circular or linear I think it wouldn't be much of the problem but I am not sure how to move the dot with this shape.

❌
❌