private void Initialize() { _meshInstance = GetNode <MeshInstance>("Mesh"); PlaneMesh initialMesh = (PlaneMesh)_meshInstance.Mesh; _resX = initialMesh.SubdivideWidth + 1; _resZ = initialMesh.SubdivideDepth + 1; _noise = new OpenSimplexNoise(); UpdateNoiseSettings(); _surfaceTool = new SurfaceTool(); _meshDataTool = new MeshDataTool(); Control HUD = GetNode <Control>("../HUD"); HUD.Connect("UpdateSeed", this, nameof(_On_Seed_Updated)); HUD.Connect("UpdateOctaves", this, nameof(_On_Octaves_Updated)); HUD.Connect("UpdateAmplitude", this, nameof(_On_Amplitude_Updated)); HUD.Connect("UpdatePeriod", this, nameof(_On_Period_Updated)); HUD.Connect("UpdateLacunarity", this, nameof(_On_Lacunarity_Updated)); HUD.Connect("UpdatePersistence", this, nameof(_On_Persistence_Updated)); _initialized = true; }
/** * Create surface for overlay */ public ArrayMesh createSurfaceOverlay(ArrayMesh mesh, string slotName, string urlPath, string overlayName, List <UMAReciepeBindPose> origBindPoses) { var file = ResourceLoader.Load <PackedScene>(urlPath); var instance = file.Instance(); var meshes = new List <MeshInstance>(); if (instance is Spatial) { foreach (var child in (instance as Spatial).GetChildren()) { if (child is MeshInstance) { meshes.Add(child as MeshInstance); } } } if (instance is MeshInstance) { meshes.Add(instance as MeshInstance); } var mdt = new MeshDataTool(); var idx = mesh.SurfaceFindByName(slotName); mdt.CreateFromSurface(mesh, idx); int totalSurfaces = 0; foreach (var mi in meshes) { var newMesh = (mi as MeshInstance).Mesh; var newSkin = (mi as MeshInstance).Skin; for (int surface = 0; surface < newMesh.GetSurfaceCount(); surface++) { mesh.AddSurfaceFromArrays(Mesh.PrimitiveType.Triangles, createSurfaceByBones(newMesh as ArrayMesh, surface, newSkin, origBindPoses)); var lastId = mesh.GetSurfaceCount() - 1; var mat = newMesh.SurfaceGetMaterial(surface); mat.ResourceLocalToScene = true; if (mat is SpatialMaterial) { (mat as SpatialMaterial).ParamsGrow = true; (mat as SpatialMaterial).ParamsGrowAmount = 0.005f; } mesh.SurfaceSetMaterial(lastId, mat); mesh.SurfaceSetName(lastId, (totalSurfaces == 0) ? overlayName : overlayName + "/" + totalSurfaces); totalSurfaces++; } changes++; } return(mesh); }
public static ArrayMesh AddNoiseToMesh(PlaneMesh plane, float[,] noiseMap, int chunkSize, int heightMultiplier, Curve heightCurve) { SurfaceTool st = new SurfaceTool(); st.CreateFrom(plane, 0); ArrayMesh mesh = new ArrayMesh(); MeshDataTool dt = new MeshDataTool(); mesh = st.Commit(); dt.CreateFromSurface(mesh, 0); for (int y = 0; y < chunkSize; y++) { for (int x = 0; x < chunkSize; x++) { int z = y; int vertexIndex = z * chunkSize + x; Vector3 vertex = dt.GetVertex(vertexIndex); vertex.y = heightCurve.Interpolate(noiseMap[chunkSize - x - 1, chunkSize - z - 1]) * heightMultiplier; dt.SetVertex(vertexIndex, vertex); } } for (int surface = 0; surface < mesh.GetSurfaceCount(); surface++) { mesh.SurfaceRemove(surface); } dt.CommitToSurface(mesh); st.Begin(Mesh.PrimitiveType.Triangles); st.CreateFrom(mesh, 0); st.Index(); st.GenerateNormals(); return(st.Commit()); }
/// <summary> /// 4th attempt: set color by most linked, not by color /// </summary> /// <param name="mdt"></param> public static void _SetVertexColorToBarycentric(MeshDataTool mdt) { //store info about our verticies into an array var vertStorage = new VertexInfo[mdt.GetVertexCount()]; for (var vertIdx = 0; vertIdx < vertStorage.Length; vertIdx++) { vertStorage[vertIdx] = new VertexInfo(vertIdx, mdt, vertStorage); //set vert color to alphaBlack mdt.SetVertexColor(vertIdx, Colors.Transparent); } //sort verticies by degree (number of edges). defaults to highest first var sortedVerts = new List <VertexInfo>(vertStorage); sortedVerts.Sort(); //color channels used for verticies. 3 is ideal, but aprox 10% of verts wont be colored. var colorChoices = new Color[] { //encode 5 channels as 20% red each. new Color(0.2f, 0, 0, 0), new Color(0.4f, 0, 0, 0), new Color(0.6f, 0, 0, 0), new Color(0.8f, 0, 0, 0), new Color(1f, 0, 0, 0) }; ////////////// various algorithm choices. best is _WELSH_POWELL_ADJUSTED //_GREEDY_FACE(sortedVerts, colorChoices, mdt); //_GREEDY_BASIC(sortedVerts, colorChoices, mdt); //_CYBERREALITY(sortedVerts, colorChoices, mdt); //_CYBERREALITY_EDIT(sortedVerts, colorChoices, mdt); _WELSH_POWELL_ADJUSTED(sortedVerts, colorChoices, mdt); }
public VertexInfo(int idx, MeshDataTool mdt, VertexInfo[] storage) { this.storage = storage; this.vertIdx = idx; this.mdt = mdt; edges = mdt.GetVertexEdges(idx); faces = mdt.GetVertexFaces(idx); this.pos = mdt.GetVertex(idx); adjacentVerticies = new int[edges.Length]; for (var i = 0; i < edges.Length; i++) { var edgeIdx = edges[i]; var edgeVert0 = mdt.GetEdgeVertex(edgeIdx, 0); var edgeVert1 = mdt.GetEdgeVertex(edgeIdx, 1); var adjacent = edgeVert0 != idx ? edgeVert0 : edgeVert1; adjacentVerticies[i] = adjacent; } //better heuristic for sorting (vert with most adjcent faces) foreach (var faceIdx in faces) { //adjadj++; for (var i = 0; i < 3; i++) { var faceVertIdx = mdt.GetFaceVertex(faceIdx, i); adjadj += mdt.GetVertexFaces(faceVertIdx).Length; } } }
public override UnifiedObject Mirror() { StaticObject clone = (StaticObject)this.Clone(); ArrayMesh originalMesh = (ArrayMesh)this.m_meshInstance.Mesh; int originalSurfaceCount = originalMesh.GetSurfaceCount(); ArrayMesh newMesh = new ArrayMesh(); for (int i = 0; i < originalSurfaceCount; i++) { MeshDataTool mdt = new MeshDataTool(); mdt.CreateFromSurface(originalMesh, i); for (int j = 0; j < mdt.GetVertexCount(); j++) { Vector3 vert = mdt.GetVertex(j); vert.x *= -1; mdt.SetVertex(j, vert); } mdt.CommitToSurface(newMesh); } clone.ObjectMeshInstance.Mesh = newMesh; return(clone); }
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); }
private void Deform() { var sn = new OpenSimplexNoise(); sn.Period = Period; sn.Octaves = Octaves; sn.Seed = Seed; sn.Persistence = Persistence; sn.Lacunarity = Lacunarity; var mesh = sphere.Mesh; var st = new SurfaceTool(); st.CreateFrom(mesh, 0); var array = st.Commit(); var dt = new MeshDataTool(); dt.CreateFromSurface(array, 0); var count = dt.GetVertexCount(); var origin = Vector3.Zero; for (int i = 0; i < count; i++) { var vertex = dt.GetVertex(i); var n = -vertex.DirectionTo(origin); var noise = sn.GetNoise3d(vertex.x, vertex.y, vertex.z); noise = Mathf.Clamp(noise, -1f, 1f); vertex += n * noise * MoveFactor; dt.SetVertex(i, vertex); } var surfCount = array.GetSurfaceCount(); for (int i = 0; i < surfCount; i++) { array.SurfaceRemove(i); } dt.CommitToSurface(array); st.Begin(Mesh.PrimitiveType.Triangles); st.CreateFrom(array, 0); st.GenerateNormals(); sphere.Mesh = st.Commit(); UpdateMaterial(); }
/// <summary> /// 3rd attempt: after researching a bit I realized this is a "graph coloring" problem: https://en.wikipedia.org/wiki/Graph_coloring /// nice overview of some here: https://github.com/Ajaypal91/Graph_Coloring_Algorithms_Implementation /// here we implement welsh-powell algorithm: https://www.youtube.com/watch?v=CQIW2mLfG04 /// </summary> /// <param name="mdt"></param> private static void _SetVertexColorToBarycentric_WP(MeshDataTool mdt) { //store info about our verticies into an array var vertStorage = new VertexInfo[mdt.GetVertexCount()]; for (var vertIdx = 0; vertIdx < vertStorage.Length; vertIdx++) { vertStorage[vertIdx] = new VertexInfo(vertIdx, mdt, vertStorage); //set vert color to black mdt.SetVertexColor(vertIdx, Colors.Transparent); } //sort verticies by degree (number of edges). defaults to highest first var sortedVerts = new List <VertexInfo>(vertStorage); sortedVerts.Sort(); //verts.CopyTo(sortedVerts,0); //Array.Sort(sortedVerts); var colorChoices = new Color[] { Colors.Red, Colors.Green, Colors.Blue }; foreach (var color in colorChoices) { //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--) { var vertInfo = sortedVerts[i]; if (vertInfo.TrySetAvailableColor(color)) { sortedVerts.RemoveAt(i); } } } //any remaining verts are uncolored! bad. GD.Print($"Done building mesh. Verticies uncolored count={sortedVerts.Count} / {mdt.GetVertexCount()}"); //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); } }
public void RebuildOutputMesh() { GD.Print("REBUILDING COLOR MESH"); var inputNode = FindNode("Input") as MeshInstance; var outputNode = FindNode("Output") as MeshInstance; var mesh = inputNode.Mesh as ArrayMesh; if (mesh == null) { GD.Print("no mesh found on input node. aborting"); return; } var surfaceCount = mesh.GetSurfaceCount(); var surfaceQueue = new Queue <MeshDataTool>(); for (var i = 0; i < surfaceCount; i++) { var mdt = new MeshDataTool(); mdt.CreateFromSurface(mesh, 0); BarycentricProcessor._SetVertexColorToBarycentric(mdt); mesh.SurfaceRemove(0); surfaceQueue.Enqueue(mdt); } //replace our mesh with modified version while (surfaceQueue.Count > 0) { var mdt = surfaceQueue.Dequeue(); mdt.CommitToSurface(mesh); mdt.Dispose(); } outputNode.Mesh = mesh; }
private static void _SetVertexColorToBarycentric_old(MeshDataTool mdt) { //try looping verticies { // var marked = new System.Collections.Generic.Dictionary<string, Color>(); // var markFailCount = 0; // var markIndex = 0; // float vertexCount = mdt.GetVertexCount(); // for (var i = 0; i < vertexCount; i++) // { // var vertex = mdt.GetVertex(i); // var vertId = vertex.ToString("F2"); // // if (marked.TryGetValue(vertId, out var markedColor)) // // { // // GD.Print($"MARK FAIL! {vertId}"); // // mdt.SetVertexColor(i, markedColor); // // markFailCount++; // // continue; // // } // var channel = markIndex % 3; // var color = new Color(0, 0, 0, 1); // switch (channel) // { // case 0: // color.r = 1; // break; // case 1: // color.g = 1; // break; // case 2: // color.b = 1; // break; // case 3: // color.r = 1; // color.g = 1; // break; // case 4: // color.r = 1; // color.b = 1; // break; // case 5: // color.b = 1; // color.g = 1; // break; // case 6: // color.r = 1; // color.g = 1; // color.b = 1; // break; // case 7: // color.r = 0; // color.g = 0; // color.b = 0; // break; // } // color = new Color(0, 0, 0, 1); // //marked.Add(vertId, color); // markIndex++; // mdt.SetVertexColor(i, color); // } } //private helper, gets the name of a color (assumes R,G,B, or Black) string _getColorName(Color color) { switch (color) { case Color c when c == Colors.Red: return("Red"); break; case Color c when c == Colors.Green: return("Green"); break; case Color c when c == Colors.Blue: return("Blue"); break; case Color c when c == Colors.Black: return("Black"); break; default: throw new Exception($"getColorName, unknown color={color}. This helper function supports only Red, Green,Blue, or Black."); } } { } //loop all faces, assigning colors to each of it's 3 verticies. { //var faceCount = mdt.GetFaceCount(); //var faceColorChoices = new List<string>(); //var vertClusterColors = new Dictionary<string, string>(); //key = vertex.toString(), value = color name ////preprocess verticies of the mesh. ////reset vertex color to black. we do this in case the model already uses R,G, or B for vertex color, which can mess up our color assigning algorithm below (we check the color of the vertex to see if it's been set) //var vertexCount = mdt.GetVertexCount(); //for (var vertIdx = 0; vertIdx < vertexCount; vertIdx++) //{ // mdt.SetVertexColor(vertIdx, Colors.Black); //} ////first loop through all faces, assign red to the vertex with the most linked faces, black to others. ////this is to reduce chance of the green or blue colors "running out" due to other verticies being shared by faces. //for (var faceIdx = 0; faceIdx < faceCount; faceIdx++) //{ // //break; // //the colors this faces' verticies will use. // faceColorChoices.Clear(); // faceColorChoices.Add("Green"); // faceColorChoices.Add("Blue"); // faceColorChoices.Add("Red"); // //sort verts by number of linked faces, and remove any used colors // var mostFacedVertFaces = 0; // var mostFacedVertIdx = -1; // //var sortedButUncoloredVerts = new SortedS<int, int>(); //key = faceCount, value = vertIdx // // { int faces; int vertIdx } tp;// = { faces = 1, vertIdx = -1 }; // for (var faceVert = 0; faceVert < 3; faceVert++) // { // var vertIdx = mdt.GetFaceVertex(faceIdx, faceVert); // var faces = mdt.GetVertexFaces(vertIdx); // var vertColor = mdt.GetVertexColor(vertIdx); // var vertColorName = _getColorName(vertColor); // switch (vertColorName) // { // case "Black": // //no color assigned to the vertex // if (faces.Length > mostFacedVertFaces) // { // mostFacedVertFaces = faces.Length; // mostFacedVertIdx = vertIdx; // } // //sortedButUncoloredVerts.Add(faces.Length, vertIdx); //only add the vert if it's uncolored // break; // default: // //remove the vertex's color from our choices (so the next loop through the faces's verticies wont pick it) // var result = faceColorChoices.Remove(vertColorName); // if (!result) // { // //color used twice in the vertex! bad // GD.Print($"failed, vert color used twice!!!!! color={vertColorName} vertIdx={vertIdx}"); // //throw new Exception($"failed to set the faces vertex color properly. color is used twice on the face."); // } // break; // } // } // //assign color to our top uncolored vert // { // //var vertIdx = sortedButUncoloredVerts. // if (mostFacedVertFaces > 2) // { // var vert = mdt.GetVertex(mostFacedVertIdx); // var vertName = vert.ToString("F5"); // var colorChoice = faceColorChoices[0]; // faceColorChoices.RemoveAt(0); // mdt.SetVertexColor(mostFacedVertIdx, Color.ColorN(colorChoice)); // if (!vertClusterColors.ContainsKey(vertName)) // { // vertClusterColors[vertName] = colorChoice; // } // } // } // // var mostFacedVertFaces = 0; // //var mostFacedVert = -1; // //var isRedAssigned = false; // //var isBlueAssigned = false; // //for (var faceVert = 0; faceVert < 3; faceVert++) // //{ // // var vertIdx = mdt.GetFaceVertex(faceIdx, faceVert); // // var vertColor = mdt.GetVertexColor(vertIdx); // // var vertColorName = _getColorName(vertColor); // // switch (vertColorName) // // { // // case "Red": // // isRedAssigned = true; // // break; // // case "Blue": // // isBlueAssigned = true; // // break; // // } // // var faces = mdt.GetVertexFaces(vertIdx); // // if (mostFacedVertFaces >= faces.Length) // // { // // continue; // // } // // mostFacedVertFaces = faces.Length; // // mostFacedVert = faceVert; // //} //} //for (var faceIdx = 0; faceIdx < faceCount; faceIdx++) //{ // //the colors this faces' verticies will use. // faceColorChoices.Clear(); // faceColorChoices.Add("Red"); // faceColorChoices.Add("Green"); // faceColorChoices.Add("Blue"); // //loop through all the faces' verticies and removed any colors already used. // for (var faceVert = 0; faceVert < 3; faceVert++) // { // var vertIdx = mdt.GetFaceVertex(faceIdx, faceVert); // //var vert = mdt.GetVertex(vertIdx); // //var vertName = vert.ToString("F5"); // var vertColor = mdt.GetVertexColor(vertIdx); // var vertColorName = _getColorName(vertColor); // switch (vertColorName) // { // case "Black": // //no color assigned to the vertex // break; // default: // //remove the vertex's color from our choices (so the next loop through the faces's verticies wont pick it) // var result = faceColorChoices.Remove(vertColorName); // if (!result) // { // //color used twice in the vertex! bad // GD.Print($"failed, vert color used twice!!!!! color={vertColorName} vertIdx={vertIdx}"); // //throw new Exception($"failed to set the faces vertex color properly. color is used twice on the face."); // } // break; // } // } // //loop through all the faces' verticies and assign color used by the vertCluster // for (var faceVert = 0; faceVert < 3; faceVert++) // { // var vertIdx = mdt.GetFaceVertex(faceIdx, faceVert); // var vert = mdt.GetVertex(vertIdx); // var vertName = vert.ToString("F5"); // var vertColor = mdt.GetVertexColor(vertIdx); // var vertColorName = _getColorName(vertColor); // switch (vertColorName) // { // case "Black": // //no color assigned to the vertex // //so check if another another vertex with same location has this color, so use it too. // if (vertClusterColors.TryGetValue(vertName, out var _tempVertCol)) // { // if (faceColorChoices.Remove(_tempVertCol)) // { // mdt.SetVertexColor(vertIdx, Color.ColorN(_tempVertCol)); // } // } // break; // default: // //vert already colored // break; // } // } // //this pass, assign all black verticies our remaining colors // for (var faceVert = 0; faceVert < 3; faceVert++) // { // var vertIdx = mdt.GetFaceVertex(faceIdx, faceVert); // var vert = mdt.GetVertex(vertIdx); // var vertName = vert.ToString("F5"); // var vertColor = mdt.GetVertexColor(vertIdx); // var vertColorName = _getColorName(vertColor); // switch (vertColorName) // { // case "Black": // //assign the vertex a color from our remaining color options for this vertex, // //but we prefer using a color that other verticies at the same location are already using. // string colorChoice = null; // if (vertClusterColors.TryGetValue(vertName, out var _tempVertCol)) // { // if (faceColorChoices.Remove(_tempVertCol)) // { // //another vertex with same location has this color, so use it too. // colorChoice = _tempVertCol; // } // else // { // //color already in use by another vertex, so do our "normal" color pick // } // } // if (colorChoice is null) // { // // // colorChoice = faceColorChoices[0]; // faceColorChoices.RemoveAt(0); // } // mdt.SetVertexColor(vertIdx, Color.ColorN(colorChoice)); // if (!vertClusterColors.ContainsKey(vertName)) // { // vertClusterColors[vertName] = colorChoice; // } // break; // default: // //vertex already has a color assigned // break; // } // //switch (faceVert) // //{ // // case 0: // // vertColor.r = 1; // // break; // // case 1: // // vertColor.g = 1; // // break; // // case 2: // // vertColor.b = 1; // // break; // //} // //mdt.SetVertexColor(vertIdx, vertColor); // //if (vertColors.TryGetValue(vertName, out var _tempVertCol)) // //{ // // mdt.getvertexc // // //if this vertex already has a color assigned to it // // vertColor = _tempVertCol; // //} // //else // //{ // // switch (priorVertColor) // // { // // case Color c when c == Colors.Black || c == Colors.Blue: // // vertColor = Colors.Red; // // break; // // case Color c when c == Colors.Red: // // vertColor = Colors.Green; // // break; // // case Color c when c == Colors.Green: // // vertColor = Colors.Blue; // // break; // // } // // mdt.SetVertexColor(vert0Idx, Colors.Red); // // lastVertCol = Colors.Red; // //} // ////verify that color isn't already used for a vert of this face. // //switch (vertColor) // //{ // // case Color c when c == Colors.Red: // // if (redUsed) // // { // // throw new Exception("red already used"); // // } // // redUsed = true; // // break; // // case Color c when c == Colors.Green: // // if (greenUsed) // // { // // throw new Exception("green already used"); // // } // // greenUsed = true; // // break; // // case Color c when c == Colors.Blue: // // if (blueUsed) // // { // // throw new Exception("blue already used"); // // } // // blueUsed = true; // // break; // //} // } //} } }
/// <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); //} }
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()); }
// 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; }
/// <summary> /// experimental greedy mesh technique. /// </summary> /// <param name="sortedVerts"></param> /// <param name="colorChoices"></param> /// <param name="mdt"></param> private static void _GREEDY_FACE(List <VertexInfo> sortedVerts, Color[] colorChoices, MeshDataTool mdt) { List <VertexInfo> noColor = new List <VertexInfo>(); for (int i = sortedVerts.Count - 1; i >= 0; i--) { var removed = false; var vertInfo = sortedVerts[i]; for (var h = 0; h < colorChoices.Length; h++) { var color = colorChoices[h]; if (vertInfo.TrySetAvailableColor(color)) { sortedVerts.RemoveAt(i); removed = true; foreach (var adj0Vert in vertInfo.GetAdjacentVertInfo()) { if (h < colorChoices.Length - 2 && adj0Vert.adjacentVerticies.Length >= 3 //vertInfo.adjacentVerticies.Length ) { if (adj0Vert.TrySetAvailableColor(colorChoices[h + 1])) { ; } } if (h < colorChoices.Length - 3 && adj0Vert.adjacentVerticies.Length >= 3 //vertInfo.adjacentVerticies.Length ) { adj0Vert.TrySetAvailableColor(colorChoices[h + 2]); } foreach (var adj1Vert in adj0Vert.GetAdjacentVertInfo()) { if (adj1Vert.adjacentVerticies.Length >= 3) //vertInfo.adjacentVerticies.Length) //if (adj1Vert.adjacentVerticies.Length >= vertInfo.adjacentVerticies.Length) { adj1Vert.TrySetAvailableColor(color); } } } break; } } if (removed == false) { noColor.Add(vertInfo); //var alphaBlack = new Color(0, 0, 0, 0); vertInfo.TrySetAvailableColor(Colors.White, true); sortedVerts.RemoveAt(i); } } GD.Print($"_GREEDY_FACE uncolored count={noColor.Count} / {mdt.GetVertexCount()}"); }
/// <summary> /// experimental greedy mesh technique. /// </summary> /// <param name="sortedVerts"></param> /// <param name="colorChoices"></param> /// <param name="mdt"></param> private static void _GREEDY_BASIC(List <VertexInfo> sortedVerts, Color[] colorChoices, MeshDataTool mdt) { bool TrySetAdjAdj(VertexInfo _current, Color c, List <VertexInfo> _store) { if (_store.Contains(_current) == false) { return(true); } if (_current.TrySetAvailableColor(c)) { _store.Remove(_current); foreach (var adj0Vert in _current.GetAdjacentVertInfo()) { foreach (var adj1Vert in adj0Vert.GetAdjacentVertInfo()) { TrySetAdjAdj(adj1Vert, c, _store); } } return(true); } return(false); } List <VertexInfo> problems = new List <VertexInfo>(); while (sortedVerts.Count > 0) { var vertInfo = sortedVerts[sortedVerts.Count - 1]; //sortedVerts.RemoveAt(sortedVerts.Count - 1); for (var h = 0; h < colorChoices.Length; h++) { var color = colorChoices[h]; //TrySetAdjAdj(vertInfo, color, sortedVerts); if (vertInfo.TrySetAvailableColor(color)) { sortedVerts.Remove(vertInfo); //preemptively try to set adjacent and adjadj with related colors foreach (var adj0Vert in vertInfo.GetAdjacentVertInfo()) { if (h < colorChoices.Length - 2 // && adj0Vert.adjacentVerticies.Length >= vertInfo.adjacentVerticies.Length ) { if (adj0Vert.TrySetAvailableColor(colorChoices[h + 1])) { ; } } if (h < colorChoices.Length - 3 //&& adj0Vert.adjacentVerticies.Length >= vertInfo.adjacentVerticies.Length ) { adj0Vert.TrySetAvailableColor(colorChoices[h + 2]); } foreach (var adj1Vert in adj0Vert.GetAdjacentVertInfo()) { //if (adj1Vert.adjacentVerticies.Length >= vertInfo.adjacentVerticies.Length) { adj1Vert.TrySetAvailableColor(color); } } } break; } } if (sortedVerts.Contains(vertInfo)) { problems.Add(vertInfo); vertInfo.TrySetAvailableColor(Colors.White, true); sortedVerts.Remove(vertInfo); } } GD.Print($"_GREEDY_BASIC uncolored count={problems.Count} / {mdt.GetVertexCount()}"); }
public override void _Ready() { var mesh = new PlaneMesh(); mesh.Size = new Vector2(size, size); mesh.SubdivideDepth = 3; mesh.SubdivideWidth = (int)position.x == 0 ? (int)size : 3; var surface_tool = new SurfaceTool(); surface_tool.CreateFrom(mesh, 0); var mesh_tool = new MeshDataTool(); mesh_tool.CreateFromSurface(surface_tool.Commit(), 0); var biome = GetBiome(/*hydro_noise.GetNoise2dv(position / size), */ heat_noise.GetNoise2d(position.x / size / 10.0f, position.y)); for (int i = 0; i < mesh_tool.GetVertexCount(); ++i) { var vertex = mesh_tool.GetVertex(i); var vertex_global_pos = position + new Vector2(vertex.x, vertex.z); var height_noise_val = height_noise.GetNoise2dv(vertex_global_pos); vertex.y = height_noise_val * 20; var color_factor = (height_noise_val + 1) / 2.0f; var hydro_val = (int)Math.Round(hydro_noise.GetNoise2dv(vertex_global_pos)); if ((int)vertex.x == 0 && (int)position.x == 0) { mesh_tool.SetVertexColor(i, new Color(color_factor, color_factor / 2, 0.0f)); } else if (hydro_val == -1) { mesh_tool.SetVertexColor(i, biome.dry_color * color_factor); } else if (hydro_val == 1) { mesh_tool.SetVertexColor(i, biome.humid_color * color_factor); } else { mesh_tool.SetVertexColor(i, biome.ground_color * color_factor); } mesh_tool.SetVertex(i, vertex); } /*if (base_tree_mesh == null && ResourceLoader.Exists("res://assets/tree.obj")) * { * base_tree_mesh = ResourceLoader.Load<Mesh>("res://assets/tree.obj"); * } * if (base_tree_material == null && ResourceLoader.Exists("res://assets/tree.tres")) * { * Console.WriteLine("OK"); * base_tree_material = ResourceLoader.Load<SpatialMaterial>("res://assets/tree.tres"); * } * * MultiMesh trees = new MultiMesh(); * trees.Mesh = base_tree_mesh; * trees.TransformFormat = MultiMesh.TransformFormatEnum.Transform3d; * * if ((int)position.x == 0) * { * var points1 = Utility.UniformPoissonDiskSampler.SampleRectangle(-new Vector2(size, size) / 2, new Vector2(-5, size / 2.0f), biome.tree_spacing); * var points2 = Utility.UniformPoissonDiskSampler.SampleRectangle(new Vector2(5, 0), new Vector2(size, size) / 2, biome.tree_spacing); * trees.InstanceCount = points1.Count + points2.Count; * * int i = 0; * foreach (var p in points1) * { * trees.SetInstanceTransform(i, Transform.Identity.Scaled(new Vector3(1, biome.tree_size, 1)).Translated(new Vector3(p.x, height_noise.GetNoise2dv(position + p) * 20, p.y))); ++i; * } * * foreach (var p in points2) * { * trees.SetInstanceTransform(i, Transform.Identity.Scaled(new Vector3(1, biome.tree_size, 1)).Translated(new Vector3(p.x, height_noise.GetNoise2dv(position + p) * 20, p.y))); ++i; * } * } * else * { * var points = Utility.UniformPoissonDiskSampler.SampleRectangle(-new Vector2(size, size) / 2, new Vector2(size, size) / 2, biome.tree_spacing); * trees.InstanceCount = points.Count; * int i = 0; * foreach (var p in points) * { * trees.SetInstanceTransform(i, Transform.Identity.Scaled(new Vector3(1, biome.tree_size, 1)).Translated(new Vector3(p.x, height_noise.GetNoise2dv(position + p) * 20, p.y))); ++i; * } * } * * MultiMeshInstance child = new MultiMeshInstance(); * child.Multimesh = trees; * child.MaterialOverride = base_tree_material; * AddChild(child);*/ var array = new ArrayMesh(); mesh_tool.CommitToSurface(array); Mesh = array; if (base_shader == null && ResourceLoader.Exists("res://assets/chunk_shader.tres")) { base_shader = ResourceLoader.Load <ShaderMaterial>("res://assets/chunk_shader.tres"); } var shader = base_shader; MaterialOverride = shader; }