当我“绘制”线条时,如何将点平均分配到 LineRenderer 的宽度曲线?

2024-05-20

我正在使用线条渲染器创建一个“绘图”应用程序,现在我尝试使用线条渲染器上的宽度曲线启用笔压。问题在于,AnimationCurve 的“时间”值(水平轴)从 0 标准化为 1,因此我不能在每次添加位置时都在其末尾添加一个值。除非有一个我不知道的函数,否则我能想到的唯一解决方案就是找到一种方法,在绘制线条时将所有数百个先前值移动精确的百分比,并在添加位置时执行此操作。这似乎太过分了。

我不知道在这里做什么。

这是我用笔绘制时在每一帧添加点的基本线。

curve.AddKey(1.0f, penPressureValue);

“1.0f”是曲线上的位置(1 是最后一个),所以这只是在每帧的末尾添加一个点,在我绘制时改变整条线的宽度。


不幸的是,我认为没有一种方法可以实现这一点,这在某种程度上是不可思议的并且性能密集。

当然你可以计算它(假设LineRenderer从位置计数 = 0 开始),例如

public LineRenderer line;
private int positionCount;
private float totalLengthOld;

private void AddPoint(Vector3 position, float width)
{
    // increase the position count by one
    positionCount++;

    // set the count back to the line
    line.positionCount = positionCount;

    // add our new point
    line.SetPosition(positionCount - 1, position);

    // now get the current width curve
    var curve = line.widthCurve;

    // Is this the beginning of the line?
    if (positionCount == 1)
    {
        // First point => simply set the first keyframe 
        curve.MoveKey(0, new Keyframe(0f, width));
    }
    else
    {
        // otherwise get all positions
        var positions = new Vector3[positionCount];
        line.GetPositions(positions);

        // sum up the distances between positions to obtain the length of the line
        var totalLengthNew = 0f;
        for (var i = 1; i < positionCount; i++)
        {
            totalLengthNew += Vector3.Distance(positions[i - 1], positions[i]);
        }

        // calculate the time factor we have to apply to all already existing keyframes
        var factor = totalLengthOld / totalLengthNew;

        // then store for the next added point
        totalLengthOld = totalLengthNew;

        // now move all existing keys which are currently based on the totalLengthOld to according positions based on the totalLengthNew
        // we can skip the first one as it will stay at 0 always
        var keys = curve.keys;
        for (var i = 1; i < keys.Length; i++)
        {
            var key = keys[i];
            key.time *= factor;

            curve.MoveKey(i, key);
        }

        // add the new last keyframe
        curve.AddKey(1f, width);
    }

    // finally write the curve back to the line
    line.widthCurve = curve;
}

就像一个小演示一样

public class Example : MonoBehaviour
{
    public LineRenderer line;
    public Transform pen;
    [Range(0.01f, 0.5f)] public float width;
    public float drawThreshold = 0.1f;

    private int positionCount;
    private float totalLengthOld;
    private Vector3 lastPenPosition;
    
    private void Awake()
    {
        line = GetComponent<LineRenderer>();
        line.useWorldSpace = true;
        line.positionCount = 0;

        lastPenPosition = pen.position;
    }

    private void Update()
    {
        // just for the demo simply ping-pong the width over time
        width = Mathf.Lerp(0.01f, 0.8f, Mathf.PingPong(Time.time, 1f));

        var currentPenPosition = pen.position;
        
        if (Vector3.Distance(lastPenPosition, currentPenPosition) >= drawThreshold)
        {
            lastPenPosition = currentPenPosition;
            AddPoint(currentPenPosition, width);
        }
    }
    
    private void AddPoint(Vector3 position, float width)
    {
        positionCount++;

        line.positionCount = positionCount;
        line.SetPosition(positionCount - 1, position);

        var curve = line.widthCurve;

        if (positionCount == 1)
        {
            curve.MoveKey(0, new Keyframe(0f, width));
        }
        else
        {
            var positions = new Vector3[positionCount];
            line.GetPositions(positions);

            var totalLengthNew = 0f;
            for (var i = 1; i < positionCount; i++)
            {
                totalLengthNew += Vector3.Distance(positions[i - 1], positions[i]);
            }

            var factor = totalLengthOld / totalLengthNew;

            totalLengthOld = totalLengthNew;

            var keys = curve.keys;
            for (var i = 1; i < keys.Length; i++)
            {
                var key = keys[i];
                key.time *= factor;

                curve.MoveKey(i, key);
            }

            curve.AddKey(1f, width);
        }

        line.widthCurve = curve;
    }
}

当然,在达到一定数量的点后,这会达到性能极限。但我认为这是您目前可以使用的LineRenderer。否则LineRenderer可能只是不是正确的绘图工具。

当然,您可以采取一些技巧,在一定数量的点之后,使用以下方法将现有线烘焙成单独的固定网格LineRenderer.BakeMesh https://docs.unity3d.com/ScriptReference/LineRenderer.BakeMesh.html并开始一条新的线,仅将最后一个点作为起点。

这样,只有线条尚未烘焙的部分实际上会受到宽度曲线键移动的影响。

有点像例如

public int meshBakeThreshold = 50;

private void AddPoint(Vector3 position, float width)
{
    ......

    if (positionCount >= meshBakeThreshold)
    {
        CreateSnapShotAndStartOver(position, width);
    }
}

private void CreateSnapShotAndStartOver(Vector3 position, float width)
{
    // create a new GameObject that will receive the line snapsho mesh
    var snapshotObject = new GameObject("LineSnapshot", typeof(MeshRenderer), typeof(MeshFilter));

    // set the material
    var renderer = snapshotObject.GetComponent<Renderer>();
    renderer.material = line.material;

    // bake and set the mesh
    var meshFilter = snapshotObject.GetComponent<MeshFilter>();
    var mesh = new Mesh();
    line.BakeMesh(mesh, Camera.main, true);
    meshFilter.mesh = mesh;

    // start with a new line at the same current position
    positionCount = 0;
    AddPoint(position, width);
}

你必须稍微调整一下阈值,50可能有点低,只是用于演示。您希望在迭代所有关键帧和烘焙网格的性能成本之间找到平衡点;)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

当我“绘制”线条时,如何将点平均分配到 LineRenderer 的宽度曲线? 的相关文章

随机推荐

  • 如何在没有 firebase 的情况下在 flutter 中显示推送通知?

    在我的 flutter 应用程序中 我必须在没有 firebase 的情况下显示推送通知 我的服务器会在点击特定 API 后向我发送一条消息 并且我希望将该消息显示为推送通知 你能告诉我一种方法如何在颤振中做到这一点吗 您可以使用本地通知插
  • Oracle REGEXP_INSTR() 和“a-z”字符范围与预期不匹配

    我想用REGEXP INSTR 在 oracle 数据库中检查小写 大写字符 我知道 upper and lower POSIX 字符类 但我选择了a z这给了我非常奇怪的结果 我不明白 有人可以解释一下吗 SELECT REGEXP IN
  • 迭代 my_dict.keys() 并修改字典中的值是否会使迭代器失效?

    我的例子是这样的 for my key in my dict keys my dict my key mutate 上述代码的行为是否已定义 假设my dict是一本字典并且mutate是一个改变其对象的方法 我担心的是 改变字典中的值可能
  • 我如何将整数列表添加到路由

    我正在尝试将 int 数组添加到我的 Url Action 中 如下所示 var routeData new RouteValueDictionary for int i 0 i lt Model GroupsId Length i rou
  • Select2 下拉列表动态添加、删除和刷新项目

    这让我发疯 为什么 Select2 不能在其页面上实现清晰的方法或示例如何在 Select2 上进行简单的 CRUD 操作 我有一个 select2 从 ajax 调用获取数据
  • git merge 冲突的不同场景

    我试图了解 git 合并后可能发生 git 冲突的情况以及如何避免它们 我创建了一个 git 存储库并向其中添加了一个文本文件 我已将 1 添加到文本文件中并将其提交给 master 我已经从 master 创建了一个新分支 分支 2 并将
  • 将 Excel 文件读入 R 并锁定单元格

    我有一个 Excel 电子表格要读入 R 它受密码保护并锁定了单元格 我可以使用 excel link 导入受密码保护的文件 但我不知道如何解锁 取消保护单元格 excel link 给了我这个错误 gt
  • Android - 9 补丁

    我正在尝试使用 9 块图片创建一个新的微调器背景 我尝试了很多方法来获得完美的图像 但都失败了 s Here is my 9 patch 当我用Draw 9 patch模拟时 内容看起来不错 但是带有箭头的部分没有显示 或者当它显示时 这部
  • Stream_context_set_params 不适用于 ssh2.sftp 包装器

    我想使用类似的功能here http www php net manual en function stream notification callback php 请检查以下代码 function notify notification
  • 如何在R中分离两个图?

    每当我运行这段代码时 第一个图就会简单地覆盖前一个图 R中有没有办法分开得到两个图 plot pc title main abc xlab xx ylab yy plot pcs title main sdf xlab sdf ylab x
  • 当鼠标悬停在上面时,intellisense vscode 不显示参数或文档

    我正在尝试将整个工作流程从 Eclipse 和 Jupyter Notebook 迁移到 VS Code 我安装了 python 扩展 它应该带有 Intellisense 但它只是部分更糟糕 我在输入句点后收到建议 但当将鼠标悬停在其上方
  • 如何使用 GOPATH 的 Samba 服务器位置?

    我正在尝试将 GOPATH 设置为共享网络文件夹 当我进入 export GOPATH smb path to shared folder I get go GOPATH entry is relative must be absolute
  • 使用FFMpeg确定视频类型,然后进行转换?

    我正在尝试以编程方式确定文件的真实类型 看来我必须使用 FFMPeg 来实现这一点 我想确定上传的文件实际上是否是 MP4 或 FLV 对于 Flash 视频 或 WebM 对于 HTML5 我知道 FFMPeg 中的 i 运算符 但我不知
  • JavaScript 代码在不使用 ActiveX 的情况下截取网站屏幕截图

    我有一个用户与之交互的 JavaScript 应用程序 我需要保存当前界面的外观 裁剪出我需要的部分 或者通过指定div只拍摄我需要的部分 然后发送回服务器 显然任何外部服务都无法做到这一点 我需要一个 JavaScript 或Flash
  • 在 UIMenuItem 上设置accessibilityLabel

    我正在尝试设置accessibilityLabel of a UIMenuItem而且似乎没有效果 无论如何 VoiceOver 只是读取项目的标题 let foo UIMenuItem title foo action selector
  • 运行 NUnit 并指定类别时,是否也可以包含所有未分类的测试?

    我们有数百个测试类 其中几十个测试类标记有以下属性 测试治具 明确 类别 集成测试 因此它们只会在我们通宵自动构建中运行 其余的 TestFixtures 没有指定类别 也没有标记为显式 这是我们运行来执行测试的 NAnt 任务
  • local_action:shell 连接文件时出错

    我的剧本中有这样的错误 为什么以及如何解决它 获取远程主机的更新列表 将列表连接到一个文件中 name Save update deb packs in file on ansible host copy content update de
  • 如果加载 dll 找不到依赖项,有什么方法可以捕获错误吗?

    我正在编写一个 Windows 32 位程序 可以使用多个可能的 dll 之一 所以它尝试依次加载每个 dll 使用SysUtils SafeLoadLibrary如果加载成功 它就会使用该 dll 不幸的是 其中一些 dll 静态链接到其
  • Hibernate 和可序列化实体

    有谁知道是否有一个框架能够从实体类中剥离 Hibernate 集合以使它们可序列化 我查看了 BeanLib 但它似乎只进行实体的深层复制 而不允许我为实体类中的集合类型指定实现映射 BeanLib 目前不适用于 Hibernate 3 5
  • 当我“绘制”线条时,如何将点平均分配到 LineRenderer 的宽度曲线?

    我正在使用线条渲染器创建一个 绘图 应用程序 现在我尝试使用线条渲染器上的宽度曲线启用笔压 问题在于 AnimationCurve 的 时间 值 水平轴 从 0 标准化为 1 因此我不能在每次添加位置时都在其末尾添加一个值 除非有一个我不知