@akass
Developer

World Space Curved UI?

Подскажите как правильно поправить, чтобы кнопки и прочее можно было нормально нажимать в режиме worldspace?
Изначально все работает в screen space-camera, если переключить на worldspace и увидеть например только половину канваса с кнопками, то нажать на них уже нельзя. Маппинг надо как-то поправить.

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;
}
  • Вопрос задан
  • 317 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы