public void Render() { GameObject ground = new GameObject("_Ground"); ground.transform.parent = MapRenderer.mapParent.transform; for (int i = 0; i < meshes.Length; i++) { Mesh mesh = meshes[i]; GameObject gameObject = new GameObject("Ground[" + i + "]"); gameObject.transform.parent = ground.transform; var mf = gameObject.AddComponent <MeshFilter>(); mf.mesh = mesh; var mr = gameObject.AddComponent <MeshRenderer>(); mr.material = material; mr.material.mainTexture = atlas; mr.material.SetTexture("_Tintmap", tintmap); mr.material.SetTexture("_Lightmap", lightmap); Vector3 scale = gameObject.transform.localScale; scale.Set(1f, -1f, 1f); gameObject.transform.localScale = scale; //smooth out mesh NormalSolver.RecalculateNormals(mf.mesh, 60); //avoid z fighting between ground and models gameObject.transform.Translate(0, -0.002f, 0); gameObject.AddComponent <MeshCollider>(); gameObject.layer = LayerMask.NameToLayer("Ground"); } }
public override MeshData GenerateMeshData() { var vertices = new List <Vector3>(); var triangles = new List <int>(); float[,,] voxels = CalculateDensities(); for (int x = 0; x < chunkSize - 1; x++) { for (int y = 0; y < chunkSize - 1; y++) { for (int z = 0; z < chunkSize - 1; z++) { float[] cube = CreateCube(x, y, z, voxels); MarchCube(new Vector3(x, y, z), cube, vertices, triangles); } } } List <Vector3> normals = NormalSolver.RecalculateNormals(triangles, vertices, NormalSmoothing); return(new MeshData { vertices = vertices, triangles = triangles, normals = normals }); }
/// <summary> /// Will reset all meshes stored in the mesh dictionaries to default positons /// </summary> internal void ResetInflation() { //Resets all mesh inflations var keyList = new List <string>(originalVertices.Keys); //For every active meshRenderer key we have created foreach (var renderKey in keyList) { var smr = PregnancyPlusHelper.GetMeshRenderer(ChaControl, renderKey); //Normally triggered when user changes clothes, the old clothes render wont be found if (smr == null) { if (PregnancyPlusPlugin.DebugLog.Value) { PregnancyPlusPlugin.Logger.LogWarning($" ResetInflation > smr was not found {renderKey}"); } continue; } //Create an instance of sharedMesh so we don't modify the mesh shared between characters, that was a fun issue Mesh meshCopy = (Mesh)UnityEngine.Object.Instantiate(smr.sharedMesh); smr.sharedMesh = meshCopy; var sharedMesh = smr.sharedMesh; var hasValue = originalVertices.TryGetValue(renderKey, out Vector3[] origVerts); //On change clothes original verts become useless, so skip this if (!hasValue) { return; } //Some meshes are not readable and cant be touched... if (!sharedMesh.isReadable) { PregnancyPlusPlugin.errorCodeCtrl.LogErrorCode(ChaControl.chaID, ErrorCode.PregPlus_MeshNotReadable, $"ResetInflation > smr '{renderKey}' is not readable, skipping"); continue; } if (!sharedMesh || origVerts.Equals(null) || origVerts.Length == 0) { continue; } if (origVerts.Length != sharedMesh.vertexCount) { PregnancyPlusPlugin.errorCodeCtrl.LogErrorCode(ChaControl.chaID, ErrorCode.PregPlus_IncorrectVertCount, $"ResetInflation > smr '{renderKey}' has incorrect vert count {origVerts.Length}|{sharedMesh.vertexCount}"); continue; } sharedMesh.vertices = origVerts; sharedMesh.RecalculateBounds(); NormalSolver.RecalculateNormals(sharedMesh, 40f, alteredVerticieIndexes[renderKey]); //sharedMesh.RecalculateNormals(); //old way that leaves skin seams sharedMesh.RecalculateTangents(); } }
void Update() { for (int i = 0; i < mesh.vertices.Length; i++) { UpdateVertices(i); } mesh.vertices = replaceVertices; NormalSolver.RecalculateNormals(mesh, 90); }
private void UpdateMesh() { for (int i = 0; i < agents.Count; i++) { agents[i].UpdatePoints(vertexTemp); } mesh.vertices = vertexTemp; NormalSolver.RecalculateNormals(mesh, 90f); //NormalSolver.ReComputeNormals(mesh); //r.sharedMesh = mesh; }
public void DrawMeshOnEachBranch() { foreach (var branch in SplinePlus.SPData.DictBranches) { //update branches layers if (!DMBranches.ContainsKey(branch.Key)) { var newBranchLayer = new DMBranch(); newBranchLayer.MeshHolder = new GameObject("Mesh Holder"); newBranchLayer.MeshHolder.AddComponent <MeshFilter>(); newBranchLayer.MeshHolder.AddComponent <MeshRenderer>(); newBranchLayer.MeshHolder.transform.parent = this.gameObject.transform; DMBranches.Add(branch.Key, newBranchLayer); } //Draw all branches meshesB if (branch.Value.Vertices.Count > 0 && DMBranches[branch.Key].PrefabMeshes.Count > 0) { var dMBranch = DMBranches[branch.Key]; var branchFinalMesh = DrawMesh(branch.Value, dMBranch); branchFinalMesh.RecalculateBounds(); if (dMBranch.SmoothNormals) { NormalSolver.RecalculateNormals(branchFinalMesh, dMBranch.SmoothNormalsAngle); } else { branchFinalMesh.RecalculateNormals(); } dMBranch.MeshHolder.GetComponent <MeshFilter>().sharedMesh = branchFinalMesh; } } foreach (var dMBranch in DMBranches.Reverse()) { if (!SplinePlus.SPData.DictBranches.ContainsKey(dMBranch.Key)) { MonoBehaviour.DestroyImmediate(dMBranch.Value.MeshHolder); DMBranches.Remove(dMBranch.Key); } } if (IsUpdateBase) { IsUpdateBase = false; } }
private void UpdateSoftbody() { for (int i = 0; i < _vCount; i++) { _softVertices[i].UpdateVertex(); _softVertices[i].UpdateVelocity(bounciness); _softVertices[i].Settle(stiffness); _deformedVertices[i] = _softVertices[i].vertexPosition; } _originalMesh.vertices = _deformedVertices; _originalMesh.RecalculateBounds(); _originalMesh.RecalculateTangents(); //Third-party Recalculate Normals because Unity's RecalculateNormals make meshes normals to have seams NormalSolver.RecalculateNormals(_originalMesh, 60); }
/// <summary> /// Creates a copy of this planet in scaled space /// </summary> public void CreateScaledSpaceCopy() { if (!scaledSpaceCopy) { GameObject sphere = (GameObject)Resources.Load("scaledSpacePlanet"); sphere = Instantiate(sphere, transform.position / scaledSpaceFactor, transform.rotation * Quaternion.Euler(0f, 90f, 0f)); Mesh mesh; if (Application.isPlaying) { mesh = sphere.GetComponent <MeshFilter>().mesh; } else { mesh = Instantiate(sphere.GetComponent <MeshFilter>().sharedMesh); } Vector3[] vertices = mesh.vertices; Color32[] colors = new Color32[vertices.Length]; float sphereRadius = radius / scaledSpaceFactor; for (int i = 0; i < vertices.Length; i++) { float height = HeightAtXYZ(Quaternion.Euler(0f, 90f, 0f) * vertices[i]); vertices[i] *= (heightInv + height) / heightInv; vertices[i] *= sphereRadius; } mesh.vertices = vertices; mesh.colors32 = colors; mesh.RecalculateBounds(); NormalSolver.RecalculateNormals(mesh, 60); if (!Application.isPlaying) { sphere.GetComponent <MeshFilter>().mesh = mesh; } sphere.GetComponent <Renderer>().material = scaledSpaceMaterial; sphere.name = transform.name + "_ScaledSpace"; scaledSpaceCopy = sphere; } }
/// <summary> /// This will create a blendshape frame for a mesh, that can be used in timeline, required there be a renderKey for inflatedVertices for this smr /// </summary> /// <param name="smr">Target mesh renderer to update (original shape)</param> /// <param name="renderKey">The Shared Mesh render name, used in dictionary keys to get the current verticie values</param> /// <returns>Returns the MeshBlendShape that is created. Can be null</returns> internal MeshBlendShape CreateBlendShape(SkinnedMeshRenderer smr, string renderKey) { //Make a copy of the mesh. We dont want to affect the existing for this var meshCopyOrig = PregnancyPlusHelper.CopyMesh(smr.sharedMesh); if (!meshCopyOrig.isReadable) { PregnancyPlusPlugin.errorCodeCtrl.LogErrorCode(ChaControl.chaID, ErrorCode.PregPlus_MeshNotReadable, $"CreateBlendShape > smr '{renderKey}' is not readable, skipping"); return(null); } //Make sure we have an existing belly shape to work with (can be null if user hasnt used sliders yet) var exists = originalVertices.TryGetValue(renderKey, out var val); if (!exists) { if (PregnancyPlusPlugin.DebugLog.Value) { PregnancyPlusPlugin.Logger.LogInfo( $"CreateBlendShape > smr '{renderKey}' does not exists, skipping"); } return(null); } if (originalVertices[renderKey].Length != meshCopyOrig.vertexCount) { PregnancyPlusPlugin.errorCodeCtrl.LogErrorCode(ChaControl.chaID, ErrorCode.PregPlus_IncorrectVertCount, $"CreateBlendShape > smr.sharedMesh '{renderKey}' has incorrect vert count {originalVertices[renderKey].Length}|{meshCopyOrig.vertexCount}"); return(null); } //Calculate the original normals, but don't show them. We just want it for the blendshape shape destination meshCopyOrig.vertices = originalVertices[renderKey]; meshCopyOrig.RecalculateBounds(); NormalSolver.RecalculateNormals(meshCopyOrig, 40f, bellyVerticieIndexes[renderKey]); meshCopyOrig.RecalculateTangents(); // LogMeshBlendShapes(smr); //Create a blend shape object on the mesh var bsc = new BlendShapeController(meshCopyOrig, smr, $"{renderKey}_{PregnancyPlusPlugin.GUID}"); //Return the blendshape format that can be saved to character card return(ConvertToMeshBlendShape(smr.name, bsc.blendShape)); }
public void Generate(Generation world, Color grass, Color dampGrass, Color mud, PerlinNoise[] terrainNoises, PerlinNoise moistureNoise) { MeshFilter meshFilter = GetComponent <MeshFilter> (); Mesh mesh = meshFilter.mesh; Vector3[] vertices = mesh.vertices; Color[] colors = mesh.colors; for (int i = 0; i < vertices.Length; i++) { // World positon of the vertex Vector3 worldPositionVertex = transform.TransformPoint(vertices[i]); float finalDeform = 0f; float maxWorldHeight = 0f; foreach (PerlinNoise noise in terrainNoises) { finalDeform += noise.ReturnNoise(worldPositionVertex); maxWorldHeight += noise.strength; } float moisture = moistureNoise.ReturnNoise(worldPositionVertex); vertices[i] += new Vector3(0f, finalDeform, 0f); Color groundColor = Color.Lerp(Color.Lerp(grass, dampGrass, 1f / maxWorldHeight * vertices[i].y), mud, moisture); colors[i] = groundColor; } // reassignation mesh.vertices = vertices; mesh.colors = colors; mesh.RecalculateBounds(); mesh.RecalculateNormals(); NormalSolver.RecalculateNormals(mesh, normalAngle); meshFilter.mesh = mesh; GetComponent <MeshCollider> ().sharedMesh = mesh; world.terrainMeshFilters.Add(meshFilter); }
void Update() { if (Input.GetKeyDown(KeyCode.F7)) { renderers = FindObjectsOfType <SkinnedMeshRenderer>(); foreach (SkinnedMeshRenderer render in renderers) { //Console.WriteLine("SkinnedMeshRenderer: " + render.name); if (render.name.ToLower().Contains("cf_o_hair")) { NormalSolver.RecalculateNormals(render.sharedMesh, 60f); TangentSolver.Solve(render.sharedMesh); } } } else if (Input.GetKeyDown(KeyCode.F8)) { renderers = FindObjectsOfType <SkinnedMeshRenderer>(); foreach (SkinnedMeshRenderer render in renderers) { //Console.WriteLine("SkinnedMeshRenderer: " + render.name); if (render.name.ToLower().Contains("cf_o_hair")) { render.sharedMesh.RecalculateNormals(); TangentSolver.Solve(render.sharedMesh); } } } else if (Input.GetKeyDown(KeyCode.F9)) { renderers = FindObjectsOfType <SkinnedMeshRenderer>(); foreach (SkinnedMeshRenderer render in renderers) { if (render.name.ToLower().Contains("cf_o_hair")) { TangentSolver.Solve(render.sharedMesh); } } } }
public static void BuildMesh(Transform parent, LinePoints[] curves, Material material, float lineRadius, int sphereIterations, int cylinderCapSegments, Color vertexColor) { DeleteChildObjects(parent, "Curve"); for (int z = 0; z < curves.Length; z++) { for (int v = 0; v < curves[z].Points.Length; v++) { Mesh m = SphereScript.BuildMesh(curves[z].Points[v], lineRadius, sphereIterations, vertexColor); m = NormalSolver.RecalculateNormals(m, 75f); CreateChildObject(parent, "Curve_" + z + "_Sphere_" + v, m, material); if (v < curves[z].Points.Length - 1) { Mesh m2 = CylinderScript.BuildMesh(curves[z].Points[v], curves[z].Points[v + 1], lineRadius, lineRadius, vertexColor, new Vector3(0f, 90f, 0f), cylinderCapSegments, true); m2 = NormalSolver.RecalculateNormals(m2, 75f); CreateChildObject(parent, "Curve_" + z + "_Cylinder_" + v, m2, material); } } if (curves[z].ArrowAtStart) { Vector3 p0 = curves[z].Points[0]; Vector3 p1 = curves[z].Points[1]; Vector3 parrow = (p0 - p1).normalized * curves[z].ArrowLength + p0; Mesh m = CylinderScript.BuildMesh(p0, parrow, curves[z].ArrowRadius, 0f, vertexColor, new Vector3(0f, 90f, 0f), cylinderCapSegments, true); m = NormalSolver.RecalculateNormals(m, 75f); CreateChildObject(parent, "Curve_" + z + "_ArrowStart", m, material); } if (curves[z].ArrowAtEnd) { Vector3 p0 = curves[z].Points[curves[z].Points.Length - 1]; Vector3 p1 = curves[z].Points[curves[z].Points.Length - 2]; Vector3 parrow = (p0 - p1).normalized * curves[z].ArrowLength + p0; Mesh m = CylinderScript.BuildMesh(p0, parrow, curves[z].ArrowRadius, 0f, vertexColor, new Vector3(0f, 90f, 0f), cylinderCapSegments, true); m = NormalSolver.RecalculateNormals(m, 75f); CreateChildObject(parent, "Curve_" + z + "_ArrowEnd", m, material); } } }
public void createGeometry(Material material, Algorithm2 algorithm) { init(); // Generate the quads float quadSize = (new Vector3(startPoint.x, 0, endPoint.z) - startPoint).magnitude / (float)quads; for (int i = 0; i < quads; i++) { for (int j = 0; j < quads; j++) { Chunk2.createQuad((float)i * quadSize, (float)j * quadSize, quadSize, algorithm, meshData, transform); } } // Pass the data to the mesh meshRenderer.sharedMaterial = material; meshData.GenerateData(meshFilter.sharedMesh); // Recalculate bounds and normals meshFilter.sharedMesh.RecalculateBounds(); NormalSolver.RecalculateNormals(meshFilter.sharedMesh, 60); }
public void BuildMeshes() { GameObject parent = new GameObject("_Models"); parent.transform.parent = MapRenderer.mapParent.transform; Dictionary <int, AnimProperties> anims = new Dictionary <int, AnimProperties>(); int nodeId = 0; foreach (RSM.CompiledModel model in models) { GameObject modelObj = new GameObject(model.rsm.name); modelObj.transform.parent = parent.transform; foreach (var nodeData in model.nodesData) { foreach (var meshesByTexture in nodeData) { long textureId = meshesByTexture.Key; RSM.NodeMeshData meshData = meshesByTexture.Value; RSM.Node node = meshData.node; if (meshesByTexture.Value.vertices.Count == 0) { continue; } for (int i = 0; i < meshData.vertices.Count; i += 3) { meshData.triangles.AddRange(new int[] { i + 0, i + 1, i + 2 }); } //create node unity mesh Mesh mesh = new Mesh(); mesh.vertices = meshData.vertices.ToArray(); mesh.triangles = meshData.triangles.ToArray(); //mesh.normals = meshData.normals.ToArray(); mesh.uv = meshData.uv.ToArray(); GameObject nodeObj = new GameObject(node.name); nodeObj.transform.parent = modelObj.transform; string textureFile = model.rsm.textures[textureId]; var mf = nodeObj.AddComponent <MeshFilter>(); mf.mesh = mesh; var mr = nodeObj.AddComponent <MeshRenderer>(); if (meshData.twoSided) { mr.material = material2s; if (textureFile.EndsWith("tga")) { mr.material.shader = Resources.Load("2SidedAlpha") as Shader; mr.material.renderQueue += 1; } } else { mr.material = material; if (textureFile.EndsWith("tga")) { mr.material.shader = Resources.Load("ModelShaderAlpha") as Shader; mr.material.renderQueue += 1; } } mr.material.mainTexture = FileManager.Load("data/texture/" + textureFile) as Texture2D; if (model.rsm.shadeType == RSM.SHADING.SMOOTH) { NormalSolver.RecalculateNormals(mf.mesh, 60); } else { mf.mesh.RecalculateNormals(); } var matrix = node.GetPositionMatrix(); nodeObj.transform.position = matrix.ExtractPosition(); var rotation = matrix.ExtractRotation(); nodeObj.transform.rotation = rotation; nodeObj.transform.localScale = matrix.ExtractScale(); var properties = nodeObj.AddComponent <NodeProperties>(); properties.nodeId = nodeId; properties.mainName = model.rsm.mainNode.name; properties.parentName = node.parentName; if (node.posKeyframes.Count > 0 || node.rotKeyframes.Count > 0) { nodeObj.AddComponent <NodeAnimation>().nodeId = nodeId; anims.Add(nodeId, new AnimProperties() { posKeyframes = node.posKeyframes, rotKeyframes = node.rotKeyframes, animLen = model.rsm.animLen, baseRotation = rotation, isChild = properties.isChild }); } nodeId++; } } modelObj.SetActive(false); //instantiate model for (int i = 0; i < model.rsm.instances.Count; i++) { GameObject instanceObj; if (i == model.rsm.instances.Count - 1) { //last instance instanceObj = modelObj; } else { instanceObj = UnityEngine.Object.Instantiate(modelObj); } instanceObj.transform.parent = parent.transform; instanceObj.name += "[" + i + "]"; RSW.ModelDescriptor descriptor = model.rsm.instances[i]; instanceObj.transform.Rotate(Vector3.forward, -descriptor.rotation[2]); instanceObj.transform.Rotate(Vector3.right, -descriptor.rotation[0]); instanceObj.transform.Rotate(Vector3.up, descriptor.rotation[1]); Vector3 scale = new Vector3(descriptor.scale[0], -descriptor.scale[1], descriptor.scale[2]); instanceObj.transform.localScale = scale; //avoid z fighting between models float xRandom = UnityEngine.Random.Range(-0.002f, 0.002f); float yRandom = UnityEngine.Random.Range(-0.002f, 0.002f); float zRandom = UnityEngine.Random.Range(-0.002f, 0.002f); Vector3 position = new Vector3(descriptor.position[0] + xRandom, descriptor.position[1] + yRandom, descriptor.position[2] + zRandom); position.x += MapRenderer.width; position.y *= -1; position.z += MapRenderer.height; instanceObj.transform.position = position; //setup hierarchy var propertiesComponents = instanceObj.GetComponentsInChildren <NodeProperties>(); foreach (var properties in propertiesComponents) { if (properties.isChild) { var nodeParent = instanceObj.transform.FindRecursive(properties.parentName); properties.transform.parent = nodeParent; } } //setup animations var animComponents = instanceObj.GetComponentsInChildren <NodeAnimation>(); foreach (var animComponent in animComponents) { var properties = anims[animComponent.nodeId]; animComponent.Initialize(properties); } instanceObj.SetActive(true); } } anims.Clear(); }
/// <summary> /// Extend mesh along normal /// </summary> void Deform() { var mesh = meshFilter.sharedMesh; var vs = new Vector3[baseVertices.Length]; var colors = new Color[baseVertices.Length]; //var vs = mesh.vertices; var offsetX = speed * time + seedX; var offsetY = speed * time + seedY; var offsetZ = speed * time + seedZ; // compute min and max height float min = 100, max = -100; for (var i = 0; i < vs.Length; ++i) { var u = baseVertices [i]; var inX = u.x; var inY = u.y; var inZ = u.z; float h = noise.SampleNoise(inX, inY, inZ, offsetX, offsetY, offsetZ); min = Mathf.Min(min, h); max = Mathf.Max(max, h); } // compute actual height for (var i = 0; i < vs.Length; ++i) { var u = baseVertices [i]; var v = vs [i]; var inX = u.x; var inY = u.y; var inZ = u.z; float h = noise.SampleNoise(inX, inY, inZ, offsetX, offsetY, offsetZ); // re-scale, so delta will always be between 0 and 1 h = (h - min) / (max - min); int bi = biomes.Length - 1; var realH = 0.0f; for (var b = 0; b < biomes.Length; ++b) { h -= biomes [b].height; realH += biomes [b].scale; if (h < 0) { bi = b; //var dh = h - baseH; //h = baseH; //+ biomes [bi].scale; break; } } var biome = biomes [bi]; colors [i] = biome.color; // randomly move along the normal var n = baseNormals [i]; v = u + realH * n; vs [i] = v; } mesh.vertices = vs; mesh.colors = colors; //mesh.RecalculateNormals (); NormalSolver.RecalculateNormals(mesh, 0); mesh.RecalculateTangents(); mesh.RecalculateBounds(); }
void Start() { RaycastHit hit; if (Physics.Raycast(GetComponent <MeshRenderer>().bounds.center, Vector3.down, out hit, 200f)) { if (hit.transform.tag == collisonTag) { if (deformMesh) { // For each vertex, we raycast down and add an offset MeshFilter meshFilter = GetComponent <MeshFilter>(); Mesh mesh = meshFilter.mesh; Vector3[] vertices = mesh.vertices; for (int i = 0; i < vertices.Length; i++) { // World positon of the vertex Vector3 worldPositionVertex = transform.TransformPoint(vertices[i]); RaycastHit vertexHit; if (Physics.Raycast(worldPositionVertex, Vector3.down, out vertexHit, 300f, deformLayerMask)) { float baseHeight = vertices[i].y; vertices[i] -= new Vector3(0f, vertexHit.distance - baseHeight, 0f); } else { float baseHeight = vertices[i].y; vertices[i] -= new Vector3(0f, 100f - baseHeight, 0f); } } mesh.vertices = vertices; mesh.RecalculateBounds(); mesh.RecalculateNormals(); NormalSolver.RecalculateNormals(mesh, 90f); meshFilter.mesh = mesh; gameObject.AddComponent <BoxCollider>(); } else { transform.position = new Vector3(transform.position.x, hit.point.y, transform.position.z); } // Misc Additonal if (useGroundColor) { // we fetch color data from the terrain MeshFilter filter = hit.transform.gameObject.GetComponent <MeshFilter>(); Mesh mesh = filter.mesh; Color[] colors = mesh.colors; Vector3[] vertices = mesh.vertices; Color finalGrassColor = Color.white; float closestDistance = 1000f; for (int i = 0; i < vertices.Length; i++) { Vector3 worldPositionVertex = transform.TransformPoint(vertices[i]); float distancce = Vector3.Distance(transform.position, worldPositionVertex); if (distancce < closestDistance) { closestDistance = distancce; finalGrassColor = colors[i]; } } // now we color our actual mesh filter = gameObject.GetComponent <MeshFilter>(); mesh = filter.mesh; colors = mesh.colors; for (int i = 0; i < colors.Length; i++) { colors[i] = new Color(finalGrassColor.r, finalGrassColor.g, finalGrassColor.b, colors[i].a); } mesh.colors = colors; filter.mesh = mesh; } if (orientToSurfaceNormal) { Vector3 lookAt = Vector3.Cross(-hit.normal, transform.right); lookAt = lookAt.y < 0 ? -lookAt : lookAt; transform.rotation = Quaternion.LookRotation(hit.point + lookAt, hit.normal); } if (randomYRotation) { transform.Rotate(new Vector3(0f, Random.value * 360, 0f), Space.Self); } } else { Destroy(this.gameObject); } } }
public void End() { foreach (var prim in primitives) { prim.End(); } var idx_base = 0; var vertices = new List <Vector3> (); var triangles = new List <int> (); var submeshes_count = 0; var colors = new List <Color32> (); foreach (var prim in primitives) { vertices.AddRange(prim.vertices); triangles.AddRange(prim.triangles.Select(e => e + idx_base).ToList()); submeshes_count += prim.submeshes.Count; colors.AddRange(prim.vcolors); idx_base += prim.vertices.Count; } /* * Manager.DebugLog ("----------"); * Manager.DebugLog ("End:" + name); * Manager.DebugLog ("total size of vertices = " + vertices.Count); * Manager.DebugLog ("total size of triangles = " + triangles.Count); * Manager.DebugLog ("total size of colors = " + colors.Count); * Manager.DebugLog ("total size of submeshes = " + submeshes_count); * * foreach (var prim in primitives) { * Manager.DebugLog ("----------"); * Manager.DebugLog (prim.name); * Manager.DebugLog ("size of vertices = " + prim.vertices.Count); * Manager.DebugLog ("size of triangles = " + prim.triangles.Count); * Manager.DebugLog ("size of colorss = " + prim.vcolors.Count); * Manager.DebugLog ("sizeof submeshes = " + prim.submeshes.Count); * } */ var mesh = new Mesh(); mesh.name = name; mesh.vertices = vertices.ToArray(); mesh.triangles = triangles.ToArray(); mesh.colors32 = colors.ToArray(); GetComponent <MeshFilter> ().sharedMesh = mesh; var i = 0; idx_base = 0; var materials = new Material[submeshes_count]; mesh.subMeshCount = submeshes_count; foreach (var prim in primitives) { foreach (var subm in prim.submeshes) { if (subm.pen.shaderType == Pen.ShaderType.SingleSided) { materials [i] = material_singleSided; } else if (subm.pen.shaderType == Pen.ShaderType.DoubleSided) { materials [i] = material_doubleSided; } else if (subm.pen.shaderType == Pen.ShaderType.VertexColors) { materials [i] = material_vertexColors; } mesh.SetTriangles(subm.triangles.Select(e => e + idx_base).ToList(), i); ++i; } idx_base += prim.vertices.Count; } GetComponent <Renderer> ().materials = materials; i = 0; foreach (var prim in primitives) { foreach (var subm in prim.submeshes) { GetComponent <Renderer> ().materials [i].SetColor("_FColor", subm.pen.frontColor); GetComponent <Renderer> ().materials [i].SetColor("_BColor", subm.pen.backColor); ++i; } } //mesh.RecalculateNormals(); NormalSolver.RecalculateNormals(mesh, 60f); // see http://schemingdeveloper.com/2017/03/26/better-method-recalculate-normals-unity-part-2/ mesh.RecalculateBounds(); rendering = false; initialized = false; }
public void generateMesh() { this.meshCached = true; if (this.gameObject.GetComponent <MeshFilter>() == null) { this.gameObject.AddComponent <MeshFilter>(); } MeshRenderer render = this.gameObject.GetComponent <MeshRenderer>(); if (render == null) { render = this.gameObject.AddComponent <MeshRenderer>(); render.material = new Material(Shader.Find("Clayxel/ClayxelMeshShader")); } render.sharedMaterial.SetFloat("_Glossiness", this.materialSmoothness); render.sharedMaterial.SetFloat("_Metallic", this.materialMetallic); render.sharedMaterial.SetColor("_Emission", this.materialEmission); ComputeBuffer meshIndicesBuffer = new ComputeBuffer(this.chunkMaxOutPoints * 6, sizeof(float) * 3, ComputeBufferType.Counter); Clayxel.claycoreCompute.SetBuffer((int)Kernels.genMesh, "meshOutIndices", meshIndicesBuffer); ComputeBuffer meshVertsBuffer = new ComputeBuffer(this.chunkMaxOutPoints, sizeof(float) * 3, ComputeBufferType.Counter); Clayxel.claycoreCompute.SetBuffer((int)Kernels.genMesh, "meshOutPoints", meshVertsBuffer); ComputeBuffer meshColorsBuffer = new ComputeBuffer(this.chunkMaxOutPoints, sizeof(float) * 4); Clayxel.claycoreCompute.SetBuffer((int)Kernels.genMesh, "meshOutColors", meshColorsBuffer); List <Vector3> totalVertices = new List <Vector3>(); List <int> totalIndices = new List <int>(); List <Color> totalColors = new List <Color>(); int totalNumVerts = 0; this.mesh = new Mesh(); this.mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; this.switchComputeData(); this.updateSolids(); Clayxel.claycoreCompute.SetInt("numSolids", this.clayObjects.Count); Clayxel.claycoreCompute.SetFloat("chunkSize", (float)this.chunkSize); Clayxel.claycoreCompute.SetFloat("surfaceBoundaryThreshold", 4.0f); // compute more cells than needed to make sure we don't leave holes in the final mesh for (int chunkIt = 0; chunkIt < this.numChunks; ++chunkIt) { ClayxelChunk chunk = this.chunks[chunkIt]; meshIndicesBuffer.SetCounterValue(0); meshVertsBuffer.SetCounterValue(0); this.computeChunkPoints(chunk); // dirty hack, calling this a second time will make sure we don't skip cells and there's no holes in the mesh this.computeChunkPoints(chunk); Clayxel.claycoreCompute.SetInt("outMeshIndexOffset", totalNumVerts); Clayxel.claycoreCompute.Dispatch((int)Kernels.genMesh, 16, 16, 16); Clayxel.claycoreCompute.Dispatch((int)Kernels.clearChunkData, this.numThreadsCompute6, this.numThreadsCompute6, this.numThreadsCompute6); int numVerts = this.getBufferCount(meshVertsBuffer); int numQuads = this.getBufferCount(meshIndicesBuffer) * 3; totalNumVerts += numVerts; Vector3[] vertices = new Vector3[numVerts]; meshVertsBuffer.GetData(vertices); int[] indices = new int[numQuads]; meshIndicesBuffer.GetData(indices); Color[] colors = new Color[numVerts]; meshColorsBuffer.GetData(colors); totalVertices.AddRange(vertices); totalIndices.AddRange(indices); totalColors.AddRange(colors); } mesh.vertices = totalVertices.ToArray(); mesh.colors = totalColors.ToArray(); mesh.triangles = totalIndices.ToArray(); this.mesh.Optimize(); // this.mesh.RecalculateNormals(); NormalSolver.RecalculateNormals(this.mesh, 120.0f); this.gameObject.GetComponent <MeshFilter>().mesh = this.mesh; meshIndicesBuffer.Release(); meshVertsBuffer.Release(); meshColorsBuffer.Release(); this.releaseBuffers(); this.needsInit = false; }
public void RecacluateNormals(float angle = 60) { NormalSolver.RecalculateNormals(m_meshFilter.sharedMesh, angle); }
/// <summary> /// This will update all verticies with a lerp from originalVertices to inflatedVertices depending on the inflationSize config /// Only modifies belly verticies, and if none are found, no action taken. /// </summary> /// <param name="mesh">Target mesh to update</param> /// <param name="renderKey">The Shared Mesh render name, used in dictionary keys to get the current verticie values</param> /// <returns>Will return True if any verticies are changed</returns> internal bool ApplyInflation(SkinnedMeshRenderer smr, string renderKey) { var infSize = infConfig.inflationSize; //Only inflate if the value is above 0 if (infSize.Equals(null) || infSize == 0) { return(false); } //Create an instance of sharedMesh so we don't modify the mesh shared between characters var meshCopy = (Mesh)UnityEngine.Object.Instantiate(smr.sharedMesh); smr.sharedMesh = meshCopy; var sharedMesh = smr.sharedMesh; //Some meshes are not readable and cant be touched... Nothing I can do about this right now if (!sharedMesh.isReadable) { PregnancyPlusPlugin.errorCodeCtrl.LogErrorCode(ChaControl.chaID, ErrorCode.PregPlus_MeshNotReadable, $"ApplyInflation > smr '{renderKey}' is not readable, skipping"); return(false); } //Check key exists in dict, remove it if it does not var exists = originalVertices.TryGetValue(renderKey, out var val); if (!exists) { if (PregnancyPlusPlugin.DebugLog.Value) { PregnancyPlusPlugin.Logger.LogInfo( $"ApplyInflation > smr '{renderKey}' does not exists, skipping"); } RemoveRenderKey(renderKey); return(false); } //Get computed mesh values var origVert = originalVertices[renderKey]; var currentVert = currentVertices[renderKey]; var bellyVertIndex = bellyVerticieIndexes[renderKey]; if (bellyVertIndex.Length == 0) { return(false); } infConfigHistory.inflationSize = infSize; var currentVertLength = currentVert.Length; //Apply lerp morph for each changed verticie for (int i = 0; i < currentVertLength; i++) { //If not a belly index verticie then skip the morph if (!PregnancyPlusPlugin.DebugVerts.Value && !bellyVertIndex[i]) { continue; } //Set the lerp size of the belly based on the users slider value currentVert[i] = Vector3.Lerp(origVert[i], inflatedVertices[renderKey][i], (infSize / 40)); } //Check that the mesh did not change behind the scenes. It will have a different vert count if it did (possible to be the same though...) if (currentVert.Length != sharedMesh.vertexCount) { PregnancyPlusPlugin.errorCodeCtrl.LogErrorCode(ChaControl.chaID, ErrorCode.PregPlus_IncorrectVertCount, $"ApplyInflation > smr.sharedMesh '{renderKey}' has incorrect vert count {currentVert.Length}|{sharedMesh.vertexCount}"); return(false); } if (PregnancyPlusPlugin.DebugLog.Value) { PregnancyPlusPlugin.Logger.LogInfo($" mesh did ApplyInflation > {smr.name}"); } sharedMesh.vertices = currentVert; sharedMesh.RecalculateBounds(); NormalSolver.RecalculateNormals(sharedMesh, 40f, alteredVerticieIndexes[renderKey]); //sharedMesh.RecalculateNormals(); //old way that leaves skin seams at UV boundaries sharedMesh.RecalculateTangents(); return(true); }
void UpdateVertices() { UnityEngine.Debug.Log("Update Vertices"); Stopwatch sw = new Stopwatch(); sw.Start(); if (dic_VertexForce.Count == 0) { _mesh.vertices = originalVertices; _mesh.RecalculateNormals(); NormalSolver.RecalculateNormals(_mesh, 30); return; } Vector3[,] offsets = new Vector3[Masses.Count, dic_VertexForce.Count]; Dictionary <int, Vector3> .Enumerator it = dic_VertexForce.GetEnumerator(); int forceIdx = 0; while (it.MoveNext()) { int vertexIdx = it.Current.Key; Vector3 force = it.Current.Value; offsets[vertexIdx, forceIdx++] = force; } // 多组质点弹簧遍历 it = dic_VertexForce.GetEnumerator(); Queue <int> masses = new Queue <int> (); HashSet <int> mark = new HashSet <int> (); forceIdx = 0; while (it.MoveNext()) { int vidx_force = it.Current.Key; Vector3 force = it.Current.Value; offsets[vidx_force, forceIdx] = force; masses.Clear(); mark.Clear(); masses.Enqueue(vidx_force); mark.Add(vidx_force); // 一组质点弹簧遍历 while (masses.Count > 0) { int vidx = masses.Dequeue(); Vector3 delta = offsets[vidx, forceIdx]; // 遍历此节点所有链接点 Dictionary <int, float> edge = MassSprings [vidx]; Dictionary <int, float> .Enumerator iter = edge.GetEnumerator(); while (iter.MoveNext()) { int idx = iter.Current.Key; float value = iter.Current.Value; int key = vidx > idx ? vidx | (idx << 16) : (vidx << 16) | idx; if (mark.Contains(key)) { continue; } Vector3 v = delta / (1 + value / kViscosity); if (v.magnitude <= kThresholdZero) { continue; } if (!dic_VertexForce.ContainsKey(idx) && offsets[idx, forceIdx].sqrMagnitude < v.sqrMagnitude) { offsets[idx, forceIdx] = v; masses.Enqueue(idx); } } iter = edge.GetEnumerator(); while (iter.MoveNext()) { int idx = iter.Current.Key; int key = vidx > idx ? vidx | (idx << 16) : (vidx << 16) | idx; mark.Add(key); } } forceIdx++; } sw.Stop(); //UnityEngine.Debug.LogFormat ("using {0}", sw.ElapsedMilliseconds); // 计算各顶点偏移量 for (int i = 0; i < offsets.GetLength(0); i++) { Vector3 result = Vector3.zero; // 计算改顶点最终形变量(x,y,z) for (int j = 0; j < 3; j++) { float positive = 0f; float negative = 0f; for (int k = 0; k < dic_VertexForce.Count; k++) { Vector3 offset = offsets [i, k]; float v = offset [j]; if (v > 0 && v > positive) { positive = v; } else if (v < 0 && v < negative) { negative = v; } } result [j] = positive + negative; } // 最终结果保存在第一个位置 offsets [i, 0] = result; } // 计算出最新的顶点位置 for (int i = 0; i < Masses.Count; i++) { MassPoint mass = Masses [i]; for (int j = 0; j < mass.vertices.Count; j++) { int vid = mass.vertices [j]; displacedVertices [vid] = originalVertices [vid] + offsets [i, 0]; } } _mesh.vertices = displacedVertices; _mesh.RecalculateNormals(); NormalSolver.RecalculateNormals(_mesh, 30); }
public void UpdateChunkMesh(Chunk chunk, bool?blocking = null) { int numVoxelsPerAxis = numPointsPerAxis - 1; int numThreadsPerAxis = Mathf.CeilToInt(numVoxelsPerAxis / (float)threadGroupSize); float pointSpacing = boundsSize / (numPointsPerAxis - 1); bool blockGpu = blocking ?? blockingGpu; Vector3Int coord = chunk.coord; Vector3 centre = CentreFromCoord(coord); Vector3 worldBounds = new Vector3(numChunks.x, numChunks.y, numChunks.z) * boundsSize; densityGenerator.Generate(pointsBuffer, numPointsPerAxis, boundsSize, worldBounds, centre, offset, pointSpacing); void SetupShader() { triangleBuffer.SetCounterValue(0); shader.SetBuffer(0, "points", pointsBuffer); shader.SetBuffer(0, "triangles", triangleBuffer); shader.SetInt("numPointsPerAxis", numPointsPerAxis); shader.SetFloat("isoLevel", isoLevel); shader.Dispatch(0, numThreadsPerAxis, numThreadsPerAxis, numThreadsPerAxis); } ComputeBuffer.CopyCount(triangleBuffer, triCountBuffer, 0); void HandleReadBack() { int[] triCountArray = { 0 }; triCountBuffer.GetData(triCountArray); int numTris = triCountArray[0]; if (numTris > maxTris || tris == null || vertices == null || meshTriangles == null) { maxTris = numTris; tris = new Triangle[numTris]; vertices = new Vector3[numTris * 3]; meshTriangles = new int[numTris * 3]; } // Get triangle data from shader triangleBuffer.GetData(tris, 0, 0, numTris); Mesh mesh = chunk.mesh; mesh.Clear(); for (int i = 0; i < numTris; i++) { for (int j = 0; j < 3; j++) { meshTriangles[i * 3 + j] = i * 3 + j; vertices[i * 3 + j] = tris[i][j]; } } mesh.vertices = vertices; mesh.triangles = meshTriangles; var scale = chunk.GetComponent <Transform>().localScale; mesh.SetUVs(0, UvCalculator.CalculateUVs(vertices, scale.magnitude)); NormalSolver.RecalculateNormals(mesh, normalDegrees); chunk.UpdateColliders(); } if (!blockGpu) { chunk.asyncOp0 = null; chunk.asyncOp1 = null; chunk.asyncOp2 = null; var async0 = AsyncGPUReadback.Request(pointsBuffer, delegate(AsyncGPUReadbackRequest a0) { SetupShader(); var async1 = AsyncGPUReadback.Request(triangleBuffer, delegate(AsyncGPUReadbackRequest a1) { // Get number of triangles in the triangle buffer ComputeBuffer.CopyCount(triangleBuffer, triCountBuffer, 0); var async2 = AsyncGPUReadback.Request(triCountBuffer, delegate(AsyncGPUReadbackRequest a2) { HandleReadBack(); }); chunk.asyncOp2 = async2; }); chunk.asyncOp1 = async1; }); chunk.asyncOp0 = async0; } else { SetupShader(); ComputeBuffer.CopyCount(triangleBuffer, triCountBuffer, 0); HandleReadBack(); } }
public Mesh ExtrudeMeshFromPoints(Vector2[] points2d) { if (isClockwise(points2d)) { // Debug.Log("It's clockwise!"); System.Array.Reverse(points2d); } Mesh mesh = new Mesh(); Vector3[] vertices = new Vector3[4 * points2d.Length]; // Vertex list int sideOffset = 2 * points2d.Length; for (int i = 0; i < points2d.Length; i++) { Vector2 point = points2d[i]; vertices[i] = new Vector3(point.x, point.y, 0); vertices[points2d.Length + i] = new Vector3(point.x, point.y, extrusionDepth); vertices[sideOffset + i] = new Vector3(point.x, point.y, 0); vertices[sideOffset + points2d.Length + i] = new Vector3(point.x, point.y, extrusionDepth); } Triangulator tr = new Triangulator(points2d); int[] backIndices = tr.Triangulate(); int[] topIndices = GetReverseTriangles(backIndices, points2d.Length); int[] sideIndices = new int[6 * points2d.Length]; // sides for (int i = 0; i < points2d.Length - 1; i++) { sideIndices[6 * i + 0] = sideOffset + i; sideIndices[6 * i + 1] = sideOffset + i + 1; sideIndices[6 * i + 2] = sideOffset + points2d.Length + i; sideIndices[6 * i + 3] = sideOffset + points2d.Length + i; sideIndices[6 * i + 4] = sideOffset + i + 1; sideIndices[6 * i + 5] = sideOffset + points2d.Length + i + 1; } sideIndices[sideIndices.Length - 6] = sideOffset + points2d.Length - 1; sideIndices[sideIndices.Length - 5] = sideOffset + 0; sideIndices[sideIndices.Length - 4] = sideOffset + 2 * points2d.Length - 1; sideIndices[sideIndices.Length - 3] = sideOffset + 2 * points2d.Length - 1; sideIndices[sideIndices.Length - 2] = sideOffset + 0; sideIndices[sideIndices.Length - 1] = sideOffset + points2d.Length; //if (ShouldFlipPerimeter(sideIndices, points2d.Length)) // { // sideIndices = GetReverseTriangles (sideIndices, 0); // //return ExtrudeMeshFromPoints(points2d); // } // put it all together int[] triangles = new int[topIndices.Length + backIndices.Length + sideIndices.Length]; topIndices.CopyTo(triangles, 0); backIndices.CopyTo(triangles, topIndices.Length); sideIndices.CopyTo(triangles, topIndices.Length + backIndices.Length); // // UVs (texture mapping points) - Just half-assing for now. Easy to improve later! // Vector2[] uv = new Vector2[vertices.Length]; // for (int i = 0; i < topPtOffset; i += 2) { // uv[i + 0] = new Vector2((float)i/topPtOffset, 0); // uv[i + 1] = new Vector2((float)i/topPtOffset, 1); // } // for (int i = topPtOffset; i < bottomPtOffset; i++) { // uv[i] = new Vector2(0,0); // } // for (int i = bottomPtOffset; i < vertices.Length; i++) { // uv[i] = new Vector2(0,0); // } mesh.vertices = vertices; mesh.triangles = triangles; NormalSolver.RecalculateNormals(mesh, 60f); // mesh.uv = uv; mesh.Optimize(); return(mesh); }