使用Unity实现VR中在黑板上写字(升级篇)(二)----- 加入黑板擦

黑板擦的功能其实和画笔是一样的,只是黑板擦设置的颜色是画板最原始的颜色,而笔设置的是其他的颜色。

所以最大的不同时,当手柄握住黑板擦时和握住笔时的函数实现是不一样的;实现这个功能之后,黑板擦的擦掉功能将在后续的篇章中和画笔一起完成;

可以看到不管黑板擦以什么角度开始靠近画板,最终这个黑板擦一定是和画板平行的;

先看看画板的坐标系:

 

再看看黑板擦的坐标系:

也就是说不管黑板擦以何种旋转角度(Rotation)靠近黑板最终的结果就是:黑板擦的transform.up指向画板的 -transform.forward方向;而在靠近的过程中,根据靠近的距离,我们把这个Rotation进行插值就可以了;

现在的问题就是什么时候开始插值呢?The Lab中的实现是,当黑板檫的中心点与画板的距离是黑板擦长边的0.5的时候,就开始插值,什么时候结束呢?最简单的就是0的时候,但是因为我的黑板擦底部有个0.02m的黑色擦布,所以我的是0.02m时结束;

因此首先需要写一个映射函数:

复制代码
public static class Helper
{
    /// <summary>
    /// 用于比较两个Color32类型是不是一样
    /// </summary>
    /// <param name="origin"></param>
    /// <param name="compare"></param>
    /// <returns></returns>
    public static bool IsEqual(this Color32 origin, Color32 compare)
    {
        if (origin.g == compare.g && origin.r == compare.r)
        {
            if (origin.a == compare.a && origin.b == compare.b)
            {
                return true;
            }
        }
        return false;
    }

    /// <summary>
    /// 把num在low1 ~ high1之间的位置,重新映射到low2 ~ high2之间,并限制返回值是low2 ~ high2之间的值;
    /// </summary>
    /// <param name="num"></param>
    /// <param name="low1"></param>
    /// <param name="high1"></param>
    /// <param name="low2"></param>
    /// <param name="high2"></param>
    /// <returns></returns>
    public static float RemapNumberClamped(float num, float low1, float high1, float low2, float high2)
    {
        return Mathf.Clamp(RemapNumber(num, low1, high1, low2, high2), Mathf.Min(low2, high2), Mathf.Max(low2, high2));
    }

    /// <summary>
    /// 把num在low1 ~ high1之间时代表的值,映射到low2 ~ high2 之间所代表的值
    /// </summary>
    /// <param name="num"></param>
    /// <param name="low1"></param>
    /// <param name="high1"></param>
    /// <param name="low2"></param>
    /// <param name="high2"></param>
    /// <returns></returns>
    public static float RemapNumber(float num, float low1, float high1, float low2, float high2)
    {
        return low2 + (num - low1) * (high2 - low2) / (high1 - low1);
    }
}
复制代码

当我们把num限制在0 ~1 的时候,我们就得到了插值系数;当从0.096开始插值,从0.02结束插值,黑板檫距离画板的距离时0.047,重新映射后,结果为0.5;

现在可以写黑板檫的Grab Attach 机制了:

升级篇(一)中已经完成了Painter的Grab Attach机制,只要直接重写它的ProcessFixedUpdate函数就可以了;

复制代码
using UnityEngine;

public class EraserGrabAttach : PainterGrabAttach
{
    
    public override void ProcessFixedUpdate()
    {
        if (grabbedObject)//只有抓住物体后,grabbedObject才不会
        {
            grabbedObject.transform.rotation = controllerAttachPoint.transform.rotation * Quaternion.Euler(grabbedSnapHandle.transform.localEulerAngles);
            grabbedObject.transform.position = controllerAttachPoint.transform.position - (grabbedSnapHandle.transform.position - grabbedObject.transform.position);
            float distance = board.GetDistanceFromBoardPlane(transform.position);//黑板檫距离画板的距离
            if (distance > -0.096f)//当黑板檫离画板足够近的时候
            {
                float percentOfDistance = Helper.RemapNumberClamped(distance, -0.096f, -0.02f, 0f, 1f);//映射后,得到插值系数
                Quaternion q = Quaternion.FromToRotation(grabbedObject.transform.up, -board.transform.forward);//最终的目的是:黑板擦的transform.up指向-transform.forward
                q *= grabbedObject.transform.rotation;//得到黑板檫达到最终目的时的旋转
                grabbedObject.transform.rotation = Quaternion.Slerp(grabbedObject.transform.rotation, q, percentOfDistance);//通过插值,得到当前黑板檫的旋转
                if (distance > 0.01f)//如果黑板檫穿透了画板,需要进行矫正
                {
                    Vector3 pos = board.ProjectPointOnBoardPlane(grabbedObject.transform.position);
                    grabbedObject.transform.position = pos - board.transform.forward * 0.01f;
                }
            }                     
        }
    }

  
}
复制代码

其实也可以用Quaternion.LookRotation但是这个函数的限制要比Quaternion.FromToRotation要大,效果没有后者好;

在下一篇中将完善所有的初级篇中不足的地方;

转自:https://www.cnblogs.com/marsir/p/8538754.html

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用Unity在Pico实现黑板写字的代码: 1. 创建一个Plane对象,并将其旋转90度,使其成为一个平面。 ``` GameObject plane = GameObject.CreatePrimitive(PrimitiveType.Plane); plane.transform.Rotate(new Vector3(90, 0, 0)); ``` 2. 创建一个材质,并将其贴到Plane上。 ``` Material material = new Material(Shader.Find("Standard")); plane.GetComponent<Renderer>().material = material; ``` 3. 创建一个RenderTexture,用于渲染黑板上的内容。 ``` RenderTexture renderTexture = new RenderTexture(1024, 1024, 24); ``` 4. 将RenderTexture设置为材质的主纹理。 ``` material.mainTexture = renderTexture; ``` 5. 创建一个Camera,并将其渲染目标设置为RenderTexture。 ``` GameObject cameraObject = new GameObject("Camera"); Camera camera = cameraObject.AddComponent<Camera>(); camera.targetTexture = renderTexture; ``` 6. 将Camera的位置设置为黑板的位置,并使其朝向黑板。 ``` cameraObject.transform.position = new Vector3(0, 1, -2); cameraObject.transform.LookAt(plane.transform); ``` 7. 创建一个画笔对象,并将其放在Pico的手柄上。 ``` GameObject brush = GameObject.CreatePrimitive(PrimitiveType.Sphere); brush.transform.localScale = new Vector3(0.05f, 0.05f, 0.05f); brush.GetComponent<Renderer>().material.color = Color.black; brush.transform.parent = PicoUnityActivity.instance.ControllerRight.transform; brush.transform.localPosition = new Vector3(0, 0, 0.1f); ``` 8. 在Update函数,检测手柄的触发键是否按下,并在黑板上绘制画笔的位置。 ``` void Update() { if (PicoInputManager.Controller.Pico_ControllerRight.GetPress(Valve.VR.EVRButtonId.k_EButton_SteamVR_Trigger)) { Ray ray = new Ray(brush.transform.position, brush.transform.forward); RaycastHit hit; if (Physics.Raycast(ray, out hit)) { Vector2 uv = hit.textureCoord; uv.x *= renderTexture.width; uv.y *= renderTexture.height; RenderTexture.active = renderTexture; GL.PushMatrix(); GL.LoadPixelMatrix(0, renderTexture.width, 0, renderTexture.height); GL.Begin(GL.TRIANGLES); GL.Color(Color.black); GL.Vertex3(uv.x, uv.y, 0); GL.Vertex3(uv.x + 10, uv.y, 0); GL.Vertex3(uv.x, uv.y + 10, 0); GL.End(); GL.PopMatrix(); RenderTexture.active = null; } } } ``` 这样,就可以在Pico实现黑板写字了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值