public SplineMesh.CurveSample ClosestTrackSample(SplineMesh.Spline track) { int segmentA = raceController.GetTrackSegment(CarInfo?.name); int segmentB = -1; if (segmentA < 0) { segmentA = 0; segmentB = raceController.GetNumSegments(); } else { segmentB = raceController.NextSegment(segmentA); } float begin = Math.Max(0, raceController.TrackDistanceAtSegment(segmentA)); float end = Math.Max(0, raceController.TrackDistanceAtSegment(segmentB)); var closest = track.GetSampleAtDistance(begin); float closestDistance = float.MaxValue; for (float i = begin; i < end; i += 0.05f) { var curveSample = track.GetSampleAtDistance(i); var d = (gameObject.transform.position - 0.048f * Vector3.up - curveSample.location); d.y *= 10; var distance = d.magnitude; if (distance < closestDistance) { closestDistance = distance; closest = curveSample; } } return(closest); }
Vector3 GetPosition(float aLength) { if (line.useWorldSpace) { return(transform.TransformPoint(spline.GetSampleAtDistance(aLength).location)); } else { return(spline.GetSampleAtDistance(aLength).location); } }
private void FillOnce() { sampleCache.Clear(); var bentVertices = new List <MeshVertex>(source.Vertices.Count); // for each mesh vertex, we found its projection on the curve foreach (var vert in source.Vertices) { float distance = vert.position.x - source.MinX; CurveSample sample; if (!sampleCache.TryGetValue(distance, out sample)) { if (!useSpline) { if (distance > curve.Length) { distance = curve.Length; } sample = curve.GetSampleAtDistance(distance); } else { float distOnSpline = intervalStart + distance; if (distOnSpline > spline.Length) { if (spline.IsLoop) { while (distOnSpline > spline.Length) { distOnSpline -= spline.Length; } } else { distOnSpline = spline.Length; } } sample = spline.GetSampleAtDistance(distOnSpline); } sampleCache[distance] = sample; } bentVertices.Add(sample.GetBent(vert)); } MeshUtility.Update(result, source.Mesh, source.Triangles, bentVertices.Select(b => b.position), bentVertices.Select(b => b.normal)); }
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); } }
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); } }
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 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); } } }