A
A
akass2015-09-13 00:32:37
3D
akass, 2015-09-13 00:32:37

World Space Curved UI?

Tell me how to correct it so that buttons and stuff can be pressed normally in worldspace mode?
Initially, everything works in screen space-camera, if you switch to worldspace and see, for example, only half of the canvas with buttons, then you can no longer click on them. Mapping needs to be fixed somehow.

public class CylinderMapping : CanvasMapping
{
    protected override void Awake()
    {
        base.Awake();
 
        if (m_canvas.renderMode != RenderMode.ScreenSpaceCamera)
        {
            Debug.LogWarning("Cylinder mapping works best in ScreenSpaceCamera mode", this);
        }
    }
    #region CanvasMapping
    
    public override bool MapScreenToCanvas(Vector2 screenCoord, out Vector2 o_canvasCoord)
    {
        Camera worldCamera = m_canvas.worldCamera;
        if (worldCamera != null)
        {
            // Get the camera transform
            Transform worldCameraTransform = worldCamera.transform;
           
            // Get a ray from the camera through the point on the screen
            Ray ray3D = worldCamera.ScreenPointToRay(screenCoord);
 
            // Transform the ray direction into view space
            Vector3 localRayDirection = worldCameraTransform.InverseTransformDirection(ray3D.direction);
 
            // Calculate the view space size of the canvas
            float thetaFOVH = worldCamera.fieldOfView * 0.5f * Mathf.Deg2Rad;
            float tanFOVH = Mathf.Tan(thetaFOVH);
            float tanFOVW = tanFOVH * worldCamera.aspect;
 
            // Flatten cylinder and ray to 2D so this becomes a ray circle intersection
            Vector2 rayDirection2D = new Vector2(localRayDirection.x, localRayDirection.z);
            Vector2 circlePosition = new Vector2(0.0f, 1.0f + (tanFOVW * m_depth));
            float circleRadius = tanFOVW * m_radius;
 
            // Determine the far intersection, if there is one
            float farIntersection;
            if (RayCircle2D(Vector2.zero, rayDirection2D, circlePosition, circleRadius, out farIntersection))
            {
                // Intersection point on the XZ plane
                Vector2 cylinderXZ = (rayDirection2D * farIntersection) - circlePosition;
 
                // XZ -> angle around cylinder
                float cylinderTheta = Mathf.Atan2(cylinderXZ.x, cylinderXZ.y);
 
                // Y intersection
                float cylinderY = localRayDirection.y * farIntersection;
 
                // To viewport [-1, 1]
                float viewportX = cylinderTheta / (m_angle * 0.5f * Mathf.Deg2Rad);
                float viewportY = cylinderY / tanFOVH;
 
                // To canvas
                Vector2 canvasSize = m_canvas.pixelRect.size;
                o_canvasCoord.x = ((viewportX * 0.5f) + 0.5f) * canvasSize.x;
                o_canvasCoord.y = ((viewportY * 0.5f) + 0.5f) * canvasSize.y;
 
                #if DEBUG_VISUALISE
                {
                    Vector3 intersection3D = worldCameraTransform.TransformPoint(localRayDirection * (farIntersection * m_canvas.planeDistance));
                    Debug.DrawLine(worldCameraTransform.position, intersection3D);
                }
                #endif
 
                return true;
            }
        }
 
        o_canvasCoord = Vector2.zero;
        return false;
    }
    
    public override void SetCanvasToScreenParameters(Material material)
    {
        material.SetFloat("Cylinder_Depth", m_depth * 0.5f);
        material.SetFloat("Cylinder_Angle", m_angle * Mathf.Deg2Rad);
        material.SetFloat("Cylinder_Radius", m_radius * 0.5f);
    }
    
    #endregion
 
    bool RayCircle2D(Vector2 rayStart, Vector2 rayDirection, Vector2 circlePosition, float circleRadius, out float o_farIntersection)
    {
        Vector2 f = rayStart - circlePosition;
        
        float a = Vector2.Dot(rayDirection, rayDirection);
        float b = 2.0f * Vector2.Dot(f, rayDirection);
        float c = Vector2.Dot(f, f) - (circleRadius * circleRadius);
        
        float discriminantSq = (b * b) - (4.0f * a * c);
        if (discriminantSq < 0.0f)
        {
            // No intersection
            o_farIntersection = 0.0f;
            return false;
        }
        else
        {
            float discriminant = Mathf.Sqrt(discriminantSq);
            o_farIntersection = (-b + discriminant) / (2.0f * a);
            return true;
        }
    }
 
    [SerializeField]
    [Range(-10.0f, 10.0f)]
    float m_depth = -1.0f;
 
    [SerializeField]
    [Range(0.0f, 360.0f)]
    float m_angle = 180.0f;
 
    [SerializeField]
    [Range(0.0f, 10.0f)]
    float m_radius = 1.0f;
}

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question