private void GenerateMesh() { UOUtility.DestroyChildren(generated); _bounds = new Bounds(); int i = 0; float textureOffset = 0.0f; foreach (CubicBezierCurve curve in spline.GetCurves()) { GameObject go = UOUtility.Create("segment " + i++, generated, typeof(MeshFilter), typeof(MeshRenderer), typeof(ExtrusionSegment), typeof(MeshCollider)); go.GetComponent <MeshRenderer>().material = material; ExtrusionSegment mb = go.GetComponent <ExtrusionSegment>(); mb.SetShapeVertices(shapeVertices, false); mb.SetLoopAround(loopAround, false); mb.SetTextureScale(textureScale, false); mb.SetCurve(curve, true); mb.SetTextureOffset(textureOffset, true); textureOffset += curve.Length; _bounds.Encapsulate(go.GetComponent <MeshFilter>().sharedMesh.bounds); } }
private void Init() { string generatedName = "generated by " + GetType().Name; var generatedTranform = transform.Find(generatedName); generated = generatedTranform != null ? generatedTranform.gameObject : UOUtility.Create(generatedName, gameObject, typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshBender)); generated.GetComponent <MeshRenderer>().material = material; if (generated.GetComponent <DecrepitEffect>() == null) { generated.AddComponent <DecrepitEffect>(); } meshBender = generated.GetComponent <MeshBender>(); spline = GetComponent <Spline>(); meshBender.Source = SourceMesh.Build(mesh) .Rotate(Quaternion.Euler(rotation)) .Scale(scale); meshBender.Mode = MeshBender.FillingMode.StretchToInterval; meshBender.SetInterval(spline, 0, 0.01f); }
private void Generate() { UOUtility.DestroyChildren(Generated); wayPoints.Clear(); float localSpacing = 0; Joint joint = null; for (int i = 0; i < segmentCount; i++) { var seg = UOUtility.Instantiate(segmentPrefab, Generated.transform); seg.transform.Translate(0, 0, localSpacing); var segRB = seg.GetComponent <Rigidbody>(); // we fix the first segment so that the rope won't fall if (i == 0) { firstSegment = seg; segRB.constraints = RigidbodyConstraints.FreezePosition; } // we attach the rigidbody to the joint of the previous segment if (joint != null) { joint.connectedBody = segRB; } joint = seg.GetComponent <Joint>(); // we save segments as way points for the spline deformation. wayPoints.Add(seg); localSpacing += segmentSpacing; } UOUtility.Destroy(joint); }
private GameObject FindOrCreate(string name) { var childTransform = generated.transform.Find(name); GameObject res; if (childTransform == null) { res = UOUtility.Create(name, generated, typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshBender), typeof(MeshCollider)); res.isStatic = true; } else { res = childTransform.gameObject; } res.GetComponent <MeshRenderer>().material = material; res.GetComponent <MeshCollider>().material = physicMaterial; MeshBender mb = res.GetComponent <MeshBender>(); mb.Source = SourceMesh.Build(mesh) .Translate(translation) .Rotate(Quaternion.Euler(rotation)) .Scale(scale); mb.Mode = mode; return(res); }
private void GenerateMesh() { UOUtility.DestroyChildren(generated); int i = 0; float textureOffset = 0.0f; foreach (CubicBezierCurve curve in spline.GetCurves()) { GameObject go = UOUtility.Create("segment " + i++, generated, typeof(MeshFilter), typeof(MeshRenderer), typeof(ExtrusionSegment), typeof(MeshCollider)); go.isStatic = true; // TODO Changed go.GetComponent <MeshRenderer>().material = material; ExtrusionSegment mb = go.GetComponent <ExtrusionSegment>(); mb.ShapeVertices = shapeVertices; mb.TextureScale = textureScale; mb.TextureOffset = textureOffset; mb.SampleSpacing = sampleSpacing; mb.SetInterval(curve); textureOffset += curve.Length; } }
public void CreateMeshes() { var used = new List <GameObject>(); if (curveSpace) { int i = 0; foreach (var curve in spline.curves) { var go = FindOrCreate("segment " + i++ + " mesh"); go.GetComponent <MeshBender>().SetInterval(curve); go.GetComponent <MeshCollider>().enabled = generateCollider; used.Add(go); } } else { var go = FindOrCreate("segment 1 mesh"); go.GetComponent <MeshBender>().SetInterval(spline, 0); go.GetComponent <MeshCollider>().enabled = generateCollider; used.Add(go); } // we destroy the unused objects. This is classic pooling to recycle game objects. foreach (var go in generated.transform .Cast <Transform>() .Select(child => child.gameObject).Except(used)) { UOUtility.Destroy(go); } }
private GameObject FindOrCreate(string name) { var childTransform = generated.transform.Find(name); GameObject res; if (childTransform == null) { res = UOUtility.Create(name, generated, typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshBender), typeof(MeshCollider)); res.isStatic = !updateInPlayMode; } else { res = childTransform.gameObject; } res.GetComponent <MeshRenderer>().material = material; res.GetComponent <MeshCollider>().material = physicMaterial; MeshBender mb = res.GetComponent <MeshBender>(); mb.Source = SourceMesh.Build(mesh) .Translate(translation) .Rotate(Quaternion.Euler(rotation)) .Scale(scale); if (null != extraMeshes && 0 < extraMeshes.Length) { List <Material> materials = new List <Material>(); materials.Add(material); SourceMesh[] extraSourceMeshes = new SourceMesh[extraMeshes.Length]; for (int i = 0; i < extraMeshes.Length; ++i) { var T = translation; var R = rotation; var S = scale; if (extraMeshes[i].useCustomTRS) { T = extraMeshes[i].customTranslation; R = extraMeshes[i].customRotation; } extraSourceMeshes[i] = SourceMesh.Build(extraMeshes[i].mesh) .Translate(T) .Rotate(Quaternion.Euler(R)) .Scale(S); extraSourceMeshes[i].placeType = extraMeshes[i].placeType; extraSourceMeshes[i].placeWeight = extraMeshes[i].placeWeight; materials.Add(extraMeshes[i].material); } Array.Sort(extraSourceMeshes, (x, y) => (int)x.placeType - (int)y.placeType); mb.ExtraSources = extraSourceMeshes; res.GetComponent <MeshRenderer>().materials = materials.ToArray(); } mb.Mode = mode; return(res); }
public void CreateMeshes() { List <GameObject> used = new List <GameObject>(); for (int i = 0; i < spline.GetCurves().Count; i++) { var curve = spline.GetCurves()[i]; foreach (var tm in segments[i].transformedMeshes) { if (tm.mesh == null) { // if there is no mesh specified for this segment, we ignore it. continue; } // we try to find a game object previously generated. this avoids destroying/creating // game objects at each update, wich is faster. var childName = "segment " + i + " mesh " + segments[i].transformedMeshes.IndexOf(tm); var childTransform = generated.transform.Find(childName); GameObject go; if (childTransform == null) { go = UOUtility.Create(childName, generated, typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshBender), typeof(MeshCollider)); go.isStatic = true; } else { go = childTransform.gameObject; } go.GetComponent <MeshRenderer>().material = tm.material; go.GetComponent <MeshCollider>().material = tm.physicMaterial; // we update the data in the bender. It will decide itself if the bending must be recalculated. MeshBender mb = go.GetComponent <MeshBender>(); mb.Source = tm.mesh; mb.Curve = curve; mb.Translation = tm.translation; mb.Rotation = Quaternion.Euler(tm.rotation); mb.Scale = tm.scale; mb.ComputeIfNeeded(); used.Add(go); } } // finally, we destroy the unused objects foreach (var go in generated.transform .Cast <Transform>() .Select(child => child.gameObject).Except(used)) { UOUtility.Destroy(go); } }
public void CreateMeshes() { var used = new List <GameObject>(); if (curveSpace) { int i = 0; foreach (var curve in spline.curves) { if (collider) { i++; var coll = FindOrCreateCollider("segment " + i + " collider"); coll.GetComponent <MeshBender>().SetInterval(curve); used.Add(coll); var render = FindOrCreateRender("segment " + i + " collider", "segment " + i + " render"); render.GetComponent <MeshBender>().SetInterval(curve); render.transform.parent = coll.transform; used.Add(render); } else { var render = FindOrCreateRender("none", "segment " + i + " render"); render.GetComponent <MeshBender>().SetInterval(curve); used.Add(render); } } } else { if (collider) { var coll = FindOrCreateCollider("segment 1 collider"); coll.GetComponent <MeshBender>().SetInterval(spline, 0); used.Add(coll); var render = FindOrCreateRender("segment 1 collider", "segment 1 render"); render.GetComponent <MeshBender>().SetInterval(spline, 0); render.transform.parent = coll.transform; used.Add(render); } else { var render = FindOrCreateRender("none", "segment 1 render"); render.GetComponent <MeshBender>().SetInterval(spline, 0); used.Add(render); } } // we destroy the unused objects. This is classic pooling to recycle game objects. foreach (var go in generated.transform.Cast <Transform>().Select(child => child.gameObject).Except(used)) { UOUtility.Destroy(go); } }
public void Sow() { UOUtility.DestroyChildren(generated); UnityEngine.Random.InitState(randomSeed); if (spacing + spacingRange <= 0 || prefab == null) { return; } float distance = 0; while (distance <= spline.Length) { CurveSample sample = spline.GetSampleAtDistance(distance); GameObject go; if (Application.isPlaying) { go = Instantiate(prefab, generated.transform); } else { go = (GameObject)UnityEditor.PrefabUtility.InstantiatePrefab((UnityEngine.Object)prefab); go.transform.parent = generated.transform; } go.transform.localRotation = Quaternion.identity; go.transform.localPosition = Vector3.zero; go.transform.localScale = Vector3.one; // move along spline, according to spacing + random go.transform.localPosition = sample.location; // apply scale + random float rangedScale = scale + UnityEngine.Random.Range(0, scaleRange); go.transform.localScale = new Vector3(rangedScale, rangedScale, rangedScale); // rotate with random yaw if (isRandomYaw) { go.transform.Rotate(0, 0, UnityEngine.Random.Range(-180, 180)); } else { go.transform.rotation = sample.Rotation; } // move orthogonaly to the spline, according to offset + random Vector3 binormal = sample.tangent; binormal = Quaternion.LookRotation(Vector3.right, Vector3.up) * binormal; var localOffset = offset + UnityEngine.Random.Range(0, offsetRange * Math.Sign(offset)); localOffset *= sample.scale.x; binormal *= localOffset; go.transform.position += binormal; distance += spacing + UnityEngine.Random.Range(0, spacingRange); } }
private void OnEnable() { string generatedName = "generated by " + GetType().Name + GetInstanceID(); var generatedTranform = transform.Find(generatedName); generated = generatedTranform != null ? generatedTranform.gameObject : UOUtility.Create(generatedName, gameObject); spline = GetComponent <Spline>(); spline.NodeListChanged += (s, e) => toUpdate = true; }
private void OnEnable() { // tip : if you name all generated content in the same way, you can easily find all of it // at once in the scene view, with a single search. string generatedName = "generated by " + GetType().Name; var generatedTranform = transform.Find(generatedName); generated = generatedTranform != null ? generatedTranform.gameObject : UOUtility.Create(generatedName, gameObject); spline = GetComponentInParent <Spline>(); toUpdate = true; }
private void OnEnable() { string generatedName = "generated by " + GetType().Name; var generatedTranform = transform.Find(generatedName); generated = generatedTranform != null ? generatedTranform.gameObject : UOUtility.Create(generatedName, gameObject, typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshCollider)); spline = GetComponentInParent <Spline>(); spline.NodeListChanged += (s, e) => toUpdate = true; }
public void CreateMeshes() { UOUtility.DestroyChildren(generated); int i = 0; foreach (CubicBezierCurve curve in spline.GetCurves()) { GameObject go = UOUtility.Create("SplineMesh" + i++, generated, typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshBender)); go.GetComponent <MeshRenderer>().material = material; MeshBender mb = go.GetComponent <MeshBender>(); mb.Source = mesh; mb.Rotation = Quaternion.Euler(rotation); mb.Curve = curve; mb.ComputeIfNeeded(); } }
private void OnEnable() { string generatedName = "generated by " + GetType().Name; var generatedTranform = transform.Find(generatedName); generated = generatedTranform != null ? generatedTranform.gameObject : UOUtility.Create(generatedName, gameObject); spline = GetComponentInParent <Spline>(); spline.NodeListChanged += (s, e) => { toUpdate = true; foreach (CubicBezierCurve curve in spline.GetCurves()) { curve.Changed.AddListener(() => toUpdate = true); } }; foreach (CubicBezierCurve curve in spline.GetCurves()) { curve.Changed.AddListener(() => toUpdate = true); } }
private void GenerateMesh() { UOUtility.DestroyChildren(generated); int i = 0; foreach (CubicBezierCurve curve in spline.GetCurves()) { GameObject go = UOUtility.Create("segment " + i++, generated, typeof(MeshFilter), typeof(MeshRenderer), typeof(ExtrusionSegment), typeof(MeshCollider)); go.GetComponent <MeshRenderer>().material = material; ExtrusionSegment mb = go.GetComponent <ExtrusionSegment>(); mb.SetShapeVertices(shapeVertices, false); mb.SetTextureScale(textureScale, false); mb.SetCurve(curve, true); } }
private GameObject FindOrCreateRender(string parentName, string name) { var childTransform = generated.transform.Find(name); if (collider) { var parentTransform = generated.transform.Find(parentName); childTransform = parentTransform.Find(name); } GameObject res; if (childTransform == null) { res = UOUtility.Create(name, generated, typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshBender)); res.isStatic = true; } else { res = childTransform.gameObject; } res.GetComponent <MeshRenderer>().material = material; MeshBender mb = res.GetComponent <MeshBender>(); mb.Source = SourceMesh.Build(mesh) .Translate(translation) .Rotate(Quaternion.Euler(rotation)) .Scale(scale); if (mode == MeshBender.FillingMode.CustomIntervals) { mb.SetCustomInterval(customIntervalStart, customIntervalEnd); } mb.Mode = mode; return(res); }
public void CreateMeshes() { #if UNITY_EDITOR // we don't update if we are in prefab mode if (PrefabStageUtility.GetCurrentPrefabStage() != null) { return; } #endif var used = new List <GameObject>(); if (curveSpace) { int i = 0; foreach (var curve in spline.curves) { var go = FindOrCreate("segment " + i++ + " mesh"); go.GetComponent <MeshBender>().SetInterval(curve); go.GetComponent <MeshCollider>().enabled = generateCollider; used.Add(go); } } else { var go = FindOrCreate("segment 1 mesh"); go.GetComponent <MeshBender>().SetInterval(spline, 0); go.GetComponent <MeshCollider>().enabled = generateCollider; used.Add(go); } // we destroy the unused objects. This is classic pooling to recycle game objects. foreach (var go in generated.transform .Cast <Transform>() .Select(child => child.gameObject).Except(used).ToList()) { UOUtility.Destroy(go); } }
private void OnEnable() { string generatedName = "generated by " + GetType().Name + GetInstanceID(); var generatedTranform = transform.Find(generatedName); generated = generatedTranform != null ? generatedTranform.gameObject : UOUtility.Create(generatedName, gameObject); spline = GetComponent <Spline>(); // we listen changes in the spline's node list and we update the list of segment accordingly // this way, if we insert a node between two others, a segment will be inserted too and the data won't shift while (segments.Count < spline.nodes.Count) { segments.Add(new TrackSegment()); } while (segments.Count > spline.nodes.Count) { segments.RemoveAt(segments.Count - 1); } spline.NodeListChanged += (s, e) => { switch (e.type) { case ListChangeType.Add: segments.Add(new TrackSegment()); break; case ListChangeType.Remove: segments.RemoveAt(e.removeIndex); break; case ListChangeType.Insert: segments.Insert(e.insertIndex, new TrackSegment()); break; } toUpdate = true; }; toUpdate = true; }
protected void GenerateMesh() { UOUtility.DestroyChildren(generated); int i = 0; float textureOffset = 0.0f; foreach (CubicBezierCurve curve in spline.GetCurves()) { GameObject go = UOUtility.Create("segment " + i++, generated, typeof(MeshFilter), typeof(MeshRenderer), typeof(ExtrusionSegment), typeof(MeshCollider)); MeshRenderer goRenderer = go.GetComponent <MeshRenderer>(); goRenderer.material = material; ExtrusionSegment seg = go.GetComponent <ExtrusionSegment>(); seg.ShapeVertices = shapeVertices; seg.TextureScale = textureScale; seg.TextureOffset = textureOffset; seg.SampleSpacing = sampleSpacing; seg.SetInterval(curve); goRenderer.enabled = visible; if (go.TryGetComponent(out MeshCollider meshCollider)) { meshCollider.enabled = collisionEnabled; } int layerNum = LayerMask.NameToLayer(layer); if (layerNum > -1) { go.gameObject.layer = layerNum; } textureOffset += curve.Length; } }
private void Init() { for (int i = 0; i < meshes.Count; i++) { string generatedName = i + ". generated by " + GetType().Name; var generatedTranform = transform.Find(generatedName); GameObject generated = generatedTranform != null ? generatedTranform.gameObject : UOUtility.Create(generatedName, gameObject, typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshBender)); // some harmless bug TODO if (generatedList.Count < i + 1) { generatedList.Add(generated); } else { generatedList[i] = generated; } generatedList[i].GetComponent <MeshRenderer>().material = materials[i]; MeshBender meshBender = generatedList[i].GetComponent <MeshBender>(); if (meshBenders.Count < i + 1) { meshBenders.Add(meshBender); } else { meshBenders[i] = meshBender; } meshBenders[i] = generatedList[i].GetComponent <MeshBender>(); spline = GetComponent <Spline>(); meshBenders[i].Source = SourceMesh.Build(meshes[i]) .Translate(translations[i]) .Rotate(Quaternion.Euler(rotations[i])) .Scale(scales[i]); meshBenders[i].Mode = MeshBender.FillingMode.Repeat; meshBenders[i].SetInterval(spline, 0); } // First mesh determines lenght of generation contortionLength = meshBenders[0].Source.Length * ((float)(Repeat) + 0.1f); }
public void CreateMeshes() { for (int j = 0; j < numOfGeneratedMeshes; ++j) { Debug.Log("Regenerating mesh " + generated[j]); var used = new List <GameObject>(); if (curveSpace) { int i = 0; foreach (var curve in spline.curves) { //j = mesh number, e.g. 0 = render mesh, 1 = collision //i = segment of mesh Mesh mesh = null; Material mat = null; if (j == 0) { if (meshDataInternal[j].meshPrefabs[i].GetComponent <SplineMeshData>().renderMesh == null) { mesh = backupMesh; Debug.LogWarning("Can't find mesh - using backup"); } else { mesh = meshDataInternal[j].meshPrefabs[i].GetComponent <SplineMeshData>().renderMesh; } } else { if (meshDataInternal[j].meshPrefabs[i].GetComponent <SplineMeshData>().collisionMesh == null) { mesh = backupMesh; Debug.LogWarning("Can't find mesh - using backup"); } else { mesh = meshDataInternal[j].meshPrefabs[i].GetComponent <SplineMeshData>().collisionMesh; } } if (meshDataInternal[j].meshPrefabs[i].GetComponent <SplineMeshData>().material == null) { mat = backupMaterial; Debug.LogWarning("Can't find material - using backup"); } else { mat = meshDataInternal[j].meshPrefabs[i].GetComponent <SplineMeshData>().material; } var go = FindOrCreate("segment " + i++ + " mesh", mesh, mat, j); go.GetComponent <MeshBender>().SetInterval(curve); if (j == 0) { go.GetComponent <MeshCollider>().enabled = false; go.GetComponent <MeshRenderer>().enabled = true; } else { go.GetComponent <MeshCollider>().enabled = true; go.GetComponent <MeshRenderer>().enabled = false; } used.Add(go); } } else { var go = FindOrCreate("segment 1 mesh", backupMesh, backupMaterial, j); go.GetComponent <MeshBender>().SetInterval(spline, 0); go.GetComponent <MeshCollider>().enabled = true; go.GetComponent <MeshRenderer>().enabled = true; used.Add(go); } // we destroy the unused objects. This is classic pooling to recycle game objects. foreach (var go in generated[j].transform .Cast <Transform>() .Select(child => child.gameObject).Except(used)) { UOUtility.Destroy(go); } } }
private void OnEnable() { if (!allowMeshRegeneration) { return; } meshDataInternal = new MeshData[numOfGeneratedMeshes]; for (int i = 0; i < meshDataInternal.Length; ++i) { meshDataInternal[i].meshPrefabs = meshData.meshPrefabs; } if (lockMeshData == false) { //for (int i = 0; i < meshData.Length; ++i) //{ // //MeshData = meshData[i].meshPrefabs.GetComponent<SplineMeshData>().renderMesh; // //meshData[i].meshes = new Meshes[spline.curves.Count]; // //meshData[i].meshPrefabs = new Meshes[spline.curves.Count]; //} } generated = new GameObject[numOfGeneratedMeshes]; for (int j = 0; j < numOfGeneratedMeshes; ++j) { // tip : if you name all generated content in the same way, you can easily find all of it // at once in the scene view, with a single search. string generatedName = "generated by " + GetType().Name + j; var generatedTranform = transform.Find(generatedName); generated[j] = generatedTranform != null ? generatedTranform.gameObject : UOUtility.Create(generatedName, gameObject); spline = GetComponentInParent <Spline>(); spline.NodeListChanged += (s, e) => toUpdate = true; toUpdate = true; } }
public void CreateMeshes() { if (null == spline || null == meshInfos || 0 == meshInfos.Length) { return; } UpdateSourceMeshes(); UpdateDecisionParts(); string generatedName = "generated by " + GetType().Name; var generatedTranform = transform.Find(generatedName); generated = generatedTranform != null ? generatedTranform.gameObject : UOUtility.Create(generatedName, gameObject); generated.isStatic = false == updateInPlayMode; generated.layer = gameObject.layer; var generatedChildren = generated.transform.Cast <Transform>().ToList(); foreach (var child in generatedChildren) { if (null == child) { continue; } var meshCollider = child.GetComponent <MeshCollider>(); if (meshCollider) { meshCollider.enabled = false; } } var meshChunkDict = new Dictionary <Material, List <MeshChunk> >(); var sampleCache = new Dictionary <float, CurveSample>(); float offset = 0; for (int i = 0; i < decisionParts.Count; ++i) { int index = decisionParts[i]; if (false == meshChunkDict.ContainsKey(meshInfos[index].material)) { meshChunkDict.Add(meshInfos[index].material, new List <MeshChunk>()); } var meshChunkList = meshChunkDict[meshInfos[index].material]; int vertexCount = meshInfos[index].mesh.vertices.Length; bool isReachedMaxVertices = 0 < meshChunkList.Count && PerChunkMaxVertices < (meshChunkList.Last().bentVertices.Count + vertexCount); bool isReachedMaxLength = 0 < meshChunkList.Count && PerChunkMaxLength < meshChunkList.Last().length; if (0 == meshChunkList.Count || isReachedMaxVertices || isReachedMaxLength) { meshChunkList.Add(new MeshChunk() { bentVertices = new List <MeshVertex>(vertexCount), triangles = new List <int>(vertexCount / 3), uv = new List <Vector2> [8], length = 0 }); } var meshChunk = meshChunkList.Last(); ref SourceMesh sourceMesh = ref sourceMeshes[index]; meshChunk.triangles.AddRange(sourceMesh.Triangles.Select(idx => idx + meshChunk.bentVertices.Count)); List <Vector2> UV = new List <Vector2>(); for (int channel = 0; channel < 8; ++channel) { UV.Clear(); sourceMesh.Mesh.GetUVs(channel, UV); if (0 < UV.Count) { if (null == meshChunk.uv[channel]) { meshChunk.uv[channel] = new List <Vector2>(); } int fillCount = Mathf.Max(0, (meshChunk.bentVertices.Count - UV.Count) - meshChunk.uv[channel].Count); if (0 < fillCount) { meshChunk.uv[channel].AddRange(Enumerable.Repeat(Vector2.zero, fillCount)); } meshChunk.uv[channel].AddRange(UV); } } foreach (var vertex in sourceMesh.Vertices) { var vert = new MeshVertex(vertex.position, vertex.normal, vertex.uv); vert.position.x *= partsScale; float distance = vert.position.x - sourceMesh.MinX * partsScale + offset; distance = Mathf.Clamp(distance, 0, spline.Length); CurveSample sample; if (false == sampleCache.TryGetValue(distance, out sample)) { sample = spline.GetSampleAtDistance(distance); if (heightSync) { var sampleLocationWS = spline.transform.TransformPoint(sample.location); RaycastHit hitInfo; if (Physics.Raycast(sampleLocationWS + Vector3.up * heightSyncTraceRange, -Vector3.up, out hitInfo, heightSyncTraceRange * 2, heightSyncLayerMask)) { var newSampleLocation = spline.transform.InverseTransformPoint(hitInfo.point); var newSampleUp = heightNormalSync ? spline.transform.InverseTransformDirection(hitInfo.normal) : sample.up; sample = new CurveSample(newSampleLocation, sample.tangent, newSampleUp, sample.scale, sample.roll, sample.distanceInCurve, sample.timeInCurve, sample.curve); } } sampleCache.Add(distance, sample); } MeshVertex bentVertex = sample.GetBent(vert); meshChunk.bentVertices.Add(bentVertex); } offset += sourceMeshes[index].Length * partsScale; meshChunk.length += sourceMeshes[index].Length * partsScale; }
private void OnEnable() { string generatedName = "generated by " + GetType().Name; var generatedTranform = transform.Find(generatedName); generated = generatedTranform != null ? generatedTranform.gameObject : UOUtility.Create(generatedName, gameObject); generated.hideFlags = HideFlags.DontSave | HideFlags.NotEditable | HideFlags.HideInInspector | HideFlags.HideInHierarchy; spline = GetComponentInParent <Spline>(); if (spline == null) { return; } spline.NodeListChanged += (s, e) => toUpdate = true; }
public void Sow() { UOUtility.DestroyChildren(generated); UnityEngine.Random.InitState(randomSeed); if (spacing + spacingRange <= 0 || prefab == null) { return; } float distance = 0; while (distance <= spline.Length) { CurveSample sample = spline.GetSampleAtDistance(distance); if (heightSync) { var sampleLocationWS = spline.transform.TransformPoint(sample.location); RaycastHit hitInfo; if (Physics.Raycast(sampleLocationWS + Vector3.up * heightSyncTraceRange, -Vector3.up, out hitInfo, heightSyncTraceRange * 2, heightSyncLayerMask)) { var newSampleLocation = spline.transform.InverseTransformPoint(hitInfo.point); var newSampleUp = heightNormalSync ? spline.transform.InverseTransformDirection(hitInfo.normal) : sample.up; sample = new CurveSample(newSampleLocation, sample.tangent, newSampleUp, sample.scale, sample.roll, sample.distanceInCurve, sample.timeInCurve, sample.curve); } } GameObject go; go = Instantiate(prefab, generated.transform); go.transform.localRotation = Quaternion.identity; go.transform.localPosition = Vector3.zero; go.transform.localScale = Vector3.one; go.isStatic = false == updateInPlayMode; go.layer = gameObject.layer; foreach (var child in go.transform.Cast <Transform>()) { child.gameObject.layer = go.layer; } // move along spline, according to spacing + random go.transform.localPosition = sample.location; // apply scale + random float rangedScale = scale + UnityEngine.Random.Range(0, scaleRange); go.transform.localScale = new Vector3(rangedScale, rangedScale, rangedScale); // rotate with random yaw if (isRandomYaw) { go.transform.Rotate(0, 0, UnityEngine.Random.Range(-180, 180)); } else { go.transform.rotation = sample.Rotation; } // move orthogonaly to the spline, according to offset + random var binormal = (Quaternion.LookRotation(sample.tangent, sample.up) * Vector3.right).normalized; var localWidthOffset = widthOffset + UnityEngine.Random.Range(0, widthOffsetRange * Math.Sign(widthOffset)); var localHeightOffset = heightOffset + UnityEngine.Random.Range(0, heightOffsetRange * Math.Sign(heightOffset)); localWidthOffset *= sample.scale.x; binormal *= localWidthOffset; go.transform.position += binormal + sample.up * localHeightOffset; distance += spacing + UnityEngine.Random.Range(0, spacingRange); } }
private void CreateMeshes() { if (null == spline) { return; } string generatedName = "generated by " + GetType().Name; var generatedTranform = transform.Find(generatedName); generated = generatedTranform != null ? generatedTranform.gameObject : UOUtility.Create(generatedName, gameObject); generated.isStatic = false == updateInPlayMode; generated.layer = gameObject.layer; var generatedChildren = generated.transform.Cast <Transform>().ToList(); foreach (var child in generatedChildren) { if (null == child) { continue; } var meshCollider = child.GetComponent <MeshCollider>(); if (meshCollider) { meshCollider.enabled = false; } } List <MeshVertex> sourceVertices = new List <MeshVertex>(2 + Mathf.Max(0, slice - 1)); float x_start = offset - width / 2; float x_end = offset + width / 2; sourceVertices.Add(new MeshVertex(new Vector3(0, 0, x_start), Vector3.up, new Vector2(+textureOffsetScale.x, 0))); for (int step = 1; step < slice; ++step) { float t = (float)step / (float)slice; float x = Mathf.Lerp(x_start, x_end, t); sourceVertices.Add(new MeshVertex(new Vector3(0, 0, x), Vector3.up, new Vector2(t / textureOffsetScale.z + textureOffsetScale.x, 0))); } sourceVertices.Add(new MeshVertex(new Vector3(0, 0, x_end), Vector3.up, new Vector2(1 / textureOffsetScale.z + textureOffsetScale.x, 0))); if (Mathf.Approximately(sampleSpacing, 0) || sampleSpacing <= 0) { Debug.LogError("Not enough sampleSpcaing. (must be greater than zero)"); return; } int lineCount = 0; List <MeshVertex> bentVertices = new List <MeshVertex>(); for (float d = 0.0f; d <= spline.Length; d += sampleSpacing) { var sample = spline.GetSampleAtDistance(d); if (heightSync) { var sampleLocationWS = spline.transform.TransformPoint(sample.location); RaycastHit hitInfo; if (Physics.Raycast(sampleLocationWS + Vector3.up * heightSyncTraceRange, -Vector3.up, out hitInfo, heightSyncTraceRange * 2, heightSyncLayerMask)) { var newSampleLocation = spline.transform.InverseTransformPoint(hitInfo.point); sample = new CurveSample(newSampleLocation, sample.tangent, sample.up, sample.scale, sample.roll, sample.distanceInCurve, sample.timeInCurve, sample.curve); } } for (int i = 0; i < sourceVertices.Count; ++i) { var bentVertex = sample.GetBent(sourceVertices[i]); bentVertex.normal = sample.up; if (heightSync) { var bentWS = spline.transform.TransformPoint(bentVertex.position); RaycastHit hitInfo; if (Physics.Raycast(bentWS + Vector3.up * heightSyncTraceRange, -Vector3.up, out hitInfo, heightSyncTraceRange * 2, heightSyncLayerMask)) { bentVertex.position = spline.transform.InverseTransformPoint(hitInfo.point); if (heightNormalSync) { bentVertex.normal = spline.transform.InverseTransformDirection(hitInfo.normal); } } } bentVertex.uv.y = (d / width) / textureOffsetScale.w + textureOffsetScale.y; bentVertices.Add(bentVertex); } ++lineCount; } if (1 >= lineCount) { Debug.LogError("Not enough line length"); return; } List <Transform> newGeneratedTransform = new List <Transform>(); int baseIndex = 0; int lineVerticesCount = 2 + Mathf.Max(0, slice - 1); List <int> triangles = new List <int>((lineVerticesCount - 1) * (lineCount - 1) * 2); for (int i = 0; i < lineCount - 1; ++i) { int nextBaseIndex = baseIndex + lineVerticesCount; for (int v = 0; v < lineVerticesCount - 1; ++v) { int[] vertices = new int[] { baseIndex + v, baseIndex + v + 1, nextBaseIndex + v, nextBaseIndex + v + 1 }; triangles.Add(vertices[0]); triangles.Add(vertices[1]); triangles.Add(vertices[2]); triangles.Add(vertices[2]); triangles.Add(vertices[1]); triangles.Add(vertices[3]); } bool isOverVertices = nextBaseIndex + lineVerticesCount > PerSegmentMaxVertices; bool isEndLine = (i == lineCount - 2); bool needGenerateSegment = isOverVertices || isEndLine; if (needGenerateSegment) { string segmentName = $"{name}-{material.name}-{newGeneratedTransform.Count + 1}"; Transform segmentTransform = generated.transform.Find(segmentName); if (null == segmentTransform) { var go = UOUtility.Create(segmentName, generated, typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshCollider)); segmentTransform = go.transform; } segmentTransform.gameObject.isStatic = generated.isStatic; segmentTransform.gameObject.layer = generated.layer; newGeneratedTransform.Add(segmentTransform); generatedChildren.Remove(segmentTransform); var meshFilter = segmentTransform.GetComponent <MeshFilter>(); var meshRenderer = segmentTransform.GetComponent <MeshRenderer>(); var meshCollider = segmentTransform.GetComponent <MeshCollider>(); Mesh mesh = meshFilter.sharedMesh; if (null == mesh || mesh.name != segmentName) { mesh = new Mesh(); } else if (mesh.vertexCount != bentVertices.Count) { mesh.Clear(); } mesh.name = segmentName; mesh.hideFlags = HideFlags.HideInHierarchy; mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt16; var segmentBentVertices = bentVertices.GetRange(0, nextBaseIndex + lineVerticesCount); mesh.SetVertices(segmentBentVertices.Select(b => b.position).ToList()); mesh.SetNormals(segmentBentVertices.Select(b => b.normal).ToList()); mesh.SetUVs(0, segmentBentVertices.Select(b => b.uv).ToList()); mesh.SetTriangles(triangles, 0, false); mesh.RecalculateBounds(); mesh.RecalculateTangents(); meshFilter.sharedMesh = mesh; meshRenderer.material = material; meshCollider.sharedMesh = mesh; meshCollider.enabled = generateCollider; triangles.Clear(); bentVertices.RemoveRange(0, nextBaseIndex); nextBaseIndex = 0; } baseIndex = nextBaseIndex; } foreach (var deprecatedTransform in generatedChildren) { if (deprecatedTransform != null) { UOUtility.Destroy(deprecatedTransform.gameObject); } } }