/// <summary> /// Create collections of groups sharing same Material ID. Also ensures collection's MaterialID is valid! /// </summary> /// <param name="groups"></param> /// <returns></returns> List <SamplePointsMaterialGroupCollection> getMaterialIDGroups(CGVolume volume) { var matCollections = new Dictionary <int, SamplePointsMaterialGroupCollection>(); SamplePointsMaterialGroupCollection col; for (int g = 0; g < volume.CrossMaterialGroups.Count; g++) { int matID = Mathf.Min(volume.CrossMaterialGroups[g].MaterialID, MaterialCount - 1); if (!matCollections.TryGetValue(matID, out col)) { col = new SamplePointsMaterialGroupCollection(); col.MaterialID = matID; matCollections.Add(matID, col); } col.Add(volume.CrossMaterialGroups[g]); } var res = new List <SamplePointsMaterialGroupCollection>(); foreach (var item in matCollections.Values) { item.CalculateAspectCorrection(volume, MaterialSetttings[item.MaterialID]); res.Add(item); } return(res); }
void build(CGVMesh vmesh, CGVolume vol, IntRegion subset) { // Because each Material ID forms a submesh // Do we need to calculate localU? if (GenerateUV) { System.Array.Resize <Vector2>(ref vmesh.UV, vmesh.Count); } // Prepare Submeshes prepareSubMeshes(vmesh, groupsByMatID, subset.Length, ref m_Material); //prepareSubMeshes(vmesh, groupsByMatID, vol.Count - 1, ref m_Material); SamplePointsMaterialGroupCollection col; SamplePointsMaterialGroup grp; int vtIdx = 0; int[] triIdx = new int[groupsByMatID.Count]; // triIdx for each submesh // for all sample segments (except the last) along the path, create Triangles to the next segment for (int sample = subset.From; sample < subset.To; sample++) { // for each submesh (collection) for (int subMeshIdx = 0; subMeshIdx < groupsByMatID.Count; subMeshIdx++) { col = groupsByMatID[subMeshIdx]; // create UV and triangles for all groups in submesh for (int g = 0; g < col.Count; g++) { grp = col[g]; if (GenerateUV) { createMaterialGroupUV(ref vmesh, ref vol, ref grp, col.MaterialID, col.AspectCorrection, sample, vtIdx); } for (int p = 0; p < grp.Patches.Count; p++) { createPatchTriangles(ref vmesh.SubMeshes[subMeshIdx].Triangles, ref triIdx[subMeshIdx], vtIdx + grp.Patches[p].Start, grp.Patches[p].Count, vol.CrossSize, ReverseTriOrder); } } } vtIdx += vol.CrossSize; } // UV for last path segment if (GenerateUV) { // for each submesh (collection) for (int subMeshIdx = 0; subMeshIdx < groupsByMatID.Count; subMeshIdx++) { col = groupsByMatID[subMeshIdx]; // create triangles for (int g = 0; g < col.Count; g++) { grp = col[g]; createMaterialGroupUV(ref vmesh, ref vol, ref grp, col.MaterialID, col.AspectCorrection, subset.To, vtIdx); } } } }
public void GetLengths(CGVolume volume, out float worldLength, out float uLength) { worldLength = 0; for (int v = StartVertex; v < EndVertex; v++) { worldLength += (volume.Vertex[v + 1] - volume.Vertex[v]).magnitude; } uLength = volume.CrossMap[EndVertex] - volume.CrossMap[StartVertex]; }
/*! \cond PRIVATE */ Matrix4x4 getMat(CGVolume vol, int index, bool inverse) { if (inverse) { var Q = Quaternion.LookRotation(vol.Direction[index], vol.Normal[index]); return(Matrix4x4.TRS(vol.Position[index], Q, Vector3.one)); } else { var Q = Quaternion.Inverse(Quaternion.LookRotation(vol.Direction[index], vol.Normal[index])); return(Matrix4x4.TRS(-(Q * vol.Position[index]), Q, Vector3.one)); } }
/// <summary> /// trs vertices to eliminate Z and eleminate duplicates /// </summary> ContourVertex[] make2DSegment(CGVolume vol, int index) { Matrix4x4 m = getMat(vol, index, false); int idx = vol.GetSegmentIndex(index); ContourVertex[] res = new ContourVertex[vol.CrossSize]; for (int i = 0; i < vol.CrossSize; i++) { res[i] = m.MultiplyPoint(vol.Vertex[idx + i]).ContourVertex(); } return(res); }
public void CalculateAspectCorrection(CGVolume volume, CGMaterialSettingsEx matSettings) { float totalLength = 0; float totalULength = 0; float l, u; for (int g = 0; g < Count; g++) { this[g].GetLengths(volume, out l, out u); totalLength += l; totalULength += u; } AspectCorrection = volume.Length / (totalLength / totalULength); /* * float crossLength = volume.GetCrossLength(0); * for (int g = 0; g < Count; g++) * { * // Calculate local U * if (matSettings.LocalU) * this[g].CalculateLocalINTERNAL(volume); * // Aspect correction * this[g].AspectCorrectionU = 1; * this[g].AspectCorrectionV = 1; * switch (matSettings.KeepAspect) * { * case CGKeepAspectMode.ScaleU: * if (matSettings.LocalU) * this[g].AspectCorrectionU = this[g].LocalLength / volume.Length; * else * this[g].AspectCorrectionU = crossLength / volume.Length; * break; * case CGKeepAspectMode.ScaleV: * if (matSettings.LocalU) * this[g].AspectCorrectionV = volume.Length / this[g].LocalLength; * else * this[g].AspectCorrectionV = volume.Length / crossLength; * break; * } * } * * */ }
public void CalculateAspectCorrection(CGVolume volume, CGMaterialSettingsEx matSettings) { if (matSettings.KeepAspect == CGKeepAspectMode.Off) { AspectCorrection = 1; } else { float totalLength = 0; float totalULength = 0; float l, u; for (int g = 0; g < Count; g++) { this[g].GetLengths(volume, out l, out u); totalLength += l; totalULength += u; } AspectCorrection = volume.Length / (totalLength / totalULength); } }
// OPTIMIZE: Store array of U values and just copy them void createMaterialGroupUV(ref CGVMesh vmesh, ref CGVolume vol, ref SamplePointsMaterialGroup grp, int matIndex, float grpAspectCorrection, int sample, int baseVertex) { var mat = m_MaterialSettings[matIndex]; float v = mat.UVOffset.y + vol.F[sample] * mat.UVScale.y * grpAspectCorrection; float u; int hi = grp.EndVertex; for (int c = grp.StartVertex; c <= hi; c++) { u = mat.UVOffset.x + vol.CrossMap[c] * mat.UVScale.x; if (mat.SwapUV) { vmesh.UV[baseVertex + c] = new Vector2(v, u); } else { vmesh.UV[baseVertex + c] = new Vector2(u, v); } } }
/// <summary> /// trs vertices to eliminate Z and eleminate duplicates /// </summary> Vector3[] make2DSegment(CGVolume vol, int index) { Matrix4x4 m = getMat(vol, index, false); Vector3[] vertices = vol.GetSegmentVertices(index); HashSet <Vector3> hash = new HashSet <Vector3>(); List <Vector3> res = new List <Vector3>(vertices.Length); Vector3 v; Vector3 l = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); for (int i = 0; i < vertices.Length; i++) { v = m.MultiplyPoint(vertices[i]); if ((v - l).sqrMagnitude > 0.001f && hash.Add(v)) { res.Add(v); } l = v; } return(res.ToArray()); }
Matrix4x4 getMat(CGVolume vol, int index, bool inverse) { if (inverse) { var Q = Quaternion.LookRotation(vol.Direction[index], vol.Normal[index]); return Matrix4x4.TRS(vol.Position[index], Q, Vector3.one); } else { var Q = Quaternion.Inverse(Quaternion.LookRotation(vol.Direction[index], vol.Normal[index])); return Matrix4x4.TRS(-(Q * vol.Position[index]), Q, Vector3.one); } }
// OPTIMIZE: Store array of U values and just copy them void createMaterialGroupUV(ref CGVMesh vmesh, ref CGVolume vol, ref SamplePointsMaterialGroup grp, int matIndex, float grpAspectCorrection, int sample, int baseVertex) { var mat = m_MaterialSettings[matIndex]; float v = mat.UVOffset.y + vol.F[sample] * mat.UVScale.y * grpAspectCorrection; float u; int hi = grp.EndVertex; for (int c = grp.StartVertex; c <= hi; c++) { u = mat.UVOffset.x + vol.CrossMap[c] * mat.UVScale.x; if (mat.SwapUV) vmesh.UV[baseVertex+c] = new Vector2(v, u); else vmesh.UV[baseVertex+c] = new Vector2(u, v); } }
/// <summary> /// Create collections of groups sharing same Material ID. Also ensures collection's MaterialID is valid! /// </summary> /// <param name="groups"></param> /// <returns></returns> List<SamplePointsMaterialGroupCollection> getMaterialIDGroups(CGVolume volume) { var matCollections = new Dictionary<int, SamplePointsMaterialGroupCollection>(); SamplePointsMaterialGroupCollection col; for (int g = 0; g < volume.CrossMaterialGroups.Count;g++) { int matID = Mathf.Min(volume.CrossMaterialGroups[g].MaterialID,MaterialCount-1); if (!matCollections.TryGetValue(matID,out col)) { col = new SamplePointsMaterialGroupCollection(); col.MaterialID = matID; matCollections.Add(matID,col); } col.Add(volume.CrossMaterialGroups[g]); } var res = new List<SamplePointsMaterialGroupCollection>(); foreach (var item in matCollections.Values) { item.CalculateAspectCorrection(volume, MaterialSetttings[item.MaterialID]); res.Add(item); } return res; }
/*! \endcond */ #endregion #region ### Public Methods ### public override void Refresh() { base.Refresh(); CGVolume vol = InVolume.GetData <CGVolume>(); var holes = InVolumeHoles.GetAllData <CGVolume>(); if (vol) { bool genStart = (StartCap == CGYesNoAuto.Yes || (StartCap == CGYesNoAuto.Auto && !vol.Seamless)); bool genEnd = (EndCap == CGYesNoAuto.Yes || (EndCap == CGYesNoAuto.Auto && !vol.Seamless)); if (!genStart && !genEnd) { OutVMesh.SetData(null); return; } var vmesh = new CGVMesh(); Vector3[] vtStart = new Vector3[0]; Vector3[] vtEnd = new Vector3[0]; Polygon pOuter; vmesh.AddSubMesh(new CGVSubMesh()); CGVSubMesh submesh = vmesh.SubMeshes[0]; Vector3[] points; if (genStart) { #region --- Start Cap --- points = make2DSegment(vol, 0); if (points.Length < 3) { OutVMesh.SetData(null); UIMessages.Add("Cross has <3 Vertices: Can't create Caps!"); return; } pOuter = new Polygon(points); for (int h = 0; h < holes.Count; h++) { points = make2DSegment(holes[h], 0); if (points.Length < 3) { OutVMesh.SetData(null); UIMessages.Add("Hole Cross has <3 Vertices: Can't create Caps!"); return; } pOuter.AddHole(new Polygon(points)); } try { P2T.Triangulate(pOuter); } catch (System.Exception e) { Debug.LogException(e); OutVMesh.SetData(null); return; } submesh.Material = StartMaterial; pOuter.GetResults(out vtStart, out submesh.Triangles, ReverseTriOrder); vmesh.Vertex = applyMat(vtStart, getMat(vol, 0, true)); if (GenerateUV) { vmesh.UV = new Vector2[vtStart.Length]; applyUV(vtStart, ref vmesh.UV, 0, vtStart.Length, pOuter.Bounds.Bounds, StartMaterialSettings); } #endregion } if (genEnd) { #region --- End Cap --- points = make2DSegment(vol, vol.Count - 1); if (points.Length < 3) { OutVMesh.SetData(null); UIMessages.Add("Cross has <3 Vertices: Can't create Caps!"); return; } pOuter = new Polygon(points); for (int h = 0; h < holes.Count; h++) { points = make2DSegment(holes[h], holes[h].Count - 1); if (points.Length < 3) { OutVMesh.SetData(null); UIMessages.Add("Hole Cross has <3 Vertices: Can't create Caps!"); return; } pOuter.AddHole(new Polygon(points)); } try { P2T.Triangulate(pOuter); } catch (System.Exception e) { Debug.LogException(e); OutVMesh.SetData(null); return; } int[] tris; pOuter.GetResults(out vtEnd, out tris, !ReverseTriOrder, vtStart.Length); vmesh.Vertex = vmesh.Vertex.AddRange <Vector3>(applyMat(vtEnd, getMat(vol, vol.Count - 1, true))); if (!CloneStartCap && StartMaterial != EndMaterial) { vmesh.AddSubMesh(new CGVSubMesh(tris, EndMaterial)); } else { submesh.Material = StartMaterial; submesh.Triangles = submesh.Triangles.AddRange <int>(tris); } if (GenerateUV) { System.Array.Resize <Vector2>(ref vmesh.UV, vmesh.UV.Length + vtEnd.Length); applyUV(vtEnd, ref vmesh.UV, vtStart.Length, vtEnd.Length, pOuter.Bounds.Bounds, (CloneStartCap) ? StartMaterialSettings : EndMaterialSettings); } #endregion } OutVMesh.SetData(vmesh); } }
/*! \cond PRIVATE */ void prepare(CGVolume vol) { // We have groups (different MaterialID) of patches (e.g. by Hard Edges). // Create Collection of groups sharing the same material ID groupsByMatID = getMaterialIDGroups(vol); }
/// <summary> /// trs vertices to eliminate Z and eleminate duplicates /// </summary> Vector3[] make2DSegment(CGVolume vol, int index) { Matrix4x4 m = getMat(vol, index, false); Vector3[] vertices = vol.GetSegmentVertices(index); HashSet<Vector3> hash = new HashSet<Vector3>(); List<Vector3> res = new List<Vector3>(vertices.Length); Vector3 v; Vector3 l = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); for (int i = 0; i < vertices.Length; i++) { v = m.MultiplyPoint(vertices[i]); if ((v - l).sqrMagnitude > 0.001f && hash.Add(v)) res.Add(v); l = v; } return res.ToArray(); }
void build(CGVMesh vmesh, CGVolume vol, IntRegion subset) { // Because each Material ID forms a submesh // Do we need to calculate localU? if (GenerateUV) { System.Array.Resize<Vector2>(ref vmesh.UV, vmesh.Count); } // Prepare Submeshes prepareSubMeshes(vmesh, groupsByMatID, subset.Length, ref m_Material); //prepareSubMeshes(vmesh, groupsByMatID, vol.Count - 1, ref m_Material); SamplePointsMaterialGroupCollection col; SamplePointsMaterialGroup grp; int vtIdx = 0; int[] triIdx = new int[groupsByMatID.Count]; // triIdx for each submesh // for all sample segments (except the last) along the path, create Triangles to the next segment for (int sample = subset.From; sample < subset.To; sample++) { // for each submesh (collection) for (int subMeshIdx = 0; subMeshIdx < groupsByMatID.Count; subMeshIdx++) { col = groupsByMatID[subMeshIdx]; // create UV and triangles for all groups in submesh for (int g = 0; g < col.Count; g++) { grp = col[g]; if (GenerateUV) createMaterialGroupUV(ref vmesh, ref vol, ref grp, col.MaterialID, col.AspectCorrection, sample, vtIdx); for (int p = 0; p < grp.Patches.Count; p++) createPatchTriangles(ref vmesh.SubMeshes[subMeshIdx].Triangles, ref triIdx[subMeshIdx], vtIdx+grp.Patches[p].Start, grp.Patches[p].Count, vol.CrossSize, ReverseTriOrder); } } vtIdx += vol.CrossSize; } // UV for last path segment if (GenerateUV) { // for each submesh (collection) for (int subMeshIdx = 0; subMeshIdx < groupsByMatID.Count; subMeshIdx++) { col = groupsByMatID[subMeshIdx]; // create triangles for (int g = 0; g < col.Count; g++) { grp = col[g]; createMaterialGroupUV(ref vmesh, ref vol, ref grp, col.MaterialID, col.AspectCorrection, subset.To, vtIdx); } } } }
/*! \endcond */ #endregion #region ### Public Methods ### public override void Refresh() { base.Refresh(); if (Length == 0) { Reset(); } else { var req = new List <CGDataRequestParameter>(); req.Add(new CGDataRequestRasterization(this.From, this.Length, CGUtility.CalculateSamplePointsCacheSize(Resolution, InPath.SourceSlot().OnRequestPathModule.PathLength *this.Length), AngleThreshold, (Optimize) ? CGDataRequestRasterization.ModeEnum.Optimized : CGDataRequestRasterization.ModeEnum.Even)); var path = InPath.GetData <CGPath>(req.ToArray()); req.Clear(); req.Add(new CGDataRequestRasterization(this.CrossFrom, this.CrossLength, CGUtility.CalculateSamplePointsCacheSize(CrossResolution, InCross.SourceSlot().OnRequestPathModule.PathLength *this.CrossLength), CrossAngleThreshold, (CrossOptimize) ? CGDataRequestRasterization.ModeEnum.Optimized : CGDataRequestRasterization.ModeEnum.Even)); if (CrossIncludeControlPoints || CrossHardEdges || CrossMaterials) { req.Add(new CGDataRequestMetaCGOptions(CrossHardEdges, CrossMaterials, CrossIncludeControlPoints, CrossExtendedUV)); } var cross = InCross.GetData <CGShape>(req.ToArray()); if (!path || !cross || path.Count == 0 || cross.Count == 0) { OutVolume.ClearData(); OutVolumeHollow.ClearData(); return; } var vol = CGVolume.Get(OutVolume.GetData <CGVolume>(), path, cross); var volHollow = (OutVolumeHollow.IsLinked) ? CGVolume.Get(OutVolumeHollow.GetData <CGVolume>(), path, cross) : null; PathSamples = path.Count; CrossSamples = cross.Count; CrossGroups = cross.MaterialGroups.Count; CrossPosition = vol.Position[0]; CrossRotation = Quaternion.LookRotation(vol.Direction[0], vol.Normal[0]); Vector3 baseScale = (ScaleUniform) ? new Vector3(ScaleX, ScaleX, 1) : new Vector3(ScaleX, ScaleY, 1); Vector3 scl = baseScale; int vtIdx = 0; float[] scaleFArray = (ScaleReference == CGReferenceMode.Source) ? path.SourceF : path.F; Matrix4x4 mat; Matrix4x4 matHollow; Quaternion R; int crossNormalMul = (CrossReverseNormals) ? -1 : 1; int hollowNormalMul = (HollowReverseNormals) ? -1 : 1; for (int sample = 0; sample < path.Count; sample++) { R = Quaternion.LookRotation(path.Direction[sample], path.Normal[sample]); getScaleInternal(scaleFArray[sample], baseScale, ref scl); mat = Matrix4x4.TRS(path.Position[sample], R, scl); if (volHollow == null) { for (int c = 0; c < cross.Count; c++) { vol.Vertex[vtIdx] = mat.MultiplyPoint(cross.Position[c]); vol.VertexNormal[vtIdx++] = R * cross.Normal[c] * crossNormalMul; } } else { matHollow = Matrix4x4.TRS(path.Position[sample], R, scl * (1 - HollowInset)); for (int c = 0; c < cross.Count; c++) { vol.Vertex[vtIdx] = mat.MultiplyPoint(cross.Position[c]); vol.VertexNormal[vtIdx] = R * cross.Normal[c]; volHollow.Vertex[vtIdx] = matHollow.MultiplyPoint(cross.Position[c]); volHollow.VertexNormal[vtIdx] = vol.VertexNormal[vtIdx++] * hollowNormalMul; } } } switch (CrossShiftMode) { case CrossShiftModeEnum.ByOrientation: // shift CrossF to match Path Orientation Vector2 hit; float frag; for (int i = 0; i < cross.Count - 1; i++) { if (DTMath.RayLineSegmentIntersection(vol.Position[0], vol.VertexNormal[0], vol.Vertex[i], vol.Vertex[i + 1], out hit, out frag)) { vol.CrossFShift = DTMath.SnapPrecision(vol.CrossF[i] + (vol.CrossF[i + 1] - vol.CrossF[i]) * frag, 2); break; } } if (vol.CrossClosed && DTMath.RayLineSegmentIntersection(vol.Position[0], vol.VertexNormal[0], vol.Vertex[cross.Count - 1], vol.Vertex[0], out hit, out frag)) { vol.CrossFShift = DTMath.SnapPrecision(vol.CrossF[cross.Count - 1] + (vol.CrossF[0] - vol.CrossF[cross.Count - 1]) * frag, 2); } break; case CrossShiftModeEnum.Custom: vol.CrossFShift = CrossShiftValue; break; default: vol.CrossFShift = 0; break; } if (volHollow != null) { volHollow.CrossFShift = vol.CrossFShift; } OutVolume.SetData(vol); OutVolumeHollow.SetData(volHollow); } }
/*! \endcond */ #endregion #region ### Public Methods ### public override void Refresh() { base.Refresh(); CGVolume vol = InVolume.GetData <CGVolume>(); var holes = InVolumeHoles.GetAllData <CGVolume>(); if (vol) { bool genStart = (StartCap == CGYesNoAuto.Yes || (StartCap == CGYesNoAuto.Auto && !vol.Seamless)); bool genEnd = (EndCap == CGYesNoAuto.Yes || (EndCap == CGYesNoAuto.Auto && !vol.Seamless)); if (!genStart && !genEnd) { OutVMesh.SetData(null); return; } var vmesh = new CGVMesh(); Vector3[] vtStart = new Vector3[0]; Vector3[] vtEnd = new Vector3[0]; vmesh.AddSubMesh(new CGVSubMesh()); CGVSubMesh submesh = vmesh.SubMeshes[0]; if (genStart) { #region --- Start Cap --- var tess = new Tess(); tess.UsePooling = true; tess.AddContour(make2DSegment(vol, 0)); for (int h = 0; h < holes.Count; h++) { if (holes[h].Count < 3) { OutVMesh.SetData(null); UIMessages.Add("Hole Cross has <3 Vertices: Can't create Caps!"); return; } tess.AddContour(make2DSegment(holes[h], 0)); } tess.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3); vtStart = UnityLibTessUtility.FromContourVertex(tess.Vertices); Bounds b; vmesh.Vertex = applyMat(vtStart, getMat(vol, 0, true), out b); submesh.Material = StartMaterial; submesh.Triangles = tess.Elements; if (ReverseTriOrder) { flipTris(ref submesh.Triangles, 0, submesh.Triangles.Length); } if (GenerateUV) { vmesh.UV = new Vector2[vtStart.Length]; applyUV(vtStart, ref vmesh.UV, 0, vtStart.Length, StartMaterialSettings, b); } #endregion } if (genEnd) { #region --- End Cap --- var tess = new Tess(); tess.UsePooling = true; tess.AddContour(make2DSegment(vol, 0)); for (int h = 0; h < holes.Count; h++) { if (holes[h].Count < 3) { OutVMesh.SetData(null); UIMessages.Add("Hole Cross has <3 Vertices: Can't create Caps!"); return; } tess.AddContour(make2DSegment(holes[h], 0)); } tess.Tessellate(WindingRule.EvenOdd, ElementType.Polygons, 3); vtEnd = UnityLibTessUtility.FromContourVertex(tess.Vertices); Bounds b; int l = vmesh.Vertex.Length; vmesh.Vertex = vmesh.Vertex.AddRange <Vector3>(applyMat(vtEnd, getMat(vol, vol.Count - 1, true), out b)); int[] tris = tess.Elements; if (!ReverseTriOrder) { flipTris(ref tris, 0, tris.Length); } for (int i = 0; i < tris.Length; i++) { tris[i] += l; } if (!CloneStartCap && StartMaterial != EndMaterial) { vmesh.AddSubMesh(new CGVSubMesh(tris, EndMaterial)); } else { submesh.Material = StartMaterial; submesh.Triangles = submesh.Triangles.AddRange <int>(tris); } if (GenerateUV) { System.Array.Resize <Vector2>(ref vmesh.UV, vmesh.UV.Length + vtEnd.Length); applyUV(vtEnd, ref vmesh.UV, vtStart.Length, vtEnd.Length, (CloneStartCap) ? StartMaterialSettings : EndMaterialSettings, b); } #endregion } OutVMesh.SetData(vmesh); } }
public override void OnModuleSceneDebugGUI() { base.OnModuleSceneDebugGUI(); CGVolume vol = Target.InData.GetData <CGVolume>(); if (vol) { Handles.matrix = Target.Generator.transform.localToWorldMatrix; if (Target.ShowPathSamples) { CGEditorUtility.SceneGUIPlot(vol.Position, 0.1f, Target.PathColor); if (Target.ShowIndex) { var labels = Enumerable.Range(0, vol.Count).Select(i => i.ToString()).ToArray <string>(); CGEditorUtility.SceneGUILabels(vol.Position, labels, Color.black, Vector2.zero); } } if (Target.ShowCrossSamples) { int vtLo = Target.LimitCross.From * vol.CrossSize; int vtHi = vtLo + vol.CrossSize; if (!Target.LimitCross.SimpleValue) { vtLo = Target.LimitCross.Low * vol.CrossSize; vtHi = (Target.LimitCross.High + 1) * vol.CrossSize; } vtLo = Mathf.Clamp(vtLo, 0, vol.VertexCount); vtHi = Mathf.Clamp(vtHi, vtLo, vol.VertexCount); var range = vol.Vertex.SubArray <Vector3>(vtLo, vtHi - vtLo); CGEditorUtility.SceneGUIPlot(range, 0.1f, Color.white); if (Target.ShowIndex) { var labels = Enumerable.Range(vtLo, vtHi).Select(i => i.ToString()).ToArray <string>(); CGEditorUtility.SceneGUILabels(range, labels, Color.black, Vector2.zero); } if (Target.ShowMap) { var labels = Enumerable.Range(vtLo, vtHi).Select(i => DTMath.SnapPrecision(vol.CrossMap[i], 3).ToString()).ToArray <string>(); CGEditorUtility.SceneGUILabels(range, labels, new Color(1, 0, 1), new Vector2(10, 20)); } if (Target.ShowNormals) { DTHandles.PushHandlesColor(Target.NormalColor); for (int i = vtLo; i < vtHi; i++) { Handles.DrawLine(vol.Vertex[i], vol.Vertex[i] + vol.VertexNormal[i] * 2); } DTHandles.PopHandlesColor(); } } if (Target.Interpolate) { Vector3 pos; Vector3 tan; Vector3 up; vol.InterpolateVolume(Target.InterpolatePathF, Target.InterpolateCrossF, out pos, out tan, out up); Handles.ConeCap(0, pos, Quaternion.LookRotation(up, tan), 1f); } Handles.matrix = Matrix4x4.identity; } }