public virtual void FixedUpdate() { if (!limitsSet && PFUtils.canCheckTech()) { limitsSet = true; float minSize = PFUtils.getTechMinValue("PROCFAIRINGS_MINDIAMETER", 0.25f); float maxSize = PFUtils.getTechMaxValue("PROCFAIRINGS_MAXDIAMETER", 30); PFUtils.setFieldRange(Fields["manualMaxSize"], minSize, maxSize * 2); ((UI_FloatEdit)Fields["manualMaxSize"].uiControlEditor).incrementLarge = diameterStepLarge; ((UI_FloatEdit)Fields["manualMaxSize"].uiControlEditor).incrementSmall = diameterStepSmall; ((UI_FloatEdit)Fields["manualCylStart"].uiControlEditor).incrementLarge = heightStepLarge; ((UI_FloatEdit)Fields["manualCylStart"].uiControlEditor).incrementSmall = heightStepSmall; ((UI_FloatEdit)Fields["manualCylEnd"].uiControlEditor).incrementLarge = heightStepLarge; ((UI_FloatEdit)Fields["manualCylEnd"].uiControlEditor).incrementSmall = heightStepSmall; } if (!part.packed && topBasePart != null) { var adapter = part.GetComponent <ProceduralFairingAdapter>(); if (adapter) { topBasePart = adapter.getTopPart(); if (topBasePart == null) { removeJoints(); } } } }
public virtual void updateShape() { changed = false; var node = part.findAttachNode("bottom"); if (node != null) { node.size = Mathf.RoundToInt(baseSize / diameterStepLarge); } node = part.findAttachNode("top"); if (node != null) { node.size = Mathf.RoundToInt(baseSize / diameterStepLarge); } node = part.findAttachNode(topNodeName); if (node != null) { node.position = new Vector3(0, height, 0); node.size = Mathf.RoundToInt(topSize / diameterStepLarge); if (!justLoaded) { PFUtils.updateAttachedPartPos(node, part); } } else { Debug.LogError("[ProceduralAdapterBase] No '" + topNodeName + "' node in part", this); } }
public void scaleNode(AttachNode node, float scale, bool setSize) { if (node == null) { return; } node.position = node.originalPosition * scale; if (!justLoaded) { PFUtils.updateAttachedPartPos(node, part); } if (setSize) { node.size = Mathf.RoundToInt(scale / diameterStepLarge); } if (node.attachedPart != null) { var baseEventDatum = new BaseEventDetails(0); baseEventDatum.Set <Vector3>("location", node.position); baseEventDatum.Set <Vector3>("orientation", node.orientation); baseEventDatum.Set <Vector3>("secondaryAxis", node.secondaryAxis); baseEventDatum.Set <AttachNode>("node", node); node.attachedPart.SendEvent("OnPartAttachNodePositionChanged", baseEventDatum); } }
public override void resizePart(float scale) { base.resizePart(scale); var node = part.findAttachNode("bottom"); foreach (var n in part.findAttachNodes("bottom")) { n.position.y = node.position.y; if (!justLoaded) { PFUtils.updateAttachedPartPos(n, part); } } var nnt = part.GetComponent <KzNodeNumberTweaker>(); if (nnt) { float mr = size * 0.5f; if (nnt.radius > mr) { nnt.radius = mr; } ((UI_FloatEdit)nnt.Fields["radius"].uiControlEditor).maxValue = mr; } }
void OnToggleAutoshapeUI() { Fields["manualMaxSize"].guiActiveEditor = !autoShape; Fields["manualCylStart"].guiActiveEditor = !autoShape; Fields["manualCylEnd"].guiActiveEditor = !autoShape; PFUtils.refreshPartWindow(); }
public override void resizePart(float scale) { float sth = calcSideThickness(); float br = size * 0.5f - sth; scale = br * 2; base.resizePart(scale); var topNode = part.FindAttachNode("top"); var bottomNode = part.FindAttachNode("bottom"); float y = (topNode.position.y + bottomNode.position.y) * 0.5f; int sideNodeSize = Mathf.RoundToInt(scale / diameterStepLarge) - 1; if (sideNodeSize < 0) { sideNodeSize = 0; } var nodes = part.FindAttachNodes("connect"); for (int i = 0; i < nodes.Length; i++) { var n = nodes [i]; n.position.y = y; n.size = sideNodeSize; if (!justLoaded) { PFUtils.updateAttachedPartPos(n, part); } } var nnt = part.GetComponent <KzNodeNumberTweaker>(); if (nnt) { nnt.radius = size * 0.5f; } var fbase = part.GetComponent <ProceduralFairingBase>(); if (fbase) { fbase.baseSize = br * 2; fbase.sideThickness = sth; fbase.needShapeUpdate = true; } }
public void scaleNode(AttachNode node, float scale, bool setSize) { if (node == null) { return; } node.position = node.originalPosition * scale; if (!justLoaded) { PFUtils.updateAttachedPartPos(node, part); } if (setSize) { node.size = Mathf.RoundToInt(scale / diameterStepLarge); } }
public virtual void resizePart(float scale, bool pushAttachments) { if (part.FindAttachNode("bottom") is AttachNode node && part.FindAttachNodes("bottom") is AttachNode[] nodes) { foreach (AttachNode n in nodes) { Vector3 newPos = new Vector3(n.position.x, node.position.y, n.position.z); PFUtils.UpdateNode(part, n, newPos, node.size, pushAttachments); } } if (part.GetComponent <KzNodeNumberTweaker>() is KzNodeNumberTweaker nnt) { nnt.SetRadius(Math.Min(nnt.radius, size / 2), pushAttachments); (nnt.Fields[nameof(nnt.radius)].uiControlEditor as UI_FloatEdit).maxValue = size / 2; } }
void updateNodePositions() { float d = Mathf.Sin(Mathf.PI / numNodes) * radius * 2; int size = Mathf.RoundToInt(d / (radiusStepLarge * 2)); for (int i = 1; i <= numNodes; ++i) { var node = findNode(i); if (node == null) { continue; } float a = Mathf.PI * 2 * (i - 1) / numNodes; node.position.x = Mathf.Cos(a) * radius; node.position.z = Mathf.Sin(a) * radius; if (shouldResizeNodes) { node.size = size; } if (!justLoaded) { PFUtils.updateAttachedPartPos(node, part); } } for (int i = numNodes + 1; i <= maxNumber; ++i) { var node = findNode(i); if (node == null) { continue; } node.position.x = 10000; } }
public static void UpdateNode(Part part, AttachNode node, Vector3 newPosition, int size, bool pushAttachments, float attachDiameter = 0) { if (node is AttachNode) { Vector3 oldPosWorld = part.transform.TransformPoint(node.position); node.position = newPosition; node.size = size; if (pushAttachments) { PFUtils.UpdateAttachedPartPos(node, part, oldPosWorld); } if (node.attachedPart is Part) { PFUtils.InformAttachedPartNodePositionChanged(node); PFUtils.InformAttachNodeSizeChanged(node, attachDiameter > 0 ? attachDiameter : Mathf.Max(node.size, 0.01f)); } } }
public virtual void FixedUpdate() { if (!limitsSet && PFUtils.canCheckTech()) { limitsSet = true; float minSize = PFUtils.getTechMinValue(minSizeName, 0.25f); float maxSize = PFUtils.getTechMaxValue(maxSizeName, 30); PFUtils.setFieldRange(Fields["size"], minSize, maxSize); ((UI_FloatEdit)Fields["size"].uiControlEditor).incrementLarge = diameterStepLarge; ((UI_FloatEdit)Fields["size"].uiControlEditor).incrementSmall = diameterStepSmall; } if (size != oldSize) { resizePart(size); } justLoaded = false; }
public void FixedUpdate() { if (HighLogic.LoadedSceneIsEditor) { int nsym = part.symmetryCounterparts.Count; if (nsym == 0) { massDisplay = PFUtils.formatMass(part.mass); costDisplay = PFUtils.formatCost(part.partInfo.cost + GetModuleCost()); } else if (nsym == 1) { massDisplay = PFUtils.formatMass(part.mass * 2) + " (both)"; costDisplay = PFUtils.formatCost((part.partInfo.cost + GetModuleCost()) * 2) + " (both)"; } else { massDisplay = PFUtils.formatMass(part.mass * (nsym + 1)) + " (all " + (nsym + 1) + ")"; costDisplay = PFUtils.formatCost((part.partInfo.cost + GetModuleCost()) * (nsym + 1)) + " (all " + (nsym + 1) + ")"; } } }
public virtual void resizePart(float scale) { oldSize = size; part.mass = totalMass = ((specificMass.x * scale + specificMass.y) * scale + specificMass.z) * scale + specificMass.w; massDisplay = PFUtils.formatMass(totalMass); costDisplay = PFUtils.formatCost(part.partInfo.cost + GetModuleCost(part.partInfo.cost, ModifierStagingSituation.CURRENT) + part.partInfo.cost); part.breakingForce = specificBreakingForce * Mathf.Pow(scale, 2); part.breakingTorque = specificBreakingTorque * Mathf.Pow(scale, 2); var model = part.FindModelTransform("model"); if (model != null) { model.localScale = Vector3.one * scale; } else { Debug.LogError("[PF]: No 'model' transform found in part!", this); } part.rescaleFactor = scale; scaleNode(part.FindAttachNode("top"), scale, true); scaleNode(part.FindAttachNode("bottom"), scale, true); var nodes = part.FindAttachNodes("interstage"); if (nodes != null) { for (int i = 0; i < nodes.Length; i++) { scaleNode(nodes [i], scale, true); } } }
public static IEnumerator <YieldInstruction> updateDragCubeCoroutine(Part part, float areaScale) { while (true) { if (part == null || part.Equals(null)) { yield break; } if (HighLogic.LoadedSceneIsFlight) { if (part.vessel == null || part.vessel.Equals(null)) { yield break; } if (!FlightGlobals.ready || part.packed || !part.vessel.loaded) { yield return(new WaitForFixedUpdate()); continue; } break; } if (HighLogic.LoadedSceneIsEditor) { yield return(new WaitForFixedUpdate()); break; } yield break; } PFUtils.updateDragCube(part, areaScale); }
public virtual void resizePart(float scale) { oldSize = size; part.mass = ((specificMass.x * scale + specificMass.y) * scale + specificMass.z) * scale + specificMass.w; massDisplay = PFUtils.formatMass(part.mass); costDisplay = PFUtils.formatCost(GetModuleCost() + part.partInfo.cost); part.breakingForce = specificBreakingForce * Mathf.Pow(scale, 2); part.breakingTorque = specificBreakingTorque * Mathf.Pow(scale, 2); var model = part.FindModelTransform("model"); if (model != null) { model.localScale = Vector3.one * scale; } else { Debug.LogError("[KzPartResizer] No 'model' transform in the part", this); } scaleNode(part.findAttachNode("top"), scale, true); scaleNode(part.findAttachNode("bottom"), scale, true); }
public virtual void updateShape() { changed = false; float topheight = 0; float topnodeheight = 0; var node = part.FindAttachNode("bottom"); if (node != null) { node.size = Mathf.RoundToInt(baseSize / diameterStepLarge); } node = part.FindAttachNode("top"); if (node != null) { node.size = Mathf.RoundToInt(baseSize / diameterStepLarge); topheight = node.position.y; } node = part.FindAttachNode(topNodeName); if (node != null) { node.position = new Vector3(0, height, 0); node.size = Mathf.RoundToInt(topSize / diameterStepLarge); if (!justLoaded) { PFUtils.updateAttachedPartPos(node, part); } topnodeheight = height; } else { Debug.LogError("[PF]: No '" + topNodeName + "' node in part!", this); } var internodes = part.FindAttachNodes("interstage"); if (internodes != null) { var inc = (topnodeheight - topheight) / (internodes.Length / 2 + 1); for (int i = 0, j = 0; i < internodes.Length; i = i + 2) { var height = topheight + (j + 1) * inc; j++; node = internodes [i]; node.position.y = height; node.size = node.size = Mathf.RoundToInt(topSize / diameterStepLarge) - 1; if (!justLoaded) { PFUtils.updateAttachedPartPos(node, part); } node = internodes [i + 1]; node.position.y = height; node.size = node.size = Mathf.RoundToInt(topSize / diameterStepLarge) - 1; if (!justLoaded) { PFUtils.updateAttachedPartPos(node, part); } } } }
public override void FixedUpdate() { base.FixedUpdate(); if (!limitsSet && PFUtils.canCheckTech()) { limitsSet = true; float minSize = PFUtils.getTechMinValue("PROCFAIRINGS_MINDIAMETER", 0.25f); float maxSize = PFUtils.getTechMaxValue("PROCFAIRINGS_MAXDIAMETER", 30); PFUtils.setFieldRange(Fields["baseSize"], minSize, maxSize); PFUtils.setFieldRange(Fields["topSize"], minSize, maxSize); ((UI_FloatEdit)Fields["baseSize"].uiControlEditor).incrementLarge = diameterStepLarge; ((UI_FloatEdit)Fields["baseSize"].uiControlEditor).incrementSmall = diameterStepSmall; ((UI_FloatEdit)Fields["topSize"].uiControlEditor).incrementLarge = diameterStepLarge; ((UI_FloatEdit)Fields["topSize"].uiControlEditor).incrementSmall = diameterStepSmall; ((UI_FloatEdit)Fields["height"].uiControlEditor).incrementLarge = heightStepLarge; ((UI_FloatEdit)Fields["height"].uiControlEditor).incrementSmall = heightStepSmall; ((UI_FloatEdit)Fields["extraHeight"].uiControlEditor).incrementLarge = heightStepLarge; ((UI_FloatEdit)Fields["extraHeight"].uiControlEditor).incrementSmall = heightStepSmall; } if (isShipModified) { isShipModified = false; // Remove the engine fairing (if there is any) from topmost node. if (!engineFairingRemoved) { var node = part.FindAttachNode(topNodeName); if (node != null && node.attachedPart != null) { var tp = node.attachedPart; if (HighLogic.LoadedSceneIsEditor || !tp.packed) { var comps = tp.GetComponents <ModuleJettison>(); for (int i = 0; i < comps.Length; i++) { var mj = comps [i]; var jt = tp.FindModelTransform(mj.jettisonName); if (jt == null) { jt = mj.jettisonTransform; } if (jt != null) { jt.gameObject.SetActive(false); } mj.jettisonName = null; mj.jettisonTransform = null; } if (!HighLogic.LoadedSceneIsEditor) { engineFairingRemoved = true; } } } } if (!HighLogic.LoadedSceneIsEditor) { if (isTopNodePartPresent) { var tp = getTopPart(); if (tp == null) { isTopNodePartPresent = false; Events["UIToggleTopNodeDecouple"].guiActive = false; } else { if (topNodeDecouplesWhenFairingsGone && !CheckForFairingPresent()) { PartModule item = part.Modules["ModuleDecouple"]; if (item == null) { Debug.LogError("[PF]: Cannot decouple from top part!", this); } else { RemoveTopPartJoints(); ((ModuleDecouple)item).Decouple(); part.stackIcon.RemoveIcon(); StageManager.Instance.SortIcons(true); isFairingPresent = false; isTopNodePartPresent = false; Events["UIToggleTopNodeDecouple"].guiActive = false; } } } } if (isStaged) { isStaged = false; if (part != null) { if (stageNum == part.inverseStage) { part.stackIcon.RemoveIcon(); StageManager.Instance.SortIcons(true); Events["UIToggleTopNodeDecouple"].guiActive = false; } } } } } }
public override void updateShape() { base.updateShape(); float sth = calcSideThickness(); float br = baseSize * 0.5f - sth; float scale = br * 2; part.mass = totalMass = ((specificMass.x * scale + specificMass.y) * scale + specificMass.z) * scale + specificMass.w; massDisplay = PFUtils.formatMass(totalMass); costDisplay = PFUtils.formatCost(part.partInfo.cost + GetModuleCost(part.partInfo.cost, ModifierStagingSituation.CURRENT)); part.breakingForce = specificBreakingForce * Mathf.Pow(br, 2); part.breakingTorque = specificBreakingTorque * Mathf.Pow(br, 2); var model = part.FindModelTransform("model"); if (model != null) { model.localScale = Vector3.one * scale; } else { Debug.LogError("[PF]: No 'model' transform found in part!", this); } part.rescaleFactor = scale; var node = part.FindAttachNode("top"); node.position = node.originalPosition * scale; if (!justLoaded) { PFUtils.updateAttachedPartPos(node, part); } var topNode = part.FindAttachNode("top"); var bottomNode = part.FindAttachNode("bottom"); float y = (topNode.position.y + bottomNode.position.y) * 0.5f; int sideNodeSize = Mathf.RoundToInt(scale / diameterStepLarge) - 1; if (sideNodeSize < 0) { sideNodeSize = 0; } var nodes = part.FindAttachNodes("connect"); if (nodes != null) { for (int i = 0; i < nodes.Length; i++) { var n = nodes [i]; n.position.y = y; n.size = sideNodeSize; if (!justLoaded) { PFUtils.updateAttachedPartPos(n, part); } } } var topnode2 = part.FindAttachNode(topNodeName); var internodes = part.FindAttachNodes("interstage"); if (internodes != null && topnode2 != null) { var topheight = topNode.position.y; var topnode2height = topnode2.position.y; var inc = (topnode2height - topheight) / (internodes.Length / 2 + 1); for (int i = 0, j = 0; i < internodes.Length; i = i + 2) { var baseHeight = topheight + (j + 1) * inc; j++; node = internodes [i]; node.position.y = baseHeight; node.size = topNode.size; if (!justLoaded) { PFUtils.updateAttachedPartPos(node, part); } node = internodes [i + 1]; node.position.y = baseHeight; node.size = sideNodeSize; if (!justLoaded) { PFUtils.updateAttachedPartPos(node, part); } } } var nnt = part.GetComponent <KzNodeNumberTweaker>(); if (nnt) { nnt.radius = baseSize * 0.5f; } var fbase = part.GetComponent <ProceduralFairingBase>(); if (fbase) { fbase.baseSize = br * 2; fbase.sideThickness = sth; fbase.needShapeUpdate = true; } StartCoroutine(PFUtils.updateDragCubeCoroutine(part, dragAreaScale)); }
public override void FixedUpdate() { base.FixedUpdate(); if (!limitsSet && PFUtils.canCheckTech()) { limitsSet = true; float minSize = PFUtils.getTechMinValue("PROCFAIRINGS_MINDIAMETER", 0.25f); float maxSize = PFUtils.getTechMaxValue("PROCFAIRINGS_MAXDIAMETER", 30); PFUtils.setFieldRange(Fields["baseSize"], minSize, maxSize); PFUtils.setFieldRange(Fields["topSize"], minSize, maxSize); ((UI_FloatEdit)Fields["baseSize"].uiControlEditor).incrementLarge = diameterStepLarge; ((UI_FloatEdit)Fields["baseSize"].uiControlEditor).incrementSmall = diameterStepSmall; ((UI_FloatEdit)Fields["topSize"].uiControlEditor).incrementLarge = diameterStepLarge; ((UI_FloatEdit)Fields["topSize"].uiControlEditor).incrementSmall = diameterStepSmall; ((UI_FloatEdit)Fields["height"].uiControlEditor).incrementLarge = heightStepLarge; ((UI_FloatEdit)Fields["height"].uiControlEditor).incrementSmall = heightStepSmall; ((UI_FloatEdit)Fields["extraHeight"].uiControlEditor).incrementLarge = heightStepLarge; ((UI_FloatEdit)Fields["extraHeight"].uiControlEditor).incrementSmall = heightStepSmall; } if (!engineFairingRemoved) { var node = part.findAttachNode(topNodeName); if (node != null && node.attachedPart != null) { var tp = node.attachedPart; if (HighLogic.LoadedSceneIsEditor || !tp.packed) { foreach (var mj in tp.GetComponents <ModuleJettison>()) { // print("[ProceduralFairingAdapter] removing engine fairings "+mj); var jt = tp.FindModelTransform(mj.jettisonName); if (jt == null) { jt = mj.jettisonTransform; } if (jt != null) { // print("[ProceduralFairingAdapter] disabling engine fairing "+jt); jt.gameObject.SetActive(false); } mj.jettisonName = null; mj.jettisonTransform = null; // tp.RemoveModule(mj); } if (!HighLogic.LoadedSceneIsEditor) { engineFairingRemoved = true; } } } } if (!HighLogic.LoadedSceneIsEditor) { var node = part.findAttachNode(topNodeName); if (node != null && node.attachedPart != null) { var tp = node.attachedPart; foreach (var n in part.findAttachNodes("connect")) { if (n.attachedPart != null) { return; } } if (part.parent == tp) { part.decouple(0); } else if (tp.parent == part) { tp.decouple(0); } else { Debug.LogError("[ProceduralFairingAdapter] Can't decouple from top part", this); } } } }
public override void updateShape() { base.updateShape(); float sth = calcSideThickness(); float br = baseSize * 0.5f - sth; float scale = br * 2; part.mass = ((specificMass.x * scale + specificMass.y) * scale + specificMass.z) * scale + specificMass.w; massDisplay = PFUtils.formatMass(part.mass); costDisplay = PFUtils.formatCost(part.partInfo.cost + GetModuleCost()); part.breakingForce = specificBreakingForce * Mathf.Pow(br, 2); part.breakingTorque = specificBreakingTorque * Mathf.Pow(br, 2); var model = part.FindModelTransform("model"); if (model != null) { model.localScale = Vector3.one * scale; } else { Debug.LogError("[ProceduralFairingAdapter] No 'model' transform in the part", this); } var node = part.findAttachNode("top"); node.position = node.originalPosition * scale; if (!justLoaded) { PFUtils.updateAttachedPartPos(node, part); } var topNode = part.findAttachNode("top"); var bottomNode = part.findAttachNode("bottom"); float y = (topNode.position.y + bottomNode.position.y) * 0.5f; int sideNodeSize = Mathf.RoundToInt(scale / diameterStepLarge) - 1; if (sideNodeSize < 0) { sideNodeSize = 0; } foreach (var n in part.findAttachNodes("connect")) { n.position.y = y; n.size = sideNodeSize; if (!justLoaded) { PFUtils.updateAttachedPartPos(n, part); } } var nnt = part.GetComponent <KzNodeNumberTweaker>(); if (nnt) { nnt.radius = baseSize * 0.5f; } var fbase = part.GetComponent <ProceduralFairingBase>(); if (fbase) { fbase.baseSize = br * 2; fbase.sideThickness = sth; fbase.updateDelay = 0; } }
public override void OnStart(StartState state) { limitsSet = false; if (!HighLogic.LoadedSceneIsEditor && !HighLogic.LoadedSceneIsFlight) { return; } PFUtils.hideDragStuff(part); GameEvents.onEditorShipModified.Add(new EventData <ShipConstruct> .OnEvent(onEditorVesselModified)); if (HighLogic.LoadedSceneIsEditor) { if (line) { line.transform.Rotate(0, 90, 0); } DestroyAllLineRenderers(); destroyOutline(); for (int i = 0; i < outlineSlices; ++i) { var r = makeLineRenderer("fairing outline", outlineColor, outlineWidth); outline.Add(r); r.transform.Rotate(0, i * 360f / outlineSlices, 0); } ShowHideInterstageNodes(); recalcShape(); updateDelay = 0.1f; needShapeUpdate = true; } else { topBasePart = null; var adapter = part.GetComponent <ProceduralFairingAdapter>(); if (adapter) { topBasePart = adapter.getTopPart(); } else { var scan = scanPayload(); if (scan.targets.Count > 0) { topBasePart = scan.targets [0]; } } } SetUIChangedCallBacks(); OnToggleAutoshapeUI(); }
public void recalcShape() { var scan = scanPayload(); // Check for reversed bases (inline fairings). float topY = 0; float topRad = 0; AttachNode topSideNode = null; bool isInline = false; var adapter = part.GetComponent <ProceduralFairingAdapter>(); if (adapter) { isInline = true; topY = adapter.height + adapter.extraHeight; if (topY < scan.ofs) { topY = scan.ofs; } topRad = adapter.topRadius; } else if (scan.targets.Count > 0) { isInline = true; var topBase = scan.targets [0].GetComponent <ProceduralFairingBase>(); topY = scan.w2l.MultiplyPoint3x4(topBase.part.transform.position).y; if (topY < scan.ofs) { topY = scan.ofs; } topSideNode = HasNodeComponent <ProceduralFairingSide>(topBase.part.FindAttachNodes("connect")); topRad = topBase.baseSize * 0.5f; } // No payload case. if (scan.profile.Count <= 0) { scan.profile.Add(extraRadius); } // Fill profile outline (for debugging). if (line) { line.positionCount = scan.profile.Count * 2 + 2; float prevRad = 0; int hi = 0; for (int i = 0; i < scan.profile.Count; i++) { var r = scan.profile [i]; line.SetPosition(hi * 2, new Vector3(prevRad, hi * verticalStep + scan.ofs, 0)); line.SetPosition(hi * 2 + 1, new Vector3(r, hi * verticalStep + scan.ofs, 0)); hi++; prevRad = r; } line.SetPosition(hi * 2, new Vector3(prevRad, hi * verticalStep + scan.ofs, 0)); line.SetPosition(hi * 2 + 1, new Vector3(0, hi * verticalStep + scan.ofs, 0)); } // Check for attached side parts. var attached = part.FindAttachNodes("connect"); // Get the number of available fairing attachment nodes from NodeNumberTweaker. var nnt = part.GetComponent <KzNodeNumberTweaker>(); int numSideParts = nnt.numNodes; var sideNode = HasNodeComponent <ProceduralFairingSide>(attached); var baseConeShape = new Vector4(0, 0, 0, 0); var noseConeShape = new Vector4(0, 0, 0, 0); var mappingScale = new Vector2(1024, 1024); var stripMapping = new Vector2(992, 1024); var horMapping = new Vector4(0, 480, 512, 992); var vertMapping = new Vector4(0, 160, 704, 1024); float baseCurveStartX = 0; float baseCurveStartY = 0; float baseCurveEndX = 0; float baseCurveEndY = 0; int baseConeSegments = 1; float noseCurveStartX = 0; float noseCurveStartY = 0; float noseCurveEndX = 0; float noseCurveEndY = 0; int noseConeSegments = 1; float noseHeightRatio = 1; float minBaseConeAngle = 20; float density = 0; if (sideNode != null) { var sf = sideNode.attachedPart.GetComponent <ProceduralFairingSide>(); mappingScale = sf.mappingScale; stripMapping = sf.stripMapping; horMapping = sf.horMapping; vertMapping = sf.vertMapping; noseHeightRatio = sf.noseHeightRatio; minBaseConeAngle = sf.minBaseConeAngle; baseConeShape = sf.baseConeShape; baseCurveStartX = sf.baseCurveStartX; baseCurveStartY = sf.baseCurveStartY; baseCurveEndX = sf.baseCurveEndX; baseCurveEndY = sf.baseCurveEndY; baseConeSegments = (int)sf.baseConeSegments; noseConeShape = sf.noseConeShape; noseCurveStartX = sf.noseCurveStartX; noseCurveStartY = sf.noseCurveStartY; noseCurveEndX = sf.noseCurveEndX; noseCurveEndY = sf.noseCurveEndY; noseConeSegments = (int)sf.noseConeSegments; density = sf.density; } // Compute the fairing shape. float baseRad = baseSize * 0.5f; float minBaseConeTan = Mathf.Tan(minBaseConeAngle * Mathf.Deg2Rad); float cylStart = 0; float maxRad; int profTop = scan.profile.Count; if (isInline) { profTop = Mathf.CeilToInt((topY - scan.ofs) / verticalStep); if (profTop > scan.profile.Count) { profTop = scan.profile.Count; } maxRad = 0; for (int i = 0; i < profTop; ++i) { maxRad = Mathf.Max(maxRad, scan.profile [i]); } maxRad = Mathf.Max(maxRad, topRad); } else { maxRad = PFUtils.GetMaxValueFromList(scan.profile); } if (maxRad > baseRad) { // Try to fit the base cone as high as possible. cylStart = scan.ofs; for (int i = 1; i < scan.profile.Count; ++i) { float y = i * verticalStep + scan.ofs; float r0 = baseRad; float k = (maxRad - r0) / y; if (k < minBaseConeTan) { break; } bool ok = true; float r = r0 + k * scan.ofs; for (int j = 0; j < i; ++j, r += k * verticalStep) { if (scan.profile [j] > r) { ok = false; break; } } if (!ok) { break; } cylStart = y; } } else { // No base cone, just a cylinder and a nose. maxRad = baseRad; } float cylEnd = scan.profile.Count * verticalStep + scan.ofs; if (isInline) { float r0 = topRad; if (profTop > 0 && profTop < scan.profile.Count) { r0 = Mathf.Max(r0, scan.profile [profTop - 1]); if (profTop - 2 >= 0) { r0 = Mathf.Max(r0, scan.profile [profTop - 2]); } } if (maxRad > r0) { if (cylEnd > topY) { cylEnd = topY - verticalStep; } // Try to fit the top cone as low as possible. for (int i = profTop - 1; i >= 0; --i) { float y = i * verticalStep + scan.ofs; float k = (maxRad - r0) / (y - topY); bool ok = true; float r = maxRad + k * verticalStep; for (int j = i; j < profTop; ++j, r += k * verticalStep) { if (r < r0) { r = r0; } if (scan.profile [j] > r) { ok = false; break; } } if (!ok) { break; } cylEnd = y; } } else { cylEnd = topY; } } else { // Try to fit the nose cone as low as possible. for (int i = scan.profile.Count - 1; i >= 0; --i) { float s = verticalStep / noseHeightRatio; bool ok = true; float r = maxRad - s; for (int j = i; j < scan.profile.Count; ++j, r -= s) { if (scan.profile [j] > r) { ok = false; break; } } if (!ok) { break; } float y = i * verticalStep + scan.ofs; cylEnd = y; } } if (autoShape) { manualMaxSize = maxRad * 2; manualCylStart = cylStart; manualCylEnd = cylEnd; } else { maxRad = manualMaxSize * 0.5f; cylStart = manualCylStart; cylEnd = manualCylEnd; } if (cylStart > cylEnd) { cylStart = cylEnd; } // Build the fairing shape line. Vector3 [] shape; if (isInline) { shape = buildInlineFairingShape(baseRad, maxRad, topRad, cylStart, cylEnd, topY, baseConeShape, baseConeSegments, vertMapping, mappingScale.y); } else { shape = buildFairingShape(baseRad, maxRad, cylStart, cylEnd, noseHeightRatio, baseConeShape, noseConeShape, baseConeSegments, noseConeSegments, vertMapping, mappingScale.y); } if (sideNode == null && topSideNode == null) { // No side parts - fill fairing outlines. for (int j = 0; j < outline.Count; j++) { var lr = outline [j]; lr.positionCount = shape.Length; for (int i = 0; i < shape.Length; ++i) { lr.SetPosition(i, new Vector3(shape [i].x, shape [i].y)); } } } else { for (int j = 0; j < outline.Count; j++) { var lr = outline [j]; lr.positionCount = 0; } } // Rebuild the side parts. int numSegs = circleSegments / numSideParts; if (numSegs < 2) { numSegs = 2; } for (int i = 0; i < attached.Length; i++) { var sn = attached [i]; var sp = sn.attachedPart; if (!sp) { continue; } var sf = sp.GetComponent <ProceduralFairingSide>(); if (!sf) { continue; } if (sf.shapeLock) { continue; } var mf = sp.FindModelComponent <MeshFilter>("model"); if (!mf) { Debug.LogError("[PF]: No model in side fairing!", sp); continue; } var nodePos = sn.position; mf.transform.position = part.transform.position; mf.transform.rotation = part.transform.rotation; float ra = Mathf.Atan2(-nodePos.z, nodePos.x) * Mathf.Rad2Deg; mf.transform.Rotate(0, ra, 0); if (sf.meshPos == mf.transform.localPosition && sf.meshRot == mf.transform.localRotation && sf.numSegs == numSegs && sf.numSideParts == numSideParts && sf.baseRad.Equals(baseRad) && sf.maxRad.Equals(maxRad) && sf.cylStart.Equals(cylStart) && sf.cylEnd.Equals(cylEnd) && sf.topRad.Equals(topRad) && sf.inlineHeight.Equals(topY) && sf.sideThickness.Equals(sideThickness) && !sf.baseCurveStartX.Equals(baseCurveStartX) && !sf.baseCurveStartY.Equals(baseCurveStartY) && !sf.baseCurveEndX.Equals(baseCurveEndX) && !sf.baseCurveEndY.Equals(baseCurveEndY) && !sf.baseConeSegments.Equals(baseConeSegments) && !sf.noseCurveStartX.Equals(noseCurveStartX) && !sf.noseCurveStartY.Equals(noseCurveStartY) && !sf.noseCurveEndX.Equals(noseCurveEndX) && !sf.noseCurveEndY.Equals(noseCurveEndY) && !sf.noseConeSegments.Equals(noseConeSegments) && !sf.noseHeightRatio.Equals(noseHeightRatio) && !sf.density.Equals(density)) { continue; } sf.meshPos = mf.transform.localPosition; sf.meshRot = mf.transform.localRotation; sf.numSegs = numSegs; sf.numSideParts = numSideParts; sf.baseRad = baseRad; sf.maxRad = maxRad; sf.cylStart = cylStart; sf.cylEnd = cylEnd; sf.topRad = topRad; sf.inlineHeight = topY; sf.sideThickness = sideThickness; sf.baseCurveStartX = baseCurveStartX; sf.baseCurveStartY = baseCurveStartY; sf.baseCurveEndX = baseCurveEndX; sf.baseCurveEndY = baseCurveEndY; sf.baseConeSegments = baseConeSegments; sf.noseCurveStartX = noseCurveStartX; sf.noseCurveStartY = noseCurveStartY; sf.noseCurveEndX = noseCurveEndX; sf.noseCurveEndY = noseCurveEndY; sf.noseConeSegments = noseConeSegments; sf.noseHeightRatio = noseHeightRatio; sf.density = density; sf.rebuildMesh(); } var shielding = part.GetComponent <KzFairingBaseShielding>(); if (shielding) { shielding.reset(); } }
public override void FixedUpdate() { base.FixedUpdate(); if (!limitsSet && PFUtils.canCheckTech()) { limitsSet = true; float minSize = PFUtils.getTechMinValue("PROCFAIRINGS_MINDIAMETER", 0.25f); float maxSize = PFUtils.getTechMaxValue("PROCFAIRINGS_MAXDIAMETER", 30); PFUtils.setFieldRange(Fields["baseSize"], minSize, maxSize); PFUtils.setFieldRange(Fields["topSize"], minSize, maxSize); ((UI_FloatEdit)Fields["baseSize"].uiControlEditor).incrementLarge = diameterStepLarge; ((UI_FloatEdit)Fields["baseSize"].uiControlEditor).incrementSmall = diameterStepSmall; ((UI_FloatEdit)Fields["topSize"].uiControlEditor).incrementLarge = diameterStepLarge; ((UI_FloatEdit)Fields["topSize"].uiControlEditor).incrementSmall = diameterStepSmall; ((UI_FloatEdit)Fields["height"].uiControlEditor).incrementLarge = heightStepLarge; ((UI_FloatEdit)Fields["height"].uiControlEditor).incrementSmall = heightStepSmall; ((UI_FloatEdit)Fields["extraHeight"].uiControlEditor).incrementLarge = heightStepLarge; ((UI_FloatEdit)Fields["extraHeight"].uiControlEditor).incrementSmall = heightStepSmall; } if (isShipModified) { isShipModified = false; // We used to remove the engine fairing (if there is any) from topmost node, but lately that's been causing NREs. // Since KSP gives us this option nativley, let's just use KSP to do that if we want. if (!HighLogic.LoadedSceneIsEditor) { if (isTopNodePartPresent) { var tp = getTopPart(); if (tp == null) { isTopNodePartPresent = false; Events["UIToggleTopNodeDecouple"].guiActive = false; } else { if (topNodeDecouplesWhenFairingsGone && !CheckForFairingPresent()) { PartModule item = part.Modules["ModuleDecouple"]; if (item == null) { Debug.LogError("[PF]: Cannot decouple from top part!", this); } else { RemoveTopPartJoints(); ((ModuleDecouple)item).Decouple(); part.stackIcon.RemoveIcon(); StageManager.Instance.SortIcons(true); isFairingPresent = false; isTopNodePartPresent = false; Events["UIToggleTopNodeDecouple"].guiActive = false; } } } } if (isStaged) { isStaged = false; if (part != null) { if (stageNum == part.inverseStage) { part.stackIcon.RemoveIcon(); StageManager.Instance.SortIcons(true); Events["UIToggleTopNodeDecouple"].guiActive = false; } } } } } }
public void rebuildMesh() { var mf = part.FindModelComponent <MeshFilter>("model"); if (!mf) { Debug.LogError("[PF]: No model for side fairing!", part); return; } Mesh m = mf.mesh; if (!m) { Debug.LogError("[PF]: No mesh in side fairing model!", part); return; } mf.transform.localPosition = meshPos; mf.transform.localRotation = meshRot; updateNodeSize(); // Build the fairing shape line. float tip = maxRad * noseHeightRatio; Vector3 [] shape; baseConeShape = new Vector4(baseCurveStartX, baseCurveStartY, baseCurveEndX, baseCurveEndY); noseConeShape = new Vector4(noseCurveStartX, noseCurveStartY, noseCurveEndX, noseCurveEndY); if (inlineHeight <= 0) { shape = ProceduralFairingBase.buildFairingShape(baseRad, maxRad, cylStart, cylEnd, noseHeightRatio, baseConeShape, noseConeShape, (int)baseConeSegments, (int)noseConeSegments, vertMapping, mappingScale.y); } else { shape = ProceduralFairingBase.buildInlineFairingShape(baseRad, maxRad, topRad, cylStart, cylEnd, inlineHeight, baseConeShape, (int)baseConeSegments, vertMapping, mappingScale.y); } // Set up parameters. var dirs = new Vector3 [numSegs + 1]; for (int i = 0; i <= numSegs; ++i) { float a = Mathf.PI * 2 * (i - numSegs * 0.5f) / (numSideParts * numSegs); dirs [i] = new Vector3(Mathf.Cos(a), 0, Mathf.Sin(a)); } float segOMappingScale = (horMapping.y - horMapping.x) / (mappingScale.x * numSegs); float segIMappingScale = (horMapping.w - horMapping.z) / (mappingScale.x * numSegs); float segOMappingOfs = horMapping.x / mappingScale.x; float segIMappingOfs = horMapping.z / mappingScale.x; if (numSideParts > 2) { segOMappingOfs += segOMappingScale * numSegs * (0.5f - 1f / numSideParts); segOMappingScale *= 2f / numSideParts; segIMappingOfs += segIMappingScale * numSegs * (0.5f - 1f / numSideParts); segIMappingScale *= 2f / numSideParts; } float stripU0 = stripMapping.x / mappingScale.x; float stripU1 = stripMapping.y / mappingScale.x; float ringSegLen = baseRad * Mathf.PI * 2 / (numSegs * numSideParts); float topRingSegLen = topRad * Mathf.PI * 2 / (numSegs * numSideParts); float collWidth = maxRad * Mathf.PI * 2 / (numSideParts * 3); int numMainVerts = (numSegs + 1) * (shape.Length - 1) + 1; int numMainFaces = numSegs * ((shape.Length - 2) * 2 + 1); int numSideVerts = shape.Length * 2; int numSideFaces = (shape.Length - 1) * 2; int numRingVerts = (numSegs + 1) * 2; int numRingFaces = numSegs * 2; if (inlineHeight > 0) { numMainVerts = (numSegs + 1) * shape.Length; numMainFaces = numSegs * (shape.Length - 1) * 2; } int totalVerts = numMainVerts * 2 + numSideVerts * 2 + numRingVerts; int totalFaces = numMainFaces * 2 + numSideFaces * 2 + numRingFaces; if (inlineHeight > 0) { totalVerts += numRingVerts; totalFaces += numRingFaces; } var p = shape [shape.Length - 1]; float topY = p.y, topV = p.z; float collCenter = (cylStart + cylEnd) / 2; float collHeight = cylEnd - cylStart; if (collHeight <= 0) { collHeight = Mathf.Min(topY - cylEnd, cylStart) / 2; } // Compute the area. double area = 0; for (int i = 1; i < shape.Length; ++i) { area += (shape [i - 1].x + shape [i].x) * (shape [i].y - shape [i - 1].y) * Mathf.PI / numSideParts; } // Set the parameters based on volume. float volume = (float)(area * sideThickness); part.mass = totalMass = volume * density; part.breakingForce = part.mass * specificBreakingForce; part.breakingTorque = part.mass * specificBreakingTorque; var offset = new Vector3(maxRad * 0.7f, topY * 0.5f, 0); part.CoMOffset = part.transform.InverseTransformPoint(mf.transform.TransformPoint(offset)); // Remove any old colliders. var colls = part.FindModelComponents <Collider>(); for (int i = 0; i < colls.Count; i++) { var c = colls [i]; UnityEngine.Object.Destroy(c.gameObject); } // Add the new colliders. for (int i = -1; i <= 1; ++i) { var obj = new GameObject("collider"); obj.transform.parent = mf.transform; obj.transform.localPosition = Vector3.zero; obj.transform.localRotation = Quaternion.AngleAxis(90f * i / numSideParts, Vector3.up); var coll = obj.AddComponent <BoxCollider>(); coll.center = new Vector3(maxRad + sideThickness * 0.5f, collCenter, 0); coll.size = new Vector3(sideThickness, collHeight, collWidth); } { // Nose collider. float r = maxRad * 0.2f; var obj = new GameObject("nose_collider"); obj.transform.parent = mf.transform; obj.transform.localPosition = new Vector3(r, cylEnd + tip - r * 1.2f, 0); obj.transform.localRotation = Quaternion.identity; if (inlineHeight > 0) { r = sideThickness * 0.5f; obj.transform.localPosition = new Vector3(maxRad + r, collCenter, 0); } var coll = obj.AddComponent <SphereCollider>(); coll.center = Vector3.zero; coll.radius = r; } // Build the fairing mesh. m.Clear(); var verts = new Vector3 [totalVerts]; var uv = new Vector2 [totalVerts]; var norm = new Vector3 [totalVerts]; var tang = new Vector4 [totalVerts]; if (inlineHeight <= 0) { // Tip vertex. verts [numMainVerts - 1].Set(0, topY + sideThickness, 0); // Outside. verts [numMainVerts * 2 - 1].Set(0, topY, 0); // Inside. uv [numMainVerts - 1].Set(segOMappingScale * 0.5f * numSegs + segOMappingOfs, topV); uv [numMainVerts * 2 - 1].Set(segIMappingScale * 0.5f * numSegs + segIMappingOfs, topV); norm [numMainVerts - 1] = Vector3.up; norm [numMainVerts * 2 - 1] = -Vector3.up; tang [numMainVerts - 1] = Vector3.zero; tang [numMainVerts * 2 - 1] = Vector3.zero; } // Main vertices. float noseV0 = vertMapping.z / mappingScale.y; float noseV1 = vertMapping.w / mappingScale.y; float noseVScale = 1f / (noseV1 - noseV0); float oCenter = (horMapping.x + horMapping.y) / (mappingScale.x * 2); float iCenter = (horMapping.z + horMapping.w) / (mappingScale.x * 2); int vi = 0; for (int i = 0; i < shape.Length - (inlineHeight <= 0 ? 1 : 0); ++i) { p = shape [i]; Vector2 n; if (i == 0) { n = shape [1] - shape [0]; } else if (i == shape.Length - 1) { n = shape [i] - shape [i - 1]; } else { n = shape [i + 1] - shape [i - 1]; } n.Set(n.y, -n.x); n.Normalize(); for (int j = 0; j <= numSegs; ++j, ++vi) { var d = dirs [j]; var dp = d * p.x + Vector3.up * p.y; var dn = d * n.x + Vector3.up * n.y; if (i == 0 || i == shape.Length - 1) { verts [vi] = dp + d * sideThickness; } else { verts [vi] = dp + dn * sideThickness; } verts[vi + numMainVerts] = dp; float v = (p.z - noseV0) * noseVScale; float uo = j * segOMappingScale + segOMappingOfs; float ui = (numSegs - j) * segIMappingScale + segIMappingOfs; if (v > 0 && v < 1) { float us = 1 - v; uo = (uo - oCenter) * us + oCenter; ui = (ui - iCenter) * us + iCenter; } uv [vi].Set(uo, p.z); uv [vi + numMainVerts].Set(ui, p.z); norm [vi] = dn; norm [vi + numMainVerts] = -dn; tang [vi].Set(-d.z, 0, d.x, 0); tang [vi + numMainVerts].Set(d.z, 0, -d.x, 0); } } // Side strip vertices. float stripScale = Mathf.Abs(stripMapping.y - stripMapping.x) / (sideThickness * mappingScale.y); vi = numMainVerts * 2; float o = 0; for (int i = 0; i < shape.Length; ++i, vi += 2) { int si = i * (numSegs + 1); var d = dirs [0]; verts [vi] = verts [si]; uv [vi].Set(stripU0, o); norm [vi].Set(d.z, 0, -d.x); verts [vi + 1] = verts [si + numMainVerts]; uv [vi + 1].Set(stripU1, o); norm [vi + 1] = norm[vi]; tang [vi] = tang [vi + 1] = (verts [vi + 1] - verts [vi]).normalized; if (i + 1 < shape.Length) { o += ((Vector2)shape [i + 1] - (Vector2)shape [i]).magnitude * stripScale; } } vi += numSideVerts - 2; for (int i = shape.Length - 1; i >= 0; --i, vi -= 2) { int si = i * (numSegs + 1) + numSegs; if (i == shape.Length - 1 && inlineHeight <= 0) { si = numMainVerts - 1; } var d = dirs [numSegs]; verts [vi] = verts [si]; uv [vi].Set(stripU0, o); norm [vi].Set(-d.z, 0, d.x); verts [vi + 1] = verts [si + numMainVerts]; uv [vi + 1].Set(stripU1, o); norm [vi + 1] = norm [vi]; tang [vi] = tang [vi + 1] = (verts [vi + 1] - verts [vi]).normalized; if (i > 0) { o += ((Vector2)shape [i] - (Vector2)shape [i - 1]).magnitude * stripScale; } } // Ring vertices. vi = numMainVerts * 2 + numSideVerts * 2; o = 0; for (int j = numSegs; j >= 0; --j, vi += 2, o += ringSegLen * stripScale) { verts [vi] = verts [j]; uv [vi].Set(stripU0, o); norm [vi] = -Vector3.up; verts [vi + 1] = verts [j + numMainVerts]; uv [vi + 1].Set(stripU1, o); norm [vi + 1] = -Vector3.up; tang [vi] = tang [vi + 1] = (verts [vi + 1] - verts [vi]).normalized; } if (inlineHeight > 0) { // Top ring vertices. o = 0; int si = (shape.Length - 1) * (numSegs + 1); for (int j = 0; j <= numSegs; ++j, vi += 2, o += topRingSegLen * stripScale) { verts [vi] = verts [si + j]; uv [vi].Set(stripU0, o); norm [vi] = Vector3.up; verts [vi + 1] = verts [si + j + numMainVerts]; uv [vi + 1].Set(stripU1, o); norm [vi + 1] = Vector3.up; tang [vi] = tang [vi + 1] = (verts [vi + 1] - verts [vi]).normalized; } } // Set vertex data to mesh. for (int i = 0; i < totalVerts; ++i) { tang [i].w = 1; } m.vertices = verts; m.uv = uv; m.normals = norm; m.tangents = tang; m.uv2 = null; m.colors32 = null; var tri = new int [totalFaces * 3]; // Main faces. vi = 0; int ti1 = 0, ti2 = numMainFaces * 3; for (int i = 0; i < shape.Length - (inlineHeight <= 0 ? 2 : 1); ++i, ++vi) { p = shape [i]; for (int j = 0; j < numSegs; ++j, ++vi) { tri [ti1++] = vi; tri [ti1++] = vi + 1 + numSegs + 1; tri [ti1++] = vi + 1; tri [ti1++] = vi; tri [ti1++] = vi + numSegs + 1; tri [ti1++] = vi + 1 + numSegs + 1; tri [ti2++] = numMainVerts + vi; tri [ti2++] = numMainVerts + vi + 1; tri [ti2++] = numMainVerts + vi + 1 + numSegs + 1; tri [ti2++] = numMainVerts + vi; tri [ti2++] = numMainVerts + vi + 1 + numSegs + 1; tri [ti2++] = numMainVerts + vi + numSegs + 1; } } if (inlineHeight <= 0) { // Main tip faces. for (int j = 0; j < numSegs; ++j, ++vi) { tri [ti1++] = vi; tri [ti1++] = numMainVerts - 1; tri [ti1++] = vi + 1; tri [ti2++] = numMainVerts + vi; tri [ti2++] = numMainVerts + vi + 1; tri [ti2++] = numMainVerts + numMainVerts - 1; } } // Side strip faces. vi = numMainVerts * 2; ti1 = numMainFaces * 2 * 3; ti2 = ti1 + numSideFaces * 3; for (int i = 0; i < shape.Length - 1; ++i, vi += 2) { tri [ti1++] = vi; tri [ti1++] = vi + 1; tri [ti1++] = vi + 3; tri [ti1++] = vi; tri [ti1++] = vi + 3; tri [ti1++] = vi + 2; tri [ti2++] = numSideVerts + vi; tri [ti2++] = numSideVerts + vi + 3; tri [ti2++] = numSideVerts + vi + 1; tri [ti2++] = numSideVerts + vi; tri [ti2++] = numSideVerts + vi + 2; tri [ti2++] = numSideVerts + vi + 3; } // Ring faces. vi = numMainVerts * 2 + numSideVerts * 2; ti1 = (numMainFaces + numSideFaces) * 2 * 3; for (int j = 0; j < numSegs; ++j, vi += 2) { tri [ti1++] = vi; tri [ti1++] = vi + 1; tri [ti1++] = vi + 3; tri [ti1++] = vi; tri [ti1++] = vi + 3; tri [ti1++] = vi + 2; } if (inlineHeight > 0) { // Top ring faces. vi += 2; for (int j = 0; j < numSegs; ++j, vi += 2) { tri [ti1++] = vi; tri [ti1++] = vi + 1; tri [ti1++] = vi + 3; tri [ti1++] = vi; tri [ti1++] = vi + 3; tri [ti1++] = vi + 2; } } m.triangles = tri; StartCoroutine(PFUtils.updateDragCubeCoroutine(part, 1)); }