Unity网格编程笔记[十]一些网格基础操作的封装(Mesh合并,UV映射,正反面反转,顶点合并,法线求切线计算等)

news2025/1/23 21:11:30

这里的代码是在 Unity网格编程笔记[五]网格切割
中整合出来的。

这里的mesh可以直接接入到使用mesh的unity组件

一些基础的属性还是要参考 Unity网格编程笔记[零]网格编程基础知识点

Mesh合并

网格的合并,其实底层也没那么复杂。对于三角面,只是顺序需要重新组织一下,其他的属性都是重新添加就可以了。

三角面的添加做法有点特别。

新添加的网格的三角面顺序不变。但是每个元素的顺序是在原来的三角面的基础上添加的。

这里个人认为应该是在顶点的顺序上添加,即用int length = mesh.vertexCount;替换下面的int length = triangles.Count;。经过实践发现可以做到切面正常缝合,切面的uv也没有问题。

个人认为这样改的原因是新添加的网格,他们的顶点顺序都是添加到了原网格的数组里,所以索引值都添加了mesh.vertexCount。那么他们对应的三角面的数组中的对应索引值应该也添加mesh.vertexCount。才能保证添加后的顶点索引能对应上顶点数组。

 public void Add(Mesh mesh)
        {
            for (int i = 0; i < mesh.vertexCount; i++)
            {
                vertices.Add(mesh.vertices[i]);
                uvs.Add(mesh.uv[i]);
                normals.Add(mesh.normals[i]);
                tangents.Add(mesh.tangents[i]);
            }
            int length = triangles.Count;
            //我替换后也能正确运行的做法 int length = mesh.vertexCount;
            for (int i = 0; i < mesh.triangles.Length; i++)
            {
                triangles.Add(mesh.triangles[i] + length);
            }
        }

顶点合并

这里的主要思想是将过于靠近并且属性几乎一致的顶点,去除掉,以免造成不必要的计算。

首先给定范围range,对于顶点和uv小于这个范围的纳入考虑范围。个人觉得这个范围分开来用数值表示比较好。

对于纳入范围的顶点,最后考虑他们的法线方向,当点积值等于1的时候,就认为法线方向相同。

这时进行顶点的删除

for (int k = 0; k < triangles.Count; k++)
{
     if (triangles[k] == j)
         triangles[k] = i;
     if (triangles[k] > j)
         triangles[k]--;
 }
 
 vertices.RemoveAt(j);
 normals.RemoveAt(j);
 tangents.RemoveAt(j);
 uvs.RemoveAt(j);

首先在triangles数组中到前后排序的两个属性相同位置相近的顶点中,将后面排序的顶点替换成前面的。然后替换后,对于遍历之后,位于该顶点在vertex数组之后的顶点,其索引值都减一。

减一的原因是在该顶点从vertex数组中被去除后,vertex数组位于该点后面的顶点在顶点序列中的存储的索引都会减少一位。而triangles中存储的就是顶点在vertex中的顶点索引。

public void CombineVertices(float range)
        {
            range *= range;
            for (int i = 0; i < vertices.Count; i++)
            {
                for (int j = i + 1; j < vertices.Count; j++)
                {
                    bool dis = (vertices[i] - vertices[j]).sqrMagnitude < range;
                    bool uv = (uvs[i] - uvs[j]).sqrMagnitude < range;
                    bool dir = Vector3.Dot(normals[i], normals[j]) > 0.999f;
                    if (dis && uv && dir)
                    {
                        for (int k = 0; k < triangles.Count; k++)
                        {
                            if (triangles[k] == j)
                                triangles[k] = i;
                            if (triangles[k] > j)
                                triangles[k]--;
                        }
                        vertices.RemoveAt(j);
                        normals.RemoveAt(j);
                        tangents.RemoveAt(j);
                        uvs.RemoveAt(j);
                    }
                }
            }
        }

面反转

  public void Reverse()
  {
      int count = triangles.Count / 3;
      for (int i = 0; i < count; i++)
      {
          int t = triangles[i * 3 + 2];
          triangles[i * 3 + 2] = triangles[i * 3 + 1];
          triangles[i * 3 + 1] = t;
      }
      count = vertices.Count;
      for (int i = 0; i < count; i++)
      {
          normals[i] *= -1;
          Vector4 tan = tangents[i];
          tan.w = -1;
          tangents[i] = tan;
      }
  }
  for (int i = 0; i < count; i++)
      {
          int t = triangles[i * 3 + 2];
          triangles[i * 3 + 2] = triangles[i * 3 + 1];
          triangles[i * 3 + 1] = t;
      }

这里的面反转,是将triangles数组的每三个顶点中的顺序的其中两个对调。这和面向相机的顶点是顺时针而反向相机的是逆时针的原因有关。

triangles中,每三个顶点是按照索引提升的顺序依次连接成面的。一般情况下,这样的自动连接是自动生成mesh的基础,所以连接顺序决定了面的法线朝向。法线永远是朝向图形学中的正面的。参考

正常情况下,在相机视角中,顶点的连接顺序从顺时针变成逆时针,或者从逆时针变成顺时针,那么这时面就翻转了。所以将三角数组triangles中的任意第二三个顶点调换顺序,后,再次按照索引升高的顺序连接三个顶点,一定会连接顺序变换。

Unity网格编程笔记[零]网格编程基础知识点

在连接顺序翻转之后,相关的属性也要相反,例如法线和切线

 for (int i = 0; i < count; i++)
      {
          normals[i] *= -1;
          Vector4 tan = tangents[i];
          tan.w = -1;
          tangents[i] = tan;
      }

法线直接乘以负一反向取反
但是切线的做法我回顾了 Unity学习shader笔记[三十一]关于顶点的法线、切线、副切线

在这里插入图片描述

才发现的,这里将翻转之前的面认为是正面了。准确一些的做法应该是

 tan.w = - tan.w ;

计算切线

 public static Vector4 CalculateTangent(Vector3 normal)
{
    Vector3 tan = Vector3.Cross(normal, Vector3.up);
    if (tan == Vector3.zero)
        tan = Vector3.Cross(normal, Vector3.forward);
    tan = Vector3.Cross(tan, normal);
    return new Vector4(tan.x, tan.y, tan.z, 1.0f);
}

这里计算切线,可以在世界坐标系或者局部坐标系下计算,结果都是一样的。判断叉乘结果是否等于零。原因是对于法线方向刚好正上方的顶点来说的,这时根据点积的原理,与正上方向量点积就是0.

那么此时该法线要与正前方做叉乘。其实根据法线求切线,求到的都是在一个平面空间下,即垂直于法线的平面空间,只要保证法线 切线 副切线两两垂直即可。所以这里直接用叉乘前或者上向量去求了。

最后再将此时求到的切线与法线叉乘,这是因为unity和maya中,切线空间是左手空间。切线 法线 副切线三者的分布与左手三指张开一样。
参考 Unity学习shader笔记[三十一]关于顶点的法线、切线、副切线
而叉乘的结果是右手定则,所以再次求叉乘,此时到切线与法线以及副切线的分布就与左手空间的三个手指一样了。

UV映射

 public void MapperCube(Rect range)
        {
            if (uvs.Count < vertices.Count)
                uvs = new List<Vector2>(vertices.Count);
            int count = triangles.Count / 3;
            for (int i = 0; i < count; i++)
            {
                int _i0 = triangles[i * 3];
                int _i1 = triangles[i * 3 + 1];
                int _i2 = triangles[i * 3 + 2];

                Vector3 v0 = vertices[_i0] - center + size / 2f;
                Vector3 v1 = vertices[_i1] - center + size / 2f;
                Vector3 v2 = vertices[_i2] - center + size / 2f;
                v0 = new Vector3(v0.x / size.x, v0.y / size.y, v0.z / size.z);
                v1 = new Vector3(v1.x / size.x, v1.y / size.y, v1.z / size.z);
                v2 = new Vector3(v2.x / size.x, v2.y / size.y, v2.z / size.z);

                Vector3 a = v0 - v1;
                Vector3 b = v2 - v1;
                Vector3 dir = Vector3.Cross(a, b);
                float x = Mathf.Abs(Vector3.Dot(dir, Vector3.right));
                float y = Mathf.Abs(Vector3.Dot(dir, Vector3.up));
                float z = Mathf.Abs(Vector3.Dot(dir, Vector3.forward));
                if (x > y && x > z)
                {
                    uvs[_i0] = new Vector2(v0.z, v0.y);
                    uvs[_i1] = new Vector2(v1.z, v1.y);
                    uvs[_i2] = new Vector2(v2.z, v2.y);
                }
                else if (y > x && y > z)
                {
                    uvs[_i0] = new Vector2(v0.x, v0.z);
                    uvs[_i1] = new Vector2(v1.x, v1.z);
                    uvs[_i2] = new Vector2(v2.x, v2.z);
                }
                else if (z > x && z > y)
                {
                    uvs[_i0] = new Vector2(v0.x, v0.y);
                    uvs[_i1] = new Vector2(v1.x, v1.y);
                    uvs[_i2] = new Vector2(v2.x, v2.y);
                }
                uvs[_i0] = new Vector2(range.xMin + (range.xMax - range.xMin) * uvs[_i0].x, range.yMin + (range.yMax - range.yMin) * uvs[_i0].y);
                uvs[_i1] = new Vector2(range.xMin + (range.xMax - range.xMin) * uvs[_i1].x, range.yMin + (range.yMax - range.yMin) * uvs[_i1].y);
                uvs[_i2] = new Vector2(range.xMin + (range.xMax - range.xMin) * uvs[_i2].x, range.yMin + (range.yMax - range.yMin) * uvs[_i2].y);
            }
        }

此代码片段是一个名为MapperCube的方法,它用于在一个立方体上进行UV映射。

首先,方法会检查uvs列表的大小是否小于vertices列表的大小,如果是,则会重新分配足够的空间。

然后,方法通过遍历triangles列表中的三角形索引,获取每个顶点的坐标。

通过将顶点坐标减去中心点并加上尺寸的一半,得到一个以中心点为原点的局部坐标系。

接下来,将局部坐标系中的坐标值除以立方体的尺寸值,得到归一化的UV坐标。

通过计算局部坐标系中两个向量的叉积,得到三角形的法向量。

接着,分别计算法向量在三个坐标轴上的投影长度,并比较三个投影长度的大小,确定UV映射的方式。

如果x投影长度最大,则将顶点的UV坐标设置为(v.z, v.y)。

如果y投影长度最大,则将顶点的UV坐标设置为(v.x, v.z)。

如果z投影长度最大,则将顶点的UV坐标设置为(v.x, v.y)。

最后,根据range矩形范围和计算出的UV坐标进行插值计算,将结果赋值给uvs列表中相应的索引位置。

该方法的作用是将三维立方体上的顶点映射到二维的UV坐标空间中,以便在渲染时进行贴图操作。

在三维计算机图形渲染中,UV映射是将三维模型的顶点映射到二维的纹理坐标空间中的过程。UV坐标确定了模型上每个顶点在纹理上的位置,使得纹理图案可以正确地贴在模型表面上。

以立方体为例,它有六个面,每个面都需要贴上纹理。为了实现这一目标,需要为每个顶点分配一个唯一的UV坐标。然后,根据模型的三角面片(triangles)定义,通过插值计算将UV坐标映射到三角面片上的其他点。

在上述代码中,为了获得每个顶点的UV坐标,首先将顶点的坐标值转换为局部坐标系,即以立方体中心为原点。然后,将局部坐标系中的坐标进行归一化处理,以确保UV坐标在(0,0)到(1,1)的范围内。

接下来,通过计算三角形的法向量及其在三个坐标轴上的投影长度,决定使用哪个坐标轴来映射UV。这样可以确保纹理在所有面片上的方向一致,避免出现纹理贴图的扭曲或扭转现象。

最后,使用给定的矩形范围和计算出的UV坐标进行插值计算,将结果赋值给uvs列表中相应的索引位置。这样,每个顶点都获得了正确的UV坐标,可以与纹理图案进行对应,从而实现正确的纹理贴图。

总的来说,UV映射是为了将模型上的顶点映射到纹理坐标空间中,以便在渲染时可以正确地将纹理贴图在模型表面上展示出来。该方法的目的是计算并为每个顶点分配正确的UV坐标。

所有代码

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
namespace SplitMesh
{/// <summary>
/// Mesh网格数据类
/// </summary>
    public class MeshInfo
    {
        public List<Vector3> vertices;
        public List<int> triangles;
        public List<Vector2> uvs;
        public List<Vector3> normals;
        public List<Vector4> tangents;
        public Vector3 size, center;
        public MeshInfo()
        {
            vertices = new List<Vector3>();
            triangles = new List<int>();
            uvs = new List<Vector2>();
            normals = new List<Vector3>();
            tangents = new List<Vector4>();
            size = center = Vector3.zero;
        }
        public MeshInfo(Mesh mesh)
        {
            vertices = new List<Vector3>(mesh.vertices);
            triangles = new List<int>(mesh.triangles);
            uvs = new List<Vector2>(mesh.uv);
            normals = new List<Vector3>(mesh.normals);
            tangents = new List<Vector4>(mesh.tangents);
            center = mesh.bounds.center;
            size = mesh.bounds.size;
        }
        public void Add(Mesh mesh)
        {
            for (int i = 0; i < mesh.vertexCount; i++)
            {
                vertices.Add(mesh.vertices[i]);
                uvs.Add(mesh.uv[i]);
                normals.Add(mesh.normals[i]);
                tangents.Add(mesh.tangents[i]);
            }
            int length = triangles.Count;
            //我替换后也能正确运行的做法 int length = mesh.vertexCount;
            for (int i = 0; i < mesh.triangles.Length; i++)
            {
                triangles.Add(mesh.triangles[i] + length);
            }
        }
        public void Add(Vector3 vert, Vector2 uv, Vector3 normal, Vector4 tangent)
        {
            vertices.Add(vert);
            uvs.Add(uv);
            normals.Add(normal);
            tangents.Add(tangent);
        }
        public Mesh GetMesh()
        {
            Mesh mesh = new Mesh();
            mesh.vertices = vertices.ToArray();
            mesh.uv = uvs.ToArray();
            mesh.normals = normals.ToArray();
            mesh.tangents = tangents.ToArray();
            mesh.triangles = triangles.ToArray();
            return mesh;
        }
        //public void MapperSphere(Rect range){}
        public void MapperCube(Rect range)
        {
            if (uvs.Count < vertices.Count)
                uvs = new List<Vector2>(vertices.Count);
            int count = triangles.Count / 3;
            for (int i = 0; i < count; i++)
            {
                int _i0 = triangles[i * 3];
                int _i1 = triangles[i * 3 + 1];
                int _i2 = triangles[i * 3 + 2];

                Vector3 v0 = vertices[_i0] - center + size / 2f;
                Vector3 v1 = vertices[_i1] - center + size / 2f;
                Vector3 v2 = vertices[_i2] - center + size / 2f;
                v0 = new Vector3(v0.x / size.x, v0.y / size.y, v0.z / size.z);
                v1 = new Vector3(v1.x / size.x, v1.y / size.y, v1.z / size.z);
                v2 = new Vector3(v2.x / size.x, v2.y / size.y, v2.z / size.z);

                Vector3 a = v0 - v1;
                Vector3 b = v2 - v1;
                Vector3 dir = Vector3.Cross(a, b);
                float x = Mathf.Abs(Vector3.Dot(dir, Vector3.right));
                float y = Mathf.Abs(Vector3.Dot(dir, Vector3.up));
                float z = Mathf.Abs(Vector3.Dot(dir, Vector3.forward));
                if (x > y && x > z)
                {
                    uvs[_i0] = new Vector2(v0.z, v0.y);
                    uvs[_i1] = new Vector2(v1.z, v1.y);
                    uvs[_i2] = new Vector2(v2.z, v2.y);
                }
                else if (y > x && y > z)
                {
                    uvs[_i0] = new Vector2(v0.x, v0.z);
                    uvs[_i1] = new Vector2(v1.x, v1.z);
                    uvs[_i2] = new Vector2(v2.x, v2.z);
                }
                else if (z > x && z > y)
                {
                    uvs[_i0] = new Vector2(v0.x, v0.y);
                    uvs[_i1] = new Vector2(v1.x, v1.y);
                    uvs[_i2] = new Vector2(v2.x, v2.y);
                }
                uvs[_i0] = new Vector2(range.xMin + (range.xMax - range.xMin) * uvs[_i0].x, range.yMin + (range.yMax - range.yMin) * uvs[_i0].y);
                uvs[_i1] = new Vector2(range.xMin + (range.xMax - range.xMin) * uvs[_i1].x, range.yMin + (range.yMax - range.yMin) * uvs[_i1].y);
                uvs[_i2] = new Vector2(range.xMin + (range.xMax - range.xMin) * uvs[_i2].x, range.yMin + (range.yMax - range.yMin) * uvs[_i2].y);
            }
        }
        public void CombineVertices(float range)
        {
            range *= range;
            for (int i = 0; i < vertices.Count; i++)
            {
                for (int j = i + 1; j < vertices.Count; j++)
                {
                    bool dis = (vertices[i] - vertices[j]).sqrMagnitude < range;
                    bool uv = (uvs[i] - uvs[j]).sqrMagnitude < range;
                    bool dir = Vector3.Dot(normals[i], normals[j]) > 0.999f;
                    if (dis && uv && dir)
                    {
                        for (int k = 0; k < triangles.Count; k++)
                        {
                            if (triangles[k] == j)
                                triangles[k] = i;
                            if (triangles[k] > j)
                                triangles[k]--;
                        }
                        vertices.RemoveAt(j);
                        normals.RemoveAt(j);
                        tangents.RemoveAt(j);
                        uvs.RemoveAt(j);
                    }
                }
            }
        }
        public void Reverse()
        {
            int count = triangles.Count / 3;
            for (int i = 0; i < count; i++)
            {
                int t = triangles[i * 3 + 2];
                triangles[i * 3 + 2] = triangles[i * 3 + 1];
                triangles[i * 3 + 1] = t;
            }
            count = vertices.Count;
            for (int i = 0; i < count; i++)
            {
                normals[i] *= -1;
                Vector4 tan = tangents[i];
                tan.w = -1;
                tangents[i] = tan;
            }
        }

        public static Vector4 CalculateTangent(Vector3 normal)
        {
            Vector3 tan = Vector3.Cross(normal, Vector3.up);
            if (tan == Vector3.zero)
                tan = Vector3.Cross(normal, Vector3.forward);
            tan = Vector3.Cross(tan, normal);
            return new Vector4(tan.x, tan.y, tan.z, 1.0f);
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/942577.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LiveGBS伴侣

【1】LiveGBS 简介 LiveGBS是一套支持国标(GB28181)流媒体服务软件。 国标无插件;提供用户管理及Web可视化页面管理&#xff1b; 提供设备状态管理&#xff0c;可实时查看设备是否掉线等信息&#xff1b; 实时流媒体处理&#xff0c;PS&#xff08;TS&#xff09;转ES&…

python的安装(推荐)

torch安装与卸载推荐链接1推荐链接2 推荐链接3 安装pytorch步骤推荐链接 python关键字&#xff1a;

19.CSS雨云动画特效

效果 源码 <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Cloud & Rain Animation</title><link rel="stylesheet" href="style.css"> </head> <bo…

SpringCluod深入教程

1.Nacos配置管理 Nacos除了可以做注册中心&#xff0c;同样可以做配置管理来使用。 1.1.统一配置管理 当微服务部署的实例越来越多&#xff0c;达到数十、数百时&#xff0c;逐个修改微服务配置就会让人抓狂&#xff0c;而且很容易出错。我们需要一种统一配置管理方案&#…

Jmeter+ServerAgent

一、Jmeter 下载 https://jmeter.apache.org/download_jmeter.cgi选择Binaries二进制下载 apache-jmeter-5.6.2.tgz 修改配置文件 jmeter下的bin目录&#xff0c;打开jmeter.properties 文件 languagezh_CN启动命令 cd apache-jmeter-5.6/bin sh jmeter二、ServerAgent 监…

Mysql--技术文档--MVCC(Multi-Version Concurrency Control | 多版本并发控制)

MVCC到底是什么 MVCC&#xff08;Multi-Version Concurrency Control&#xff09;是一种并发控制机制&#xff0c;用于解决并发访问数据库时的数据一致性和隔离性问题。MVCC允许多个事务同时读取数据库的同一数据&#xff0c;而不会相互干扰或导致冲突。 在传统的并发控制机制中…

CTFhub-文件上传-无验证

怎样判断一个网站是 php asp jsp 网站 首先&#xff0c;上传用哥斯拉生成 .php 文件 然后&#xff0c;用蚁剑测试连接 找到 flag_1043521020.php 文件&#xff0c;进去&#xff0c;即可发现 flag ctfhub{ee09842c786c113fb76c5542}

「Vue|网页开发|前端开发」02 从单页面到多页面网站:使用路由实现网站多个页面的展示和跳转

本文主要介绍如何使用路由控制来实现将一个单页面网站扩展成多页面网站&#xff0c;包括页面扩展的逻辑&#xff0c;vue的官方路由vue-router的基本用法以及扩展用法 文章目录 一、场景说明二、基本的页面扩展页面扩展是在扩什么创建新页面的代码&#xff0c;让页面内容变化起…

windows系统配置tcp最大连接数

打开注册表 运行->regedit HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters目录下 增加一个MaxUserPort&#xff08;默认值是5000&#xff0c;端口范围是1025至5000&#xff09;MaxUserPort设置为65534&#xff08;需重启服务器&#xff09; 执行dos命令&…

登高不系安全带自动识别

登高不系安全带自动识别采用yolov8深度学习算法框架模型&#xff0c;登高不系安全带自动识别能够自动检测和识别登高作业人员是否佩戴安全带&#xff0c;过滤其他类似物体的干扰。登高不系安全带自动识别发现有人员未佩戴安全带&#xff0c;将立即触发预警。根据YOLO的设计&…

使用PXE启动无系统盘的客户机并运行Ubuntu系统

准备 机器说明server安装pxe相关软件&#xff0c;nfs-kernel-server&#xff0c;ip192.168.1.2client1带有硬盘&#xff0c;使用iso安装ubuntu系统&#xff0c;并安装日常工作需要用到的软件&#xff0c;做好相应配置&#xff0c;安装nfs客户端&#xff1a;nfs-commonclient2没…

javacv基础03-调用本机摄像头并截图保存到本地磁盘

基于基础02 的基础上对视频进行取帧保存 代码如下&#xff1a; package com.example.javacvstudy;/*** 本地摄像头截图*/import org.bytedeco.javacv.CanvasFrame; import org.bytedeco.javacv.FrameGrabber; import org.bytedeco.javacv.OpenCVFrameConverter; import org.b…

避免常见面试错误:程序员应该注意的陷阱

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

《Flink学习笔记》——第九章 多流转换

无论是基本的简单转换和聚合&#xff0c;还是基于窗口的计算&#xff0c;我们都是针对一条流上的数据进行处理的。而在实际应用中&#xff0c;可能需要将不同来源的数据连接合并在一起处理&#xff0c;也有可能需要将一条流拆分开&#xff0c;所以经常会有对多条流进行处理的场…

​LeetCode解法汇总57. 插入区间

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; https://github.com/September26/java-algorithms 原题链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 描述&#xff1a; 给你一个 …

python web GUI框架-NiceGUI 教程(一)

python web GUI框架-NiceGUI 教程&#xff08;一&#xff09; streamlit可以在一些简单的场景下仍然推荐使用&#xff0c;但是streamlit实在不灵活&#xff0c;受限于它的核心机制&#xff0c;NiceGUI是一个灵活的web框架&#xff0c;可以做web网站也可以打包成独立的exe。 基…

科研小工具|心输出量(超声)(cardiac output,CO)

​ 简介 心输出量&#xff08;cardiac output&#xff0c;CO&#xff09;是指左或右心室每分钟泵出的血液量。即心率与每搏出量的乘积。如心率以75次/分钟计算&#xff0c;则心排出量在男性为5~6L&#xff0c;女性略低些。心排出量随着机体代谢和活动情况而变化。在肌肉运动、…

783页19万字行政服务中心一网通办政务服务应用平台建设方案

导读&#xff1a;原文《783页19万字行政服务中心一网通办政务服务应用平台建设方案》&#xff08;获取来源见文尾&#xff09;&#xff0c;本文精选其中精华及架构部分&#xff0c;逻辑清晰、内容完整&#xff0c;为快速形成售前方案提供参考。以下是部分内容&#xff0c; 第三…

阿里巴巴FastJson包的使用心得

阿里巴巴FastJson包的使用心得 1.FastJson简介2.FastJson特性3.引入FastJson4.FastJson中的一些对象&#xff08;1&#xff09;JSONObject&#xff08;2&#xff09;JSONArray&#xff08;3&#xff09;SerializeWriter 4.FastJson中的一些操作&#xff08;1&#xff09; 将Jav…

配置uniapp调试环境

目录 uni-app介绍 uni-app开发工具HBuilderX 创建项目前提条件 uni-app项目结构 配置mumu模拟器 uni-app生命周期 1.应用生命周期 小程序规范 2.页面生命周期-小程序规范 3.组件生命周期 vue规范 uni-app登录按钮方法 uni-app发布安卓app uni-app介绍 uni-app 是一个…