/// <summary> /// Align current gear with the gear specified in alignTo. /// </summary> /// <param name='alignTo'> /// Align to this gear. /// </param> public void Align(GFGearGen alignTo) { int desiredTeethCount = (int)Mathf.Round((alignTo.numberOfTeeth / alignTo.radius) * this.radius); if (this.numberOfTeeth != desiredTeethCount) { this.numberOfTeeth = desiredTeethCount; Rebuild(); } base.Align(alignTo); }
/// <summary> /// Align radius of current gear with the gear specified in alignTo based on number of teeth. /// </summary> /// <param name='alignTo'> /// Align to this gear. /// </param> public void AlignRadius(GFGearGen alignTo) { float desiredRadius = (alignTo.radius / (float)alignTo.numberOfTeeth) * this.numberOfTeeth; if (this.radius != desiredRadius) { // First set radius to the amount of teeth related to it's radius this.radius = desiredRadius; Rebuild(); } base.Align(alignTo); }
void OnEnable() { gearGenObject = (GFGearGen)this.target; lastGearGenObjectMesh = gearGenObject.gameObject.GetComponent <MeshFilter>().sharedMesh; gearGen = new SerializedObject(this.target); gearGenProps = new Dictionary <string, SerializedProperty>(); AddGearGenProperty("numberOfTeeth"); AddGearGenProperty("radius"); AddGearGenProperty("innerRadius"); AddGearGenProperty("innerMinVertexDistance"); AddGearGenProperty("thickness"); AddGearGenProperty("fillCenter"); AddGearGenProperty("fillOutside"); AddGearGenProperty("is3d"); AddGearGenProperty("alignTeethWithParent"); AddGearGenProperty("alignRadiusWithParent"); AddGearGenProperty("twistAngle"); AddGearGenProperty("twistOutside"); AddGearGenProperty("innerTeeth"); AddGearGenProperty("tipLength"); AddGearGenProperty("tipSize"); AddGearGenProperty("valleySize"); AddGearGenProperty("valleyAngleOffset"); AddGearGenProperty("tipAngleOffset"); AddGearGenProperty("skew"); AddGearGenProperty("showNormals"); AddGearGenProperty("splitVerticesAngle"); AddGearGenProperty("generateTextureCoordinates"); AddGearGenProperty("uvTiling"); AddGearGenProperty("uvOffset"); GFGear c = (GFGear)gearGenObject.gameObject.GetComponent(typeof(GFGear)); if (c != null) { gear = new SerializedObject(c); gearProps = new Dictionary <string, SerializedProperty>(); AddGearProperty("numberOfTeeth"); } else { gear = null; } // innerTeethInitialState = gearGenObject.innerTeeth; //Persist(); Undo.undoRedoPerformed = UndoCallback; }
/// <summary> /// Clone a gear and place the duplicate version aligned. /// </summary> /// <param name="direction">Direction at which to align it to</param> /// <returns>The cloned gear as gameobject</returns> public GameObject Clone(Vector3 direction) { GFGear gear = this; GFGearGen gearGen = (GFGearGen)this.gameObject.GetComponent(typeof(GFGearGen)); float d; if (gearGen != null) { d = gearGen.radius + (gearGen.radius - gearGen.tipLength); } else { d = (gear.GetRadius() * 2.1f) - gear.toothSize; } GameObject newGearGO = (GameObject)Instantiate(gear.gameObject); newGearGO.transform.parent = gear.gameObject.transform.parent; GFGear newGear = newGearGO.GetComponent(typeof(GFGear)) as GFGear; newGear.DrivenBy = gear; newGear.AutoSetDrivenBy = false; GFGearGen newGearGen = newGear.GetComponent <GFGearGen>(); if (newGearGen != null) { newGearGen.alignTeethWithParent = true; newGearGen.alignRadiusWithParent = true; } newGearGO.transform.position = gear.transform.position + (direction.normalized * d); // Get number that is not followed by any other number string re = @"(\d+)(?!.*\d)"; Match m = Regex.Match(gear.gameObject.name, re); int nmbr = 1; // Add one to the last number (if exists) if (m != null && m.Value != null && m.Value != "" && gear.DrivenBy != null) { nmbr = int.Parse(m.Value) + 1; } // Rename object to sequentially numbered object newGearGO.name = Regex.Replace(gear.gameObject.name, re, "").Trim() + " " + nmbr.ToString(); newGearGen.Align(gearGen); return(newGearGO); }
static private void Persist(GFGearGen gearGenObject) { Mesh newMesh = gearGenObject.GetComponent <MeshFilter>().sharedMesh; if (newMesh == null || !AssetDatabase.Contains(newMesh)) { if (!AssetDatabase.IsValidFolder("Assets/Gear Factory/Meshes")) { AssetDatabase.CreateFolder("Assets/Gear Factory", "Meshes"); } string assetName = AssetDatabase.GenerateUniqueAssetPath("Assets/Gear Factory/Meshes/" + gearGenObject.gameObject.name + ".asset"); AssetDatabase.CreateAsset(newMesh, assetName); AssetDatabase.SaveAssets(); } }
static void Create() { GameObject gameObject = new GameObject("Gear"); GFGear g = (GFGear)gameObject.AddComponent(typeof(GFGear)); GFGearGen gg = (GFGearGen)gameObject.AddComponent(typeof(GFGearGen)); MeshFilter meshFilter = (MeshFilter)gameObject.GetComponent(typeof(MeshFilter)); meshFilter.mesh = new Mesh(); gg.Rebuild(); gameObject.GetComponent <Renderer>().material = new Material(Shader.Find("Diffuse")); if (g.DrivenBy == null) { gg.alignTeethWithParent = false; gg.alignRadiusWithParent = false; } GFGearGenEditor.Persist(gg); }
void OnEnable() { gearObject = (GFGear)this.target; gear = new SerializedObject(this.target); gearNumberOfTeeth = gear.FindProperty("numberOfTeeth"); gearRotateX = gear.FindProperty("rotateX"); gearRotateY = gear.FindProperty("rotateY"); gearRotateZ = gear.FindProperty("rotateZ"); gearAutoAlign = gear.FindProperty("AutoAlign"); gearRadius = gear.FindProperty("radius"); gearTipLength = gear.FindProperty("tipLength"); gearInnerTeeth = gear.FindProperty("innerTeeth"); gearDrivenBy = gear.FindProperty("DrivenBy"); gearAutoSetDrivenBy = gear.FindProperty("AutoSetDrivenBy"); gearReverseRotation = gear.FindProperty("ReverseRotation"); gearReverseRotationPlusSubtree = gear.FindProperty("ReverseRotationPlusSubtree"); gearSyncSpeed = gear.FindProperty("SyncSpeed"); GFGearGen c = (GFGearGen)gearObject.gameObject.GetComponent(typeof(GFGearGen)); hasGFGearGen = c != null; }
/// <summary> /// Aligns the position and rotation to match gear specified in alignTo. /// </summary> /// <param name='alignTo'> /// Align to. /// </param> public void AlignPositions(GFGearGen alignTo) { base.Align(alignTo); }
public void GenerateGear(GFGearGen gearGen) { this.gearGen = gearGen; GameObject gameObject = gearGen.gameObject; mesh = gameObject.GetSharedMesh(); if (mesh != null) { mesh.Clear(); /* * //speed up math by copying the mesh arrays * meshTriangles = mesh.triangles; * meshVertices = mesh.vertices; * meshUv = mesh.uv; * meshNormals = mesh.normals; */ // Clean up (storing these temp lists globally and just clearing them localy prevents the GC to be all nasty on our performance. verticesSideA.Clear(); verticesSideB.Clear(); facesSideA.Clear(); facesSideB.Clear(); vertices.Clear(); faces.Clear(); normals.Clear(); normalsA.Clear(); normalsB.Clear(); centersA.Clear(); centersB.Clear(); // Create vertices CreateSide(ref verticesSideA, ref facesSideA, ref normalsA, ref centersA, false, 0); if (gearGen.is3d) { CreateSide(ref verticesSideB, ref facesSideB, ref normalsB, ref centersB, true, verticesSideA.Count); } vertices.AddRange(verticesSideA); normals.AddRange(normalsA); if (gearGen.is3d) { vertices.AddRange(verticesSideB); normals.AddRange(normalsB); } // Create faces faces.AddRange(facesSideA); if (gearGen.is3d) { faces.AddRange(facesSideB); } // Optimize center vertices when inner radius > threshold if (gearGen.innerRadius > 0.0f) { verticesRemoved = MeshUtils.RemoveDoubles(gearGen.innerMinVertexDistance, vertices, normals, faces, centersA, centersB, facesSideA, facesSideB); } else { verticesRemoved = 0; } if (gearGen.is3d) { CreateGlue(facesSideA, centersA, facesSideB, centersB, ref vertices, ref faces, ref normals); } MeshUtils.SmoothNormals(gearGen.splitVerticesAngle, vertices, normals); verticesRemoved += MeshUtils.RemoveDoubles(0.001f, vertices, normals, faces); // Fill the mesh mesh.vertices = vertices.ToArray(); mesh.uv = GetUVs(mesh.vertices, gearGen.generateTextureCoordinates); mesh.triangles = faces.ToArray(); // Calculate normals /* * if (!gearGen.generateNormals) * { * mesh.RecalculateNormals(); * normals.AddRange(mesh.normals); * } * else * { */ // normals.AddRange(normalsA); // normals.AddRange(normalsB); mesh.normals = normals.ToArray(); //} // Refresh internal parameters MeshUtils.TangentSolver(mesh); mesh.RecalculateBounds(); numberOfVertices = mesh.vertexCount; numberOfFaces = mesh.triangles.Length / 3; } }
void OnSceneGUI() { Rect guiArea = new Rect(10, 10, 110, 150); GFGear gear = (GFGear)this.target; if (!Application.isPlaying) { if (UnityEditor.Selection.Contains(gear.gameObject)) { RecalculateGears(gear); GFGearGen gearGen = gear.gameObject.GetComponent <GFGearGen>(); // Show powered by arrow if (gear.machine == null || (gear.machine != null && gear.machine.ShowPoweredByIndicator)) { gear.DrawPoweredBy(); } if (gearGen == null && gear.AutoAlign) { gear.DrawAlignmentHelpers(); } //GUI.enabled = (gear.DrivenBy != null && (gear.machine == null || (gear.machine != null && gear.machine.ShowPoweredByIndicator))); //Handles.color = Color.white; //Handles.DrawLine(gear.transform.position, GetMouseInWorldCoords(MeshUtils.CalcYAlignedCenterPlane(gear.gameObject), Event.current.mousePosition)); #region GUI.enabled then this is visible. // Note: Not drawing this part is not an option as it will destroy your focus on selected element even if it's visible as being focused. //if (GUI.enabled && gear.machine != null && gear.machine.ShowBox) // gear.DrivenBy.gameObject.DrawBoundingBox(Color.yellow); // Draw unlink button Handles.BeginGUI(); GUILayout.BeginArea(guiArea); if (!isInAddGearMode) { if (gear.DrivenBy != null) { GUIContent gcontent = new GUIContent("Unlink", "Manually override linkage.\r\n- Sets \"Driven By\" to: null\n- Sets \"Auto Set Driven By\" to: false"); if (GUILayout.Button(gcontent)) { gear.DrivenBy = null; gear.AutoSetDrivenBy = false; UnityEditor.EditorUtility.SetDirty(gear); } GUI.enabled = true; if (gearGen != null) { #region auto alignment string label = ""; string hint = ""; bool autoAlign = false; if (gearGen.alignTeethWithParent || gearGen.alignRadiusWithParent) { autoAlign = false; label = "Move freely"; hint = "Switch off auto-alignment.\r\n- Sets \"Align Teeth With Parent\" to: false\r\n- Sets \"Align Radius With Parent\" to: false\r\n"; } else { autoAlign = true; label = "Snap to parent"; hint = "Switches on auto-alignment.\r\n- Sets \"Align Teeth With Parent\" to: true\r\n- Sets \"Align Radius With Parent\" to: true\r\n"; } GUIContent gcontent2 = new GUIContent(label, hint); if (GUILayout.Button(gcontent2)) { gearGen.alignTeethWithParent = autoAlign; gearGen.alignRadiusWithParent = autoAlign; UnityEditor.EditorUtility.SetDirty(gearGen); } #endregion } else { #region auto alignment if (gear.DrivenBy != null) { string label = ""; string hint = ""; if (gear.AutoAlign) { label = "Move freely"; hint = "Switch off auto-alignment.\r\n"; } else { label = "Snap to parent"; hint = "Switches on auto-alignment.\r\n"; } GUIContent gcontent3 = new GUIContent(label, hint); if (GUILayout.Button(gcontent3)) { gear.AutoAlign = !gear.AutoAlign; UnityEditor.EditorUtility.SetDirty(gear); } } #endregion } } if (gearGen != null) { GUIContent gnewgear = new GUIContent("Add single", "Adds a new gear that's linked\r\nto last selected gear.");//GFGearEditor.isInAddGearMode ? "Done" : "Link new gear", "Adds a new gear that's linked to selected gear."); if (GUILayout.Button(gnewgear)) { CloneGear(gear, Vector3.right); } GUIContent gnewgearMulti = new GUIContent("Add multiple", "Add multiple gears.\r\nClick in your scene to specify direction.\r\nRight click when finished."); if (GUILayout.Button(gnewgearMulti)) { isInAddGearMode = true; } GUIContent grandomgear = new GUIContent("Randomize", "Rebuilds current gear with\r\ndifferent randomized settings.");//GFGearEditor.isInAddGearMode ? "Done" : "Link new gear", "Adds a new gear that's linked to selected gear."); if (GUILayout.Button(grandomgear)) { gearGen.Randomize(); } } } else { GUIContent gnewgearMulti = new GUIContent("Done", "Finish adding multiple gears.\r\n"); if (GUILayout.Button(gnewgearMulti)) { cancelAddGearMode = true; } } GUILayout.EndArea(); //GUI.Label(new Rect(Screen.width - 250, Screen.height - 70 - 150, 250, 100), GUI.tooltip); Handles.EndGUI(); #endregion if (gear.machine != null && gear.machine.PoweredGear == gear) { Handles.Label(gear.transform.position + ((gear.radius * 1.30f) * Vector3.up) + (gear.radius * Vector3.left), "Machine powered (Speed:" + gear.machine.speed.ToString() + ")"); } } if (isInAddGearMode || cancelAddGearMode) { if (cancelAddGearMode || Event.current.type != EventType.MouseUp || (Event.current.type == EventType.MouseUp && !guiArea.Contains(Event.current.mousePosition))) { if (Event.current.type == EventType.MouseUp || cancelAddGearMode) { if (Event.current.button == 0 && !cancelAddGearMode) { CloneTowardsMousePos(gear, Event.current.mousePosition); } else { cancelAddGearMode = false; CancelAddGearMode(); } } int controlID = GUIUtility.GetControlID(FocusType.Passive); if (Event.current.type == EventType.Layout) { HandleUtility.AddDefaultControl(controlID); } } } } }
public void RecalculateGears(GFGear g1) { GFGear prevDrivenBy = g1.DrivenBy; if (g1.AutoSetDrivenBy) { g1.DrivenBy = null; } foreach (GFGear otherGear in g1.otherGears) { if (!otherGear.gameObject.Equals(g1.gameObject) && ((g1.AutoSetDrivenBy && g1.Intersects(otherGear)) || !g1.AutoSetDrivenBy)) { // Set initial rotation if (g1.machine == null || (g1.machine != null && g1.machine.PoweredGear != g1)) { if (g1.AutoSetDrivenBy && g1.DrivenBy != otherGear) { // If redundant / circular reference is occuring: restore previous link and abort if (otherGear.DrivenBy == g1) { g1.DrivenBy = prevDrivenBy; } else { g1.DrivenBy = otherGear; } } if (g1.DrivenBy != null) { // If gear is auto generated, we can align the teeth GFGearGen gg1 = g1.GetComponent(typeof(GFGearGen)) as GFGearGen; GFGearGen gg2 = g1.DrivenBy.GetComponent(typeof(GFGearGen)) as GFGearGen; if (gg1 != null && gg2 != null) { if (gg1.alignTeethWithParent) { gg1.Align(gg2); } else { if (gg1.alignRadiusWithParent) { gg1.AlignRadius(gg2); } } } else { // If gear is not auto generated, we can align the positions if autoAlign is true. if (gearAutoAlign.boolValue) { g1.Align(g1.DrivenBy); } } } } // Tell the unity editor we changed something by code, so it gets saved. UnityEditor.EditorUtility.SetDirty(g1); // All aligned and set: get the hell out of this loop! break; } } }