unity 绘制属性雷达图 - 绘制描边(更改uv)

2023-11-13

实现的效果
效果图
先绘制一个五边形的mesh,然后在给边缘绘制一圈mesh。
对uv进行重新赋值,实现描边效果

第一步 绘制mesh

绘制多边形mesh,首先先绘制一个五边形。

mesh绘制要素:顶点,三角形,uv信息

顶点信息

就是勾勒三角形用的几个顶点。
按照五边形来说的画, 五边形是五个边。
因为每个边的顶点要做拉伸,所以以中心点为原点,向外扩展画三角形,方便后续操作。
顶点顺序可以按照下图顺序。
在这里插入图片描述

绘制三角形

绘制三角形的时候,顶点排列顺序要按照顺时针的方向进行排列才可以绘制出来
在这里插入图片描述
所以第一个三角形,顶点依次是:0,1,2
剩下的依次进行循环赋值就可以了

uv信息

为了先绘制出五边形,我们先把uv信息设置为顶点信息显示。

代码实现
	[SerializeField]
 	private MeshFilter m_MeshFilter;

    [SerializeField]
    [Range(3, 10)]
    private int m_Sides = 4; //边数量

    [SerializeField]
    private float[] m_DistanceList; //对应各个边长
    [SerializeField] private Vector3 m_Origin; //中心点
    //绘制mesh
	private void DrawMesh()
    {
        if (m_MeshFilter == null)
        {
            return;
        }

        Vector3[] vertices = new Vector3[m_Sides + 2];
        Vector2[] uv = new Vector2[vertices.Length];
        int[] triangles = new int[m_Sides * 3];

        vertices[0] = m_Origin;
        uv[0] = new Vector2(0.5f, 0.5f);

        float angle = 0;
        float angleIncrease = 360f / m_Sides;

        int verticesIndex = 1;
        int triangleIndex = 0;
        for (int i = 0; i <= m_Sides; i++)
        {
            var dir = GetVectorFromAngle(angle);//一定的边长下,根据角度得到方向
            vertices[verticesIndex] = m_Origin + dir * GetDisance(i);
            uv[verticesIndex] = uv[0] + new Vector2(dir.x, dir.y) * 0.5f;

            if (i > 0)
            {
                triangles[triangleIndex] = 0;
                triangles[triangleIndex + 1] = verticesIndex - 1;
                triangles[triangleIndex + 2] = verticesIndex;
                triangleIndex += 3;
            }

            verticesIndex++;
            angle -= angleIncrease;
        }

        if (m_Mesh == null)
        {
            m_Mesh = new Mesh();
        }
        m_Mesh.Clear();
        m_Mesh.vertices = vertices;
        m_Mesh.uv = uv;
        m_Mesh.triangles = triangles;

        m_MeshFilter.mesh = m_Mesh;
    }
	private Vector3 GetVectorFromAngle(float angle)
    {
        float angleRad = angle * (Mathf.PI / 180f);
        return new Vector3(Mathf.Cos(angleRad), Mathf.Sin(angleRad));
    }

    private float GetDisance(int index)
    {
        if (index >= m_DistanceList.Length)
        {
            index = 0;
        }
        return m_DistanceList[index];
    }

在这里插入图片描述
可以调整参数绘制多边形

第二部 绘制描边

绘制描边的思路,是围绕多边形顶点,像内部偏移一定的距离,在绘制一层
在这里插入图片描述
需要注意的是定长的是紫色H,而不是顶点到内部顶点的长度。外部顶点到内部顶点的长度,会随着边长的不一定,导致画出来的边是不一定的。只有保持H的宽度不变, 才能保证描边是均匀宽度。否则可能是这样
在这里插入图片描述
可简化成三角函数问题。如下图。
C角可以通过 , 360/边数得到
a,b就是所在的边长
H是定长,已知 的数值
如果想要求?的长度,就需要知道A角的大小

在这里插入图片描述
推到过程 (学的三角函数都还给老师了, 硬给推导出来的,如果有简单方案,欢迎提供)
在这里插入图片描述

//获得内圈顶点的长度
private float CountMoveLength(float a , float b)
    {
        float c = Mathf.Sqrt(Mathf.Pow(a, 2) + Mathf.Pow(b, 2) - 2 * a * b * Mathf.Cos(72f * Mathf.Deg2Rad));
         float sinA = a * Mathf.Sign(72 * Mathf.Deg2Rad) / c;
        if (sinA == 0) // 处理一下sinA等于0的情况,除数不能为0
            sinA = 0.1f;
        return b - m_lineWidth / sinA;
    }

由于相邻两个三角形的角度不同所以会导致计算出来的两个点不在同一点上,所以我们就把三角形顶点分开来计算
在这里插入图片描述

效果图:
在这里插入图片描述
但是如果把边长拉的很小,在边缘的部分可能会出现的问题:
在这里插入图片描述
所以我们需要进一步进行顶点边缘优化

第三步 边缘优化

出现上面的原因是,由于在同一个边上,分出来了两个顶点,分别给了左右两边的三角形,但是如果很夸张的话会导致三角形最外层的顶点不能重合,所以就需要我们计算两个交点, 让最外层的两个顶点在相交的地方重合,就可以避免了。计算交点,顶点重新赋值就可以了。
计算交点的代码:

private Vector3 GetIntersection(Vector3 lineAStart, Vector3 lineAEnd, Vector3 lineBStart, Vector3 lineBEnd)
    {
        float x1 = lineAStart.x, y1 = lineAStart.y;
        float x2 = lineAEnd.x, y2 = lineAEnd.y;
 
        float x3 = lineBStart.x, y3 = lineBStart.y;
        float x4 = lineBEnd.x, y4 = lineBEnd.y;
 
        //两向量相互垂直,返回0
        if (x1 == x2 && x3 == x4 && x1 == x3)
        {
            return Vector3.zero;
        }
 
        //两向量相互平行。返回0
        if (y1 == y2 && y3 == y4 && y1 == y3)
        {
            return Vector3.zero;
        }
 
        //两向量相互垂直,返回0
        if (x1 == x2 && x3 == x4)
        {
            return Vector3.zero;
        }
 
        //两向量相互平行。返回0
        if (y1 == y2 && y3 == y4)
        {
            return Vector3.zero;
        }
        float x, y;
 
        if (x1 == x2)
        {
            float m2 = (y4 - y3) / (x4 - x3);
            float c2 = -m2 * x3 + y3;
 
            x = x1;
            y = c2 + m2 * x1;
        }
        else if (x3 == x4)
        {
            float m1 = (y2 - y1) / (x2 - x1);
            float c1 = -m1 * x1 + y1;
 
            x = x3;
            y = c1 + m1 * x3;
        }
        else
        {
            float m1 = (y2 - y1) / (x2 - x1);
            float c1 = -m1 * x1 + y1;
            float m2 = (y4 - y3) / (x4 - x3);
            float c2 = -m2 * x3 + y3;
            x = (c1 - c2) / (m2 - m1);
            y = c2 + m2 * x;
        }
 
        return new Vector3(x, y, 0);

    }
第四步 Reset uv

为了调整描边的大小,uv需要做一个调整。
uv调整的前提需要了解uv是什么, 怎么工作的才能更好的做一个拉伸
在这里插入图片描述

把一个四边形,拉伸到一个五边形,让外部边缘重合。
内部的一圈可以拉一个变量出来,然后可以根据图片的边缘,来调整真正的描边效果

private void ResetUV()
    {
        Vector2[] uv = m_Mesh.uv;
        uv[0] = new Vector2(0.5f, 0.5f);
        List<Vector2> rectUV = new List<Vector2>(4);
        rectUV.Add(new Vector2(0,0));
        rectUV.Add(new Vector2(0,1));
        rectUV.Add(new Vector2(1,1));
        rectUV.Add(new Vector2(1,0));
        
        List<Vector2> rectInUV = new List<Vector2>(4);
        rectInUV.Add(new Vector2(linePercent,linePercent));
        rectInUV.Add(new Vector2(linePercent,1 -linePercent));
        rectInUV.Add(new Vector2(1 - linePercent,1-linePercent));
        rectInUV.Add(new Vector2(1-linePercent,linePercent));
        if (m_Sides > rectUV.Count)
        {
            int diff = m_Sides - rectUV.Count;
            float everyLength = 1f / (diff + 1);
            for (int i = 0; i < diff; i++)
            {
                rectUV.Insert(3+i,new Vector2(1,everyLength*(i+1)));
                rectInUV.Insert(3+i,new Vector2(1-linePercent,everyLength*(i+1)));
            }
        }
        for (int i = 0; i < m_Sides; i++)
        {
            uv[i*4 + 1] = uv[GetVerticesIndexByIndex(i*4 - 1)] = rectUV[i];
            uv[i*4 + 2] = uv[GetVerticesIndexByIndex(i*4)] = rectInUV[i];
        }
        m_Mesh.uv = uv;
    }
    private int GetVerticesIndexByIndex(int index)
    {
        if (index <= 0)
        {
            return vertices.Length + index -1;
        }else if (index >= vertices.Length)
        {
            return vertices.Length + index - 1;
        }
        else
            return index;
    }

    public Vector2 GetPointByIndex(int index)
    {
        float angle = m_Roatation;
        float angleIncrease = 360f / m_Sides;
        var dir = GetVectorFromAngle(angle);
        dir = GetVectorFromAngle(angle-angleIncrease*index);
        return m_Origin + dir * GetDisance(index);

    }

效果图
在这里插入图片描述

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

unity 绘制属性雷达图 - 绘制描边(更改uv) 的相关文章

  • 在 SceneKit 中使用 Metal 着色器

    我想用一个Metal着色器将卡通 单元着色应用于场景中使用的材质 我试图实现的着色器是苹果自己的AAPLCelShader发现于金属着色器展示柜 https developer apple com library ios samplecod
  • 游戏开发中常见系统梳理之背包系统的实现一

    游戏中几乎都存在大大小小的背包系统 接下来我将讲述背包系统具体是如何实现的 完整源码 以下是使用unity NGUI实现 使用txt配置的方法 后续更新UGUI Json实现的背包系统敬请期待 背包中的物品我们常常将其制作成预设体 通过改变
  • Qt3D默认制服和属性

    我开始学习通过 QML 使用着色器 但找不到任何讨论传递给着色器的默认统一和属性值的参考资料 在某些示例中 我们可以看到其中的几个 例如顶点位置 or 模型视图投影 这也被传递为mvp 但是没有包含我们可以使用的所有变量的清晰列表 在调查
  • LibGDX 网格高度图法线和灯光

    我正在尝试让网格法线和灯光在 LibGDX 项目中工作 我已经有了从高度图纹理像素生成的纹理网格 问题是我无法正确点亮法线 另外 我不能 100 确定我在 TerrainChunk 类中正确设置了法线顶点 这是主类代码 package co
  • 环境错误:Gmsh 版本必须 >= 2.0

    我是 fipy 的新手 所以如果我问一些应该显而易见的问题 请原谅我的无知 但我无法运行已经存在的 并且在其他机器上工作的 脚本 无法获取EnvironmentError Gmsh version must be gt 2 0 我可能在安装
  • 使用 texelFetch() 进行纹理化

    当我将非最大值传递到纹理缓冲区时 在渲染时它会绘制具有最大值颜色的几何图形 我在使用 glTexBuffer API 时发现了这个问题 例如 假设我的纹理数据是GLubyte 当我传递任何小于255的值时 那么颜色与用255绘制的颜色相同
  • OpenGL 定向光着色器

    我想使用 OpenGL 和 GLSL 将定向光添加到我的场景中 问题在于 理论上正确的方法会产生错误的结果 在顶点着色器中我执行以下操作 光线的方向以世界坐标给出 并使用 viewMatrix 转换为相机坐标 使用法线矩阵将顶点的法线转换为
  • GLSL 纹理立方体和纹理2D 在同一着色器中

    我似乎无法两者兼得texture2D and textureCube 在一个着色器中 当我这样做时 什么也没有显示 也没有错误 我用我自己的着色器加载器和 Apple GLSL 着色器生成器尝试了这一点 并且发生了同样的事情 即使我有也会发
  • 完成部分网格并使其不漏水

    我正在从 RealSense 相机捕获点云 并使用 Trimesh 库将它们转换为网格 问题是我只能从中得到一个不防水的网格 如何 完成 网格并使其防水 I tried trimesh repair broken faces mesh co
  • THREE.JS 加载 STL 网格数组

    因此 我有一个数据库 其中包含文件引用列以及对其所需的子 STL 文件的任何引用 我可以将一两个模型加载到 THREE js 查看器中 因此所有这些都可以正常工作 但是当我加载四个左右的数组时 事情开始变得毛茸茸的 分配的网格 ID 开始变
  • OpenGL ES 2.0 多个程序或多着色器还是什么?它是如何工作的?

    问题 TL DR 我的问题从根本上来说是我不知道 OpenGL ES 2 0 期望我如何编写和使用多个着色器 或者如果甚至建议 期望一个人会这样做 这里的基本问题是 如果我有一个苹果 一块发光的岩石和一个模糊网格 它们都在同一个 3D 世界
  • 如何使用鼠标改变OpenGL相机

    我正在尝试在 OpenGL 中设置一个相机来查看 3 维中的一些点 为了实现这一点 我不想使用旧的 固定的功能样式 glMatrixMode glTranslate 等 而是自己设置模型视图投影矩阵并在我的顶点着色器中使用它 正交投影就足够
  • 对数/线性 Z 缓冲区阴影贴图

    问题在于 伪影出现在距离很远的阴影中 我想尝试制作一个对数深度缓冲区 但我不明白应该在哪里完成以及如何完成 我对全向阴影贴图使用点光源方法 顶点着色器 version 460 core layout location 0 in vec3 a
  • 如何在 WebGL 中创建合适的圆角矩形?

    我试图实现答案这个问题 https stackoverflow com questions 43970170 bordered rounded rectangle in glsl但似乎有点问题 如果您打开他们的 ShaderToys 并尝试
  • 如何在 python Open3d 中向网格添加纹理?

    我正在使用 python Open3d 处理三角形网格 我想向我的网格添加纹理映射 我在文档中没有找到它 这是一个带有简单立方体网格的示例代码 import numpy as np import open3d as o3d vert 0 0
  • 对 VBO 中的特定三角形使用不同的纹理

    我有 9 个由三角形组成的四边形 如下所示 我在用着VBO存储有关它们的数据 它们的位置和纹理坐标 我的问题是 是否可以仅使用一个来使四边形 5 具有与其余四边形不同的纹理VBO and shader 绿色代表纹理 1 黄色代表纹理 2 到
  • Phong 着色问题

    我正在根据以下内容编写着色器冯模型 http en wikipedia org wiki Phong reflection model 我正在尝试实现这个方程 其中 n 是法线 l 是光线方向 v 是相机方向 r 是光反射 维基百科文章中更
  • 如何将网格转换为VTK格式?

    我有一个自己格式的网格 我想将其导出到 vtk 文件 我该怎么做呢 原始网格的格式如下 伪代码 class Mesh List
  • 在 OpenGL ES 1.1 中将多个纹理绑定到一个网格

    如果我有一个网格 例如有 6 个面的立方体 每个面分别由 4 个顶点组成 总共 24 个顶点 并且我想对每个面应用不同的纹理 我该怎么做 目前 我使用 glDrawElements 一次绘制整个网格 立方体的所有 6 个面 将所有索引提供到
  • 如何挤出平面 2D 网格并赋予其深度

    我有一组共面 连接的三角形 即二维网格 现在我需要将其在 z 轴上挤出几个单位 网格由一组顶点定义 渲染器通过与三角形数组匹配来理解这些顶点 网格示例 顶点 0 0 0 10 0 0 10 10 0 0 10 0 所以这里我们有一个二维正方

随机推荐

  • 搭建Prometheus监控报警服务

    什么是Prometheus Prometheus是由SoundCloud开发的开源监控报警系统和时序列数据库 TSDB Prometheus使用Go语言开发 是Google BorgMon监控系统的开源版本 2016年由Google发起Li
  • 关于端口协议Up down的一点理解

    在处理网络障碍的时候 经常需要查看端口的状态 端口所配协议的状态 使用一些常用的工具里投入ping等命令进行测试 然后大家有没有发现 路由器或者三层交换机针对于广域网的端口的查看和以太网的端口查看包括ping等有很大区别 在此将自己的理解概
  • 数据结构与算法--分治策略

    目录 1 分治概念 2 递归的概念递归 3 分治策略的 1 分治策略的特征 2 分治法步骤 4 栈的面试题 5 示例 1 示例1求解n的阶乘 1 分析 2 阶乘可递归的定义为 3 递归程序 4 图解递归过程 代码的调动过程 5 图解递归过程
  • git提交多个文件到远程服务器,解决使用commit提交大文件无法推送到远程库问题及git rebase使用详解...

    解决这个问题并没有特别的 删除提交历史中某个文件 然后重新push 但是由于开始的使用失误 中间有使用git rebase和git reset命令处理 所以特此记录下 大文件无法push到远程仓库 问题 首先 故事 事故 的起因是这样的 某
  • SpringJDBC与声明式事务操作

    文章目录 Spring JDBC与事务操作 一 Spring整合JDBC的环境 一 添加依赖坐标 二 添加jdbc properties的配置 三 创建Spring的配置文件 四 配置数据源 五 JDBC测试 二 持久层账户模块操作 例 一
  • qt中的菜单QMenu QAction

    Qt中要建立菜单 有三个类很重要 QMenuBar QWidget parent 0 QMenu QWidget parent 0 QMenu const QString title QWidget parent 0 QAction QOb
  • Spring AOP三种方式定义增强

    一 通过实现 implements 的方式增强 BeforeLog package cn log import java lang reflect Method import org springframework aop MethodBe
  • 几个算法举例。

    如何计算某个数x是否是2的幂次方 因为若y为2的幂 则为x 2 y 在2进制位的表示中在第y 1位上为1 其余为0 则 x 1 x 0 即可以得出x是否为2的幂次方 百鸡问题 若公鸡价钱为5 母鸡价钱为3 小鸡价钱为1 3 则100元买10
  • 【python】python实现类似fiddler 底层抓包

    Fiddler抓包 Fiddler抓包代理 Fiddler 是一款用于网络抓包和调试的工具 它的底层抓包采用了代理服务器技术 当 Fiddler 启动时 它会在本地计算机上创建一个代理服务器 该代理服务器会拦截通过计算机网络传输的所有网络请
  • 常用正则表达式

  • python网络爬虫--项目实战--scrapy爬取贝壳网(7)

    一 完整代码 bk py import json import scrapy from ScrapyAdvanced items import HouseItem class BkSpider scrapy Spider name bk a
  • java如何根据模板填充数据生成word文档

    java根据模板填充数据生成word文档 这篇文章干什么 思路总览 1 准备word模板 2 转换文件格式 3 编写代码 补充 下载流 这篇文章干什么 使用代码将word模板内容进行替换 并输出替换后的word 思路总览 1 准备一个wor
  • 计算机很多文件无法删除,电脑有文件删不掉怎么办?电脑有文件删不掉解决方法介绍...

    电脑是我们日常生活中经常使用的一种电子产品 有了电脑之后 我们的生活方式也因此而改变了许多 大多数人都是以电脑作为娱乐产品 电脑让我们在工作学习时资源共享也更方便了一些 效率得到了很大提高 但是作为 高科 技产品 很多人对电脑的使用其实并不
  • 【MATLAB编程学习】自己实现矩阵乘法

    MATLAB编程学习 自己实现矩阵乘法 欢迎关注 高强度更新和MATLAB PYTHON编程 C 编程 算法编程 深度学习 自然语言处理 图像处理 OPENCV等相关知识 这是也给简单的课后题 不过可以帮助我们更好的理解矩阵乘法以及matl
  • 反卷积通俗详细解析与nn.ConvTranspose2d重要参数解释

    文章目录 反卷积的作用 卷积中padding的几个概念 No Padding Half Same Padding Full Padding 反卷积 反卷积中的Padding参数 反卷积的stride参数 反卷积的output padding
  • 0、1编码

    一 声音的0 1编码 1 声音数据的编码过程 声音是一种连续的波 要把连续的波用0 1进行编码 需要经过采样 量化两步完成 1 采样就是每隔一定的时间 测取连续波上的一个振幅值 2 量化就是用一个二进制尺子计量采样得到的每个脉冲 假设有图1
  • openwrt之initramfs-kernel

    在下载openwrt系统时 经常能看到initramfs kernel bin squashfs factory bin squashfs sysupgrade bin等结尾的文件 factory适用于从原厂系统刷到openwrt sysu
  • The “path“ argument must be of type string. Received undefined; at(Object.extname)

    validateString下一行是 Object extname path js 752 5 的报错 原因是在nuxt config js中 把plugins的参数写错了 此处省略大量代码 const baseConfig require
  • Activiti 流程启动及节点流转源码分析

    作者 jiankunking 出处 http blog csdn net jiankunking 本文主要是以activiti study中的xiaomage xml流程图为例进行跟踪分析 具体的流程图如下 流程图对应的XML文件如下
  • unity 绘制属性雷达图 - 绘制描边(更改uv)

    实现的效果 先绘制一个五边形的mesh 然后在给边缘绘制一圈mesh 对uv进行重新赋值 实现描边效果 第一步 绘制mesh 绘制多边形mesh 首先先绘制一个五边形 mesh绘制要素 顶点 三角形 uv信息 顶点信息 就是勾勒三角形用的几