/// <summary> /// 计算一组三角形网格中每个顶点的Normal值 /// 1.对每个三角形片元分析,根据*三个顶点*的坐标位置计算出该片元的法向矢量 /// 2.将法向矢量赋值给三个顶点 /// 3.对有片元进行处理完毕后,每个顶点的normal值是所有*与之相邻的片元法向矢量的和* /// 4.最后遍历每个顶点,对Norma值归一化即可 /// </summary> /// <param name="inputVex"></param> /// <param name="inputInd"></param> public static void ComputeVertexNormal(ref MyVertex[] inputVex, int[] inputInd) { // 遍历每个三角形片元 for (int i = 0; i < inputInd.Length / 3; i++) { // 三角形对应的三个顶点索引 int i0 = inputInd[i * 3 + 0]; int i1 = inputInd[i * 3 + 1]; int i2 = inputInd[i * 3 + 2]; // 三角形三个顶点 MyVertex v0 = inputVex[i0]; MyVertex v1 = inputVex[i1]; MyVertex v2 = inputVex[i2]; // 计算平面法向矢量 Vector3 e0 = v1.Position - v0.Position; Vector3 e1 = v2.Position - v0.Position; Vector3 faceNormal = Vector3.Cross(e0, e1); // 因为这个三角形占用了这三个顶点 // 因此这三个顶点的normal值应该添加该平面三角形的法线向量 inputVex[i0].Normal += faceNormal; inputVex[i1].Normal += faceNormal; inputVex[i2].Normal += faceNormal; } // 遍历每个顶点,将其Normal值归一化 for (int i = 0; i < inputVex.Length; i++) { inputVex[i].Normal = Vector3.Normalize(inputVex[i].Normal); } }
public static MeshData[] LoadModelFromFile(string filename) { var importer = new AssimpContext(); if (!importer.IsImportFormatSupported(System.IO.Path.GetExtension(filename))) { throw new ArgumentException($"Model format {System.IO.Path.GetExtension(filename)} is not supported. Cannot load {filename}.", nameof(filename)); } var postProcessFlags = PostProcessSteps.GenerateSmoothNormals | PostProcessSteps.CalculateTangentSpace; var model = importer.ImportFile(filename, postProcessFlags); List <MeshData> meshDatas = new List <MeshData>(model.MeshCount); MeshData meshData = new MeshData(); foreach (var mesh in model.Meshes) { List <MyVertex> myVertices = new List <MyVertex>(mesh.VertexCount); for (int i = 0; i < mesh.VertexCount; i++) { var pos = mesh.HasVertices ? mesh.Vertices[i].ToVector3() : new Vector3(); var norm = mesh.HasNormals ? mesh.Normals[i] : new Vector3D(); var texC = mesh.HasTextureCoords(0) ? mesh.TextureCoordinateChannels[0][i] : new Vector3D(1, 1, 0); var v = new MyVertex(pos, norm.ToVector3(), texC.ToVector2()); myVertices.Add(v); } var indices = mesh.GetIndices().ToList(); meshData.Vertices = myVertices.ToArray(); meshData.Indices = indices.ToArray(); meshDatas.Add(meshData); } return(meshDatas.ToArray()); }
/// <summary> /// 生成平面 /// </summary> /// <param name="length">平面长度 X方向</param> /// <param name="width">平面宽度 Z方向</param> /// <param name="lenNum">X方向切片数</param> /// <param name="widNum">Z方向切片数</param> /// <param name="outMesh">输出数据</param> public static void GeneratePlane(float length, float width, int lenNum, int widNum, out MeshData outMesh) { //[0]顶点数据 List <MyVertex> tempVertice = new List <MyVertex>(); MyVertex tempVex; lenNum += 1; widNum += 1; float dl = length / lenNum; float dw = width / widNum; float y = 0f; for (int i = 0; i < lenNum; i++) { float x = -length / 2 + i * dl; //第i列(从前往后) for (int j = 0; j < widNum; j++) { //第j行(从左往右) float z = -width / 2 + j * dw; tempVex = new MyVertex(); tempVex.Position = new Vector3(x, y, z); tempVex.Normal = new Vector3(0, 1, 0); tempVertice.Add(tempVex); } } //[1]索引数据 List <int> tempIndex = new List <int>(); for (int i = 0; i < lenNum - 1; i++) { //第i列(从前往后) for (int j = 0; j < widNum - 1; j++) { //第j行(从左往右) tempIndex.Add(i * widNum + j); tempIndex.Add(i * widNum + j + 1); tempIndex.Add((i + 1) * widNum + j + 1); tempIndex.Add((i + 1) * widNum + j + 1); tempIndex.Add((i + 1) * widNum + j); tempIndex.Add(i * widNum + j); } } outMesh.Indices = tempIndex.ToArray(); outMesh.Vertices = tempVertice.ToArray(); }
/// <summary> /// 生成柱体 /// </summary> /// <param name="topRadius">顶部半径</param> /// <param name="bottomRadius">底部半径</param> /// <param name="height">高度</param> /// <param name="sliceCount">切片数</param> /// <param name="stackCount">断层数</param> /// <param name="outMesh">输出的MeshData网格结构</param> public static void GenerateCylinder(float topRadius, float bottomRadius, float height, int sliceCount, int stackCount, out MeshData outMesh) { //[0] 侧面数据 // init meshdata size var vertexsNum = (stackCount + 1) * (sliceCount + 1); var indexNum = stackCount * sliceCount * 6; outMesh = new MeshData(vertexsNum, indexNum); // Stacks float stackHeight = height / stackCount; // radius increment float radiusStep = (topRadius - bottomRadius) / stackCount; // ring count var ringCount = stackCount + 1; int vetexNumber = 0; float dTheta = 2.0f * (float)Math.PI / sliceCount; // 层层建模 侧面顶点数据 for (int i = 0; i < ringCount; i++) { // 建模中心 y 在中心高度处,从低往高建 float y = -0.5f * height + i * stackHeight; float r = bottomRadius + i * radiusStep; // vertices // 起始顶点和最终顶点只是位置一样,但顶点其它分量不同 for (int j = 0; j <= sliceCount; j++) { float c = (float)Math.Cos(j * dTheta); float s = (float)Math.Sin(j * dTheta); MyVertex myVertex = new MyVertex(); myVertex.Position = new Vector3(r * c, y, r * s); float dr = bottomRadius - topRadius; Vector3 bitangent = new Vector3(dr * c, -height, dr * s); myVertex.Normal = Vector3.Normalize(Vector3.Cross(new Vector3(-s, 0f, c), bitangent)); outMesh.Vertices[vetexNumber] = myVertex; vetexNumber++; } } //[1] 修改索引 int number = 0; int numsPerRing = sliceCount + 1; for (int i = 0; i < stackCount; i++) { for (int j = 0; j < sliceCount; j++) { outMesh.Indices[number + 0] = i * numsPerRing + j; outMesh.Indices[number + 1] = (i + 1) * numsPerRing + j; outMesh.Indices[number + 2] = (i + 1) * numsPerRing + j + 1; outMesh.Indices[number + 3] = (i + 1) * numsPerRing + j + 1; outMesh.Indices[number + 4] = i * numsPerRing + j + 1; outMesh.Indices[number + 5] = i * numsPerRing + j; number += 6; } } //[2] 顶面数据和索引 // 顶面顶点数据 List <MyVertex> tempVertex = outMesh.Vertices.ToList(); for (int i = 0; i <= sliceCount; i++) { float x = (float)(topRadius * Math.Cos(i * dTheta)); float z = (float)(topRadius * Math.Sin(i * dTheta)); MyVertex myVertex = new MyVertex(); myVertex.Position = new Vector3(x, 0.5f * height, z); myVertex.Normal = new Vector3(0, 1, 0); tempVertex.Add(myVertex); } // 顶点中心数据 var myVertexCenter = new MyVertex(); myVertexCenter.Position = new Vector3(0, 0.5f * height, 0); myVertexCenter.Normal = new Vector3(0, 1, 0); tempVertex.Add(myVertexCenter); outMesh.Vertices = tempVertex.ToArray(); // 顶面索引 List <int> tempIndices = outMesh.Indices.ToList(); for (int i = 0; i <= sliceCount; i++) { tempIndices.Add(outMesh.Vertices.Length - 1); tempIndices.Add(outMesh.Vertices.Length - 2 - i); tempIndices.Add(outMesh.Vertices.Length - 1 - i); } outMesh.Indices = tempIndices.ToArray(); //[3] 底面数据和索引 // 底面顶点数据 tempVertex = outMesh.Vertices.ToList(); for (int i = 0; i <= sliceCount; i++) { float x = (float)(topRadius * Math.Cos(i * dTheta)); float z = (float)(topRadius * Math.Sin(i * dTheta)); MyVertex myVertex = new MyVertex(); myVertex.Position = new Vector3(x, -0.5f * height, z); myVertex.Normal = new Vector3(0, -1, 0); tempVertex.Add(myVertex); } // 顶点中心数据 myVertexCenter = new MyVertex(); myVertexCenter.Position = new Vector3(0, -0.5f * height, 0); myVertexCenter.Normal = new Vector3(0, -1, 0); tempVertex.Add(myVertexCenter); outMesh.Vertices = tempVertex.ToArray(); // 顶面索引 tempIndices = outMesh.Indices.ToList(); for (int i = 0; i <= sliceCount; i++) { tempIndices.Add(outMesh.Vertices.Length - 1); tempIndices.Add(outMesh.Vertices.Length - 2 - i); tempIndices.Add(outMesh.Vertices.Length - 1 - i); } outMesh.Indices = tempIndices.ToArray(); }
/// <summary> /// 生成球体 /// </summary> /// <param name="rad">球体半径</param> /// <param name="sliceNum">切片数</param> /// <param name="stackNum">断层数</param> /// <param name="sphereMesh">输出的MeshData网格结构</param> public static void GenerateSphere(int rad, int sliceNum, int stackNum, out MeshData sphereMesh) { //[0]侧面 sphereMesh = new MeshData(1, 1); float dTheta = 2.0f * (float)Math.PI / sliceNum; float dPhi = (float)Math.PI / stackNum; float Phi = 0; var tempVertex = sphereMesh.Vertices.ToList(); tempVertex.Clear(); //[1]底部顶点 tempVertex.Add(new MyVertex() { Position = new Vector3(0, -rad, 0), Normal = new Vector3(0, -1, 0), }); float layerColor = 0f; //[2]层层建模 侧面顶点数据 for (int i = 1; i < stackNum; i++) { // 建模中心 y 在中心高度处,从低往高建 float y = -rad * (float)Math.Cos(Phi + i * dPhi); float r = rad * (float)Math.Sin(Phi + i * dPhi); // 起始顶点和最终顶点只是位置一样,但顶点其它分量不同 for (int j = 0; j <= sliceNum; j++) { float c = (float)Math.Cos(j * dTheta); float s = (float)Math.Sin(j * dTheta); MyVertex myVertex = new MyVertex(); myVertex.Position = new Vector3(r * c, y, r * s); myVertex.Normal = new Vector3(0, 1f, 0); tempVertex.Add(myVertex); } layerColor += 0.1f; } //[3]顶部 tempVertex.Add(new MyVertex() { Position = new Vector3(0, rad, 0), Normal = new Vector3(0, 1, 0), }); sphereMesh.Vertices = tempVertex.ToArray(); //[4]索引部分 int numsPerRing = sliceNum + 1; List <int> tempIndice = sphereMesh.Indices.ToList(); tempIndice.Clear(); int number = 0; for (int i = 0; i < sliceNum; i++) { tempIndice.Add(0); tempIndice.Add(number + 1); tempIndice.Add(number + 2); number += 1; } for (int i = 0; i < stackNum - 2; i++) { for (int j = 1; j <= sliceNum; j++) { tempIndice.Add(i * numsPerRing + j); tempIndice.Add((i + 1) * numsPerRing + j); tempIndice.Add((i + 1) * numsPerRing + j + 1); tempIndice.Add((i + 1) * numsPerRing + j + 1); tempIndice.Add(i * numsPerRing + j + 1); tempIndice.Add(i * numsPerRing + j); } } number = 0; for (int i = 0; i < sliceNum; i++) { tempIndice.Add(sphereMesh.Vertices.Length - 1); tempIndice.Add(sphereMesh.Vertices.Length - 2 - number); tempIndice.Add(sphereMesh.Vertices.Length - 3 - number); number += 1; } sphereMesh.Indices = tempIndice.ToArray(); }