【问题标题】:Input mouse position not captured accurately?输入鼠标位置不准确?
【发布时间】:2017-12-13 10:42:36
【问题描述】:

我正在使用鼠标输入在纹理上从点 A 到点 B 绘制一条线。我意识到我并没有击中每个像素,所以将鼠标从屏幕的最左边移动到最右边,它会跳过一些值,导致间隙。当我慢慢移动鼠标时,它会变得更好。

我正在使用以下方法获取鼠标位置:

var viewPortPosition = Camera.main.ScreenToViewportPoint (Input.mousePosition);

【问题讨论】:

    标签: c# unity3d


    【解决方案1】:

    如果你想画一条线,我建议你使用line renderer。假设您在 Update() 函数中实现了代码 - 这在渲染的每一帧中都会调用。所以即使你的动作很慢,显然它已经足够在你的画线中留下空隙了。

    下面是来自 link 的一些代码,它应该适合你:

    using System.Collections.Generic;
     using UnityEngine;
    
     [RequireComponent(typeof(LineRenderer))]
     public class LineRendererTest : MonoBehaviour
     {
         List<Vector3> linePoints = new List<Vector3>();
         LineRenderer lineRenderer;
         public float startWidth = 1.0f;
         public float endWidth = 1.0f;
         public float threshold = 0.001f;
         Camera thisCamera;
         int lineCount = 0;
    
         Vector3 lastPos = Vector3.one * float.MaxValue;
    
    
         void Awake()
         {
             thisCamera = Camera.main;
             lineRenderer = GetComponent<LineRenderer>();
         }
    
         void Update()
         {
             Vector3 mousePos = Input.mousePosition;
             mousePos.z = thisCamera.nearClipPlane;
             Vector3 mouseWorld = thisCamera.ScreenToWorldPoint(mousePos);
    
             float dist = Vector3.Distance(lastPos, mouseWorld);
             if(dist <= threshold)
                 return;
    
             lastPos = mouseWorld;
             if(linePoints == null)
                 linePoints = new List<Vector3>();
             linePoints.Add(mouseWorld);
    
             UpdateLine();
         }
    
    
         void UpdateLine()
         {
             lineRenderer.SetWidth(startWidth, endWidth);
             lineRenderer.SetVertexCount(linePoints.Count);
    
             for(int i = lineCount; i < linePoints.Count; i++)
             {
                 lineRenderer.SetPosition(i, linePoints[i]);
             }
             lineCount = linePoints.Count;
         }
    

    【讨论】:

    • 我知道 LineRenderer,并且我之前使用过它,并且实际上也在考虑使用 LineRenderer 将曲线参数化和光栅化到纹​​理上。我不想使用 LineRenderer 方法的原因是,在某一时刻我会耗尽内存。在纹理上绘画会给我一个固定的画布。
    • @user1767754 您可以轻松实现以避免在重用相同内存时耗尽内存,例如使用缓冲区。所以我还是会选择 LineRenderer。
    • 如果您不再需要内存,您可以重复使用相同的内存。但是当你想不断地画线并保持线条时,这可能会很棘手。如果我有固定的画布,我就不会遇到问题。我可能不得不采用使用 Linerenderer 绘制线条的混合解决方案,完成后将它们喷到纹理上。我仍然很困惑为什么会跳过鼠标位置。
    【解决方案2】:

    我最终做的是通过 Bresenham 的 Line Drawing 函数运行迄今为止收集的鼠标位置以栅格化线条。

    来源:

        public void line(Vector2 pointA, Vector2 pointB, Texture2D texture) {
        int x = (int)pointA.x;
        int y = (int)pointA.y;
    
        int x2 = (int)pointB.x;
        int y2 = (int)pointB.y;
    
        int w = x2- x ;
        int h = y2 - y;
        int dx1 = 0, dy1 = 0, dx2 = 0, dy2 = 0 ;
        if (w<0) dx1 = -1 ; else if (w>0) dx1 = 1 ;
        if (h<0) dy1 = -1 ; else if (h>0) dy1 = 1 ;
        if (w<0) dx2 = -1 ; else if (w>0) dx2 = 1 ;
        int longest = Math.Abs(w) ;
        int shortest = Math.Abs(h) ;
        if (!(longest>shortest)) {
            longest = Math.Abs(h) ;
            shortest = Math.Abs(w) ;
            if (h<0) dy2 = -1 ; else if (h>0) dy2 = 1 ;
            dx2 = 0 ;            
        }
        int numerator = longest >> 1 ;
        for (int i=0;i<=longest;i++) {
            texture.SetPixel (x, y, Color.red);
    
            numerator += shortest ;
            if (!(numerator<longest)) {
                numerator -= longest ;
                x += dx1 ;
                y += dy1 ;
            } else {
                x += dx2 ;
                y += dy2 ;
            }
        }
    }
    

    原始代码源,但针对 Unity C# 进行了修改:All cases covered Bresenham's line-algorithm

    【讨论】:

    • 谢谢。它是映射到屏幕空间坐标的 2D 世界鼠标输入坐标。
    • O.我知道了。我以为那是世界空间
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-25
    • 2019-09-28
    • 2019-09-11
    • 2020-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多