public void Generate() { planeMesh = new PlaneMesh(); planeMesh.Size = new Vector2(chunkSize, chunkSize); planeMesh.SubdivideDepth = Mathf.RoundToInt(chunkSize * 0.5f); planeMesh.SubdivideWidth = Mathf.RoundToInt(chunkSize * 0.5f); surfaceTool = new SurfaceTool(); meshDataTool = new MeshDataTool(); surfaceTool.CreateFrom(planeMesh, 0); arrayPlane = surfaceTool.Commit(); meshDataTool.CreateFromSurface(arrayPlane, 0); for (int i = 0; i < meshDataTool.GetVertexCount(); i++) { Vector3 vertex = meshDataTool.GetVertex(i); vertex.y = noise.GetNoise3d( vertex.x + position.x, vertex.y, vertex.z + position.z) * References.steepness; meshDataTool.SetVertex(i, vertex); avgHeight += vertex.y; } avgHeight /= meshDataTool.GetVertexCount(); for (int i = 0; i < arrayPlane.GetSurfaceCount(); i++) { arrayPlane.SurfaceRemove(i); } for (int i = 0; i < meshDataTool.GetFaceCount(); i++) { Vector3 A = meshDataTool.GetVertex(meshDataTool.GetFaceVertex(i, 0)); Vector3 B = meshDataTool.GetVertex(meshDataTool.GetFaceVertex(i, 1)); Vector3 C = meshDataTool.GetVertex(meshDataTool.GetFaceVertex(i, 2)); Vector3 face = (A + B + C) / 3 + position; Vector3 normal = meshDataTool.GetFaceNormal(i); slope += Maths.Angle(Vector3.Up, normal); } slope /= meshDataTool.GetFaceCount(); meshDataTool.CommitToSurface(arrayPlane); surfaceTool.Begin(Mesh.PrimitiveType.Triangles); surfaceTool.CreateFrom(arrayPlane, 0); surfaceTool.GenerateNormals(); meshInstance = new MeshInstance(); meshInstance.Mesh = surfaceTool.Commit(); meshInstance.SetSurfaceMaterial(0, (Material)ResourceLoader.Load("res://Assets/Shader/Terrain.material")); meshInstance.CreateTrimeshCollision(); meshInstance.CastShadow = GeometryInstance.ShadowCastingSetting.On; AddChild(meshInstance); }
// Declare member variables here. Examples: // private int a = 2; // private string b = "text"; // Called when the node enters the scene tree for the first time. public override void _Ready() { var orig = GetNode <MeshInstance>("orig"); var tights = GetNode <MeshInstance>("tights"); var result = GetNode <MeshInstance>("result"); var tmpMesh = new ArrayMesh(); var surfaceTool = new SurfaceTool(); surfaceTool.Begin(Mesh.PrimitiveType.Triangles); var tool = new MeshDataTool(); tool.CreateFromSurface((ArrayMesh)tights.Mesh, 0); var tool2 = new MeshDataTool(); tool2.CreateFromSurface((ArrayMesh)orig.Mesh, 0); List <Vector3> vertices = new List <Vector3>(); for (int v = 0; v < tool2.GetVertexCount(); v++) { vertices.Add(tool2.GetVertex(v)); } for (int v = 0; v < tool.GetVertexCount(); v++) { // surfaceTool.AddNormal(tool.GetVertexNormal(v)); // surfaceTool.AddColor(tool.GetVertexColor(v)); // surfaceTool.AddUv(tool.GetVertexUv(v)); // surfaceTool.AddUv2(tool.GetVertexUv2(v)); // surfaceTool.AddTangent(tool.GetVertexTangent(v)); var newVer = tool.GetVertex(v); var replace = vertices.OrderBy(df => newVer.DistanceTo(df)).FirstOrDefault(); if (replace != null && replace != Vector3.Zero && replace.DistanceTo(newVer) > 0.03f) { GD.Print("replace" + newVer + " by dist " + replace.DistanceTo(newVer)); surfaceTool.AddVertex(replace); } else { surfaceTool.AddVertex(newVer); } } for (int fc = 0; fc < tool.GetFaceCount(); fc++) { for (var i = 0; i <= 2; i++) { var ind = tool.GetFaceVertex(fc, i); surfaceTool.AddIndex(ind); } } surfaceTool.Commit(tmpMesh); result.Mesh = tmpMesh; }
private Godot.Collections.Array createSurfaceByBones(ArrayMesh mesh, int surface, Skin newSkin, List <UMAReciepeBindPose> origBindPoses) { var mdt = new MeshDataTool(); mdt.CreateFromSurface(mesh, surface); var st = new SurfaceTool(); st.Begin(Mesh.PrimitiveType.Triangles); var newBindPoses = new List <UMAReciepeBindPose>(); if (newSkin != null) { for (int i = 0; i < newSkin.GetBindCount(); i++) { newBindPoses.Add(new UMAReciepeBindPose { boneName = newSkin.GetBindName(i), transform = newSkin.GetBindPose(i), boneIndex = newSkin.GetBindBone(i) }); } } var boneAmount = 0; for (int i = 0; i < mdt.GetVertexCount(); i++) { var oldVer = mdt.GetVertex(i); var oldNorm = mdt.GetVertexNormal(i); var newVer = new Vector3(); var newNorm = new Vector3(); var indexes = mdt.GetVertexBones(i); // st.AddTangent(mdt.GetVertexTangent(i)); st.AddBones(mdt.GetVertexBones(i)); st.AddWeights(mdt.GetVertexWeights(i)); int boneId = 0; foreach (var weight in mdt.GetVertexWeights(i)) { if (newBindPoses.Count >= indexes[boneId] && origBindPoses.Count >= indexes[boneId]) { var restBoneNew = newBindPoses[indexes[boneId]]; var restBoneTemplate = origBindPoses[indexes[boneId]]; var dataup = restBoneNew.transform.Xform(Vector3.Up); var dataright = restBoneNew.transform.Xform(Vector3.Right); var templateup = restBoneTemplate.transform.Xform(Vector3.Up); var templateright = restBoneTemplate.transform.Xform(Vector3.Right); if (Mathf.Abs(dataup.AngleTo(templateup)) > 1 || Mathf.Abs(dataright.AngleTo(templateright)) > 1) { Transform convertMatrix = restBoneTemplate.transform.Inverse() * restBoneNew.transform; newVer += convertMatrix.Xform(oldVer) * weight; newNorm += convertMatrix.basis.Xform(oldNorm) * weight; } else { newVer += oldVer * weight; newNorm += oldNorm * weight; } } else { newVer += oldVer * weight; newNorm += oldNorm * weight; } boneId++; } st.AddUv(mdt.GetVertexUv(i)); if (mdt.GetVertexColor(i) != null) { st.AddColor(mdt.GetVertexColor(i)); } if (mdt.GetVertexUv2(i) != null) { st.AddUv2(mdt.GetVertexUv2(i)); } st.AddNormal(newNorm); st.AddVertex(newVer); boneAmount += mdt.GetVertexBones(i).Length; } //creating indexes for (int face = 0; face < mdt.GetFaceCount(); face++) { for (int faceI = 0; faceI < 3; faceI++) { var ind = mdt.GetFaceVertex(face, faceI); st.AddIndex(ind); } } st.GenerateTangents(); return(st.CommitToArrays()); }
/// <summary> /// cyberality's technique. needs some optimization for use with big meshes. /// </summary> /// <param name="sortedVerts"></param> /// <param name="colorChoices"></param> /// <param name="mdt"></param> private static void _CYBERREALITY(List <VertexInfo> sortedVerts, Color[] colorChoices, MeshDataTool mdt) { var done = new Dictionary <int, bool>(); //vertidx/isDone var bary = new Dictionary <int, Color>(); //vertidx/color var rand = new Random(0); var rand_color = new Color((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble()); var nors = new Dictionary <int, (Vector3 normal, Color color)>(); //normalIdx/normal for (var j = 0; j < mdt.GetFaceCount(); j++) { var fid = mdt.GetFaceVertex(j, 0); var nor = mdt.GetVertexNormal(fid); var coords = new List <Color>() { Colors.Red, Colors.Green, Colors.Blue }; foreach (var n in nors.Keys) { var dot = nor.Dot(nors[n].normal); if (dot == 1) { rand_color = nors[n].color; } else { rand_color = new Color((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble()); } } nors[fid] = (normal : nor, color : rand_color); for (var k = 0; k < 3; k++) { var vid = mdt.GetFaceVertex(j, k); if (bary.ContainsKey(vid)) { coords.Remove(bary[vid]); } } for (var i = 0; i < 3; i++) { var vid = mdt.GetFaceVertex(j, i); if (!done.ContainsKey(vid) || done[vid] != true) { done[vid] = true; var removal = Colors.Black; var vert_0 = mdt.GetFaceVertex(j, 0); var vert_1 = mdt.GetFaceVertex(j, 1); var vert_2 = mdt.GetFaceVertex(j, 2); var edge_a = mdt.GetVertex(vert_2).DirectionTo(mdt.GetVertex(vert_0)); var edge_b = mdt.GetVertex(vert_0).DirectionTo(mdt.GetVertex(vert_1)); var edge_c = mdt.GetVertex(vert_1).DirectionTo(mdt.GetVertex(vert_2)); if ((edge_a > edge_b) && (edge_a > edge_c)) { removal.g = 1; } else if ((edge_b > edge_c) && (edge_b > edge_a)) { removal.r = 1; } else { removal.b = 1; } if (coords.Count > 0) { var next = coords[0]; coords.RemoveAt(0); bary[vid] = next + removal; } else { var coords2 = new List <Color>() { Colors.Red, Colors.Green, Colors.Blue }; for (var m = 0; m < 3; m++) { if (m == i) { continue; } var vid2 = mdt.GetFaceVertex(j, m); if (bary.ContainsKey(vid2)) { coords2.Remove(bary[vid2]); } bary[vid] = coords2[0] + removal; //BUG? coords was checked to not have any.... maybe means coords2 coords2.RemoveAt(0); } } mdt.SetVertexColor(vid, bary[vid]); } } } }
/// <summary> /// my edited version of Cyberality's technique. /// faster performance, about as good coverage as "greedy" algo. /// </summary> /// <param name="sortedVerts"></param> /// <param name="_colorChoices"></param> /// <param name="mdt"></param> private static void _CYBERREALITY_EDIT(List <VertexInfo> sortedVerts, Color[] _colorChoices, MeshDataTool mdt) { var done = new Dictionary <int, bool>(); //vertidx/isDone var vertColorStorage = new Dictionary <int, Color>(); //vertidx/color var rand = new Random(0); var rand_color = new Color((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble()); var faceVert0MetaInfo = new Dictionary <int, (Vector3 normal, Color color)>(); //normalIdx/normal for (var faceIdx = 0; faceIdx < mdt.GetFaceCount(); faceIdx++) { var faceVert0Idx = mdt.GetFaceVertex(faceIdx, 0); var faceVert0Norm = mdt.GetVertexNormal(faceVert0Idx); var colorChoices = new List <Color>() { Colors.Red, Colors.Green, Colors.Blue }; //////JASON CLEANUP: this code block isn't actually used in the algo... ////foreach (var n in faceVert0MetaInfo.Keys) ////{ //// var dot = faceVert0Norm.Dot(faceVert0MetaInfo[n].normal); //// if (dot == 1) //// { //// rand_color = faceVert0MetaInfo[n].color; //// } //// else //// { //// rand_color = new Color((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble()); //// } ////} ////faceVert0MetaInfo[faceVert0Idx] = (normal: faceVert0Norm, color: rand_color); //loop through all verts for the face, and remove colors from our colorChoices if a vert is already using it for (var faceVertId = 0; faceVertId < 3; faceVertId++) { var vertIdx = mdt.GetFaceVertex(faceIdx, faceVertId); if (vertColorStorage.ContainsKey(vertIdx)) { colorChoices.Remove(vertColorStorage[vertIdx]); } } for (var faceVertId = 0; faceVertId < 3; faceVertId++) { var vertIdx = mdt.GetFaceVertex(faceIdx, faceVertId); if (!done.ContainsKey(vertIdx) || done[vertIdx] != true) { done[vertIdx] = true; var removal = Colors.Black; var vert_0 = mdt.GetFaceVertex(faceIdx, 0); var vert_1 = mdt.GetFaceVertex(faceIdx, 1); var vert_2 = mdt.GetFaceVertex(faceIdx, 2); var edge_a = mdt.GetVertex(vert_2).DirectionTo(mdt.GetVertex(vert_0)); var edge_b = mdt.GetVertex(vert_0).DirectionTo(mdt.GetVertex(vert_1)); var edge_c = mdt.GetVertex(vert_1).DirectionTo(mdt.GetVertex(vert_2)); if ((edge_a > edge_b) && (edge_a > edge_c)) { removal.g = 1; } else if ((edge_b > edge_c) && (edge_b > edge_a)) { removal.r = 1; } else { removal.b = 1; } if (colorChoices.Count > 0) { var next = colorChoices[0]; colorChoices.RemoveAt(0); vertColorStorage[vertIdx] = next + removal; } //JASON CLEANUP: this else will never trigger, as there are only 3 verticies else { GD.Print("in else!"); var coords2 = new List <Color>() { Colors.Red, Colors.Green, Colors.Blue }; for (var m = 0; m < 3; m++) { if (m == faceVertId) { continue; } var vid2 = mdt.GetFaceVertex(faceIdx, m); if (vertColorStorage.ContainsKey(vid2)) { coords2.Remove(vertColorStorage[vid2]); } vertColorStorage[vertIdx] = coords2[0] + removal; //BUG? coords was checked to not have any.... maybe means coords2 coords2.RemoveAt(0); } } mdt.SetVertexColor(vertIdx, vertColorStorage[vertIdx]); } } } }
/// <summary> /// /// </summary> /// <param name="sortedVerts"></param> /// <param name="colorChoices"></param> /// <param name="mdt"></param> private static void _WELSH_POWELL_ADJUSTED(List <VertexInfo> sortedVerts, Color[] colorChoices, MeshDataTool mdt) { for (var h = 0; h < colorChoices.Length; h++) { var color = colorChoices[h]; //enumerate in reverse so we inspect our verticies with highest degree first (most edges) //and also lets us remove from the list directly for (int i = sortedVerts.Count - 1; i >= 0; i--) { //if we remove too many, reset our index. this means we might invoke this loop on an element more than once. //but that's ok as it doesn't have negative consiquences. if (i >= sortedVerts.Count) { i = sortedVerts.Count - 1; } var vertInfo = sortedVerts[i]; if (vertInfo.TrySetAvailableColor(color)) { sortedVerts.RemoveAt(i); //preemptively try to set adjacent and adjadj with related colors foreach (var adj0Vert in vertInfo.GetAdjacentVertInfo()) { //JASON OPTIMIZATION: reduces non-colored by aprox 8% on sibnek 100k vert mesh. foreach (var adj1Vert in adj0Vert.GetAdjacentVertInfo()) { if (adj1Vert.adjacentVerticies.Length > vertInfo.adjacentVerticies.Length * 0.75) { adj1Vert.TrySetAvailableColor(color); } } } } } } //any remaining verts are uncolored! bad. GD.Print($"Done building mesh. Verticies uncolored count={sortedVerts.Count} / {mdt.GetVertexCount()}"); //loop through all faces, finding the vertex for the longest edge, //and encode that into green channel = 0.1; //may be used by the shader to remove interrior edges var faceCount = mdt.GetFaceCount(); for (var faceIdx = 0; faceIdx < faceCount; faceIdx++) { var vertIdx0 = mdt.GetFaceVertex(faceIdx, 0); var vertIdx1 = mdt.GetFaceVertex(faceIdx, 1); var vertIdx2 = mdt.GetFaceVertex(faceIdx, 2); var vert0 = mdt.GetVertex(vertIdx0); var vert1 = mdt.GetVertex(vertIdx1); var vert2 = mdt.GetVertex(vertIdx2); var edgeLen1 = vert0.DistanceTo(vert1); var edgeLen2 = vert0.DistanceTo(vert2); var edgeLen3 = vert1.DistanceTo(vert2); int longestEdgeVertIdx = -1; if (edgeLen1 > edgeLen2 && edgeLen1 > edgeLen3) { longestEdgeVertIdx = vertIdx2; } if (edgeLen2 > edgeLen1 && edgeLen2 > edgeLen3) { longestEdgeVertIdx = vertIdx1; } if (edgeLen3 > edgeLen1 && edgeLen3 > edgeLen2) { longestEdgeVertIdx = vertIdx0; } if (longestEdgeVertIdx != -1) { var curCol = mdt.GetVertexColor(longestEdgeVertIdx); //encode that this vertext has longest edge (used in shader code) curCol.g += 0.1f; mdt.SetVertexColor(longestEdgeVertIdx, curCol); } } ////for any remaining verticies color alpha //var alphaBlack = new Color(0, 0, 0, 0); //for (int i = sortedVerts.Count - 1; i >= 0; i--) //{ // var vertInfo = sortedVerts[i]; // mdt.SetVertexColor(vertInfo.vertIdx, alphaBlack); // //vertInfo.TrySetAvailableColor(Colors.White, true); //} }