public override void OnInspectorGUI() { Undo.RecordObject(target, "Modified Inspector"); Water2D_Tool water2D = (Water2D_Tool)target; // Render the custom inspector fields. CustomInspector(water2D); if (GUI.changed) { EditorUtility.SetDirty(target); water2D.RecreateWaterMesh(); } if (Event.current.type == EventType.ValidateCommand) { switch (Event.current.commandName) { case "UndoRedoPerformed": water2D.RecreateWaterMesh(); break; } } // A button for updating the Transform Position of the water object. if (GUILayout.Button("Center Position")) { water2D.ReCenterPivotPoint(); } }
private void ResetChildTransform(Water2D_Tool water2D) { if (water2D.cubeWater) { water2D.topMeshGameObject.transform.localPosition = Vector3.zero; water2D.topMeshGameObject.transform.localRotation = Quaternion.identity; water2D.topMeshGameObject.transform.localScale = Vector3.one; } }
void CreateObstructionTextureNow() { if (water2DGameObject == null || water2DGameObject.GetComponent <Water2D_Tool>() == null) { Debug.LogError("Please place a Water 2D Object in the Water Object field."); return; } water2DGameObject.GetComponent <Water2D_Tool>(); water2DTool = water2DGameObject.GetComponent <Water2D_Tool>();; leftHandleGlobalPos = water2DGameObject.transform.TransformPoint(water2DTool.handlesPosition[2]); texWidth = (int)(water2DTool.renderTextureWidth * textureScale); texHeight = (int)(water2DTool.renderTextureHeight * textureScale); Texture2D tex = new Texture2D(texWidth, texHeight, TextureFormat.RGB24, false); tex.wrapMode = TextureWrapMode.Clamp; tex.filterMode = FilterMode.Trilinear; int count = 0; Color color = Color.white; pixelColor = new Color32[texWidth * texHeight]; FillColliderLists(); SetClipPolygon(); WorldPointsToTexture(); for (int y = 0; y < texHeight; y++) { for (int x = 0; x < texWidth; x++) { pixelColor[count] = color; color = Color.white; count++; } } FillObstructionColor(); tex.SetPixels32(pixelColor); tex.Apply(); if (textureName.Length < 1) { textureName = "NewObstructionTexture"; } var bytes = tex.EncodeToPNG(); string path = Application.dataPath + "/Water2D_Tool/Assets/Textures/Obstructions" + "/" + textureName + ".png"; File.WriteAllBytes(path, bytes); AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate); UnityEngine.Object.DestroyImmediate(tex); }
void OnEnable() { texDot = GetGizmo("water2D_circle.png"); selectedPoints.Clear(); Water2D_Tool water2D_Tool = (Water2D_Tool)target; if (water2D_Tool.GetComponent <MeshFilter>().sharedMesh == null) { water2D_Tool.RecreateWaterMesh(); } }
private void CreateTopMeshObject(Water2D_Tool water) { if (water.topMeshGameObject == null) { GameObject obj = new GameObject("new Water2D_TM"); obj.AddComponent <MeshRenderer>(); obj.AddComponent <MeshFilter>(); obj.transform.position = water.transform.position; obj.transform.SetParent(water.transform); water.topMeshGameObject = obj; water.RecreateWaterMesh(); } }
private void DrawOverlapSphereGizmo(Water2D_Tool water) { UnityEditor.Handles.color = Color.blue; Vector3[] vertices = water.GetComponent <MeshFilter>().sharedMesh.vertices; Water2D_Simulation water2D_Sim = water.GetComponent <Water2D_Simulation>(); int surfaceVertsCount = water.frontMeshVertsCount / 2; for (int i = 0; i < surfaceVertsCount; i++) { Vector3 vertexGlobalPos = water.transform.TransformPoint(vertices[i + surfaceVertsCount]); UnityEditor.Handles.DrawWireDisc(new Vector3(vertexGlobalPos.x, vertexGlobalPos.y, vertexGlobalPos.z + water.overlapingSphereZOffset), Vector3.up, water2D_Sim.overlapSphereRadius); UnityEditor.Handles.DrawWireDisc(new Vector3(vertexGlobalPos.x, vertexGlobalPos.y, vertexGlobalPos.z + water.overlapingSphereZOffset), Vector3.forward, water2D_Sim.overlapSphereRadius); } }
private void DrawFlowDirection(Water2D_Tool water) { Handles.color = Color.white; Water2D_Simulation sim = water.GetComponent <Water2D_Simulation>(); float angleInDeg = 0; if (sim.waterFlow) { if (sim.useAngles) { angleInDeg = sim.flowAngle; Handles.ArrowCap(0, water.transform.position, Quaternion.Euler(new Vector3(angleInDeg, 90f, 0)), 1.5f); } } }
void OnSceneGUI() { Water2D_Tool water2D_Tool = (Water2D_Tool)target; EditorUtility.SetSelectedWireframeHidden(water2D_Tool.gameObject.GetComponent <Renderer>(), water2D_Tool.showMesh); GUIStyle iconStyle = new GUIStyle(); iconStyle.alignment = TextAnchor.MiddleCenter; // Setup undoing things Undo.RecordObject(target, "Handles Position"); if (Event.current.type == EventType.repaint) { DrawRectangle(water2D_Tool); DrawFlowDirection(water2D_Tool); } // Draw and interact with the handles. if (water2D_Tool.useHandles) { UpdateHandles(water2D_Tool, iconStyle); } if (Event.current.type == EventType.repaint && water2D_Tool.use3DCollider) { DrawOverlapSphereGizmo(water2D_Tool); } // Update everything that relies on the handles, if the GUI changed. if (GUI.changed) { water2D_Tool.RecreateWaterMesh(); EditorUtility.SetDirty(target); prevChanged = true; } else if (Event.current.type == EventType.used) { if (prevChanged == true) { water2D_Tool.RecreateWaterMesh(); } prevChanged = false; } }
private void DrawRectangle(Water2D_Tool water2D) { Handles.color = Color.white; for (int i = 2; i < 4; i++) { Vector3 pos = water2D.transform.position + water2D.transform.rotation * Vector3.Scale(new Vector3(water2D.handlesPosition[i].x, water2D.handlesPosition[0].y, 0), water2D.transform.localScale); Vector3 pos2 = water2D.transform.position + water2D.transform.rotation * Vector3.Scale(new Vector3(water2D.handlesPosition[i].x, water2D.handlesPosition[1].y, 0), water2D.transform.localScale); Handles.DrawLine(pos, pos2); } for (int i = 0; i < 2; i++) { Vector3 pos = water2D.transform.position + water2D.transform.rotation * Vector3.Scale(new Vector3(water2D.handlesPosition[2].x, water2D.handlesPosition[i].y, 0), water2D.transform.localScale); Vector3 pos2 = water2D.transform.position + water2D.transform.rotation * Vector3.Scale(new Vector3(water2D.handlesPosition[3].x, water2D.handlesPosition[i].y, 0), water2D.transform.localScale); Handles.DrawLine(pos, pos2); } }
static GameObject CreateGPUWater(bool collider2D) { GameObject fmObject = new GameObject("New Water2D_FM"); Water2D_Tool water2DTool = fmObject.AddComponent <Water2D_Tool>(); fmObject.AddComponent <Water2D_Simulation>(); fmObject.AddComponent <Water2D_Ripple>(); water2DTool.Add(new Vector3(0, 3, 0)); water2DTool.Add(new Vector3(0, -3, 0)); water2DTool.Add(new Vector3(-8, 0, 0)); water2DTool.Add(new Vector3(8, 0, 0)); water2DTool.Add(new Vector3(0, 3, 10)); if (!collider2D) { water2DTool.use3DCollider = true; } water2DTool.squareSegments = true; water2DTool.segmentsPerUnit = 4; water2DTool.cubeWater = true; GameObject tmObject = new GameObject("New Water2D_TM"); tmObject.AddComponent <MeshRenderer>(); tmObject.AddComponent <MeshFilter>(); tmObject.AddComponent <Water2D_PlanarReflection>(); tmObject.transform.position = water2DTool.transform.position; tmObject.transform.SetParent(water2DTool.transform); water2DTool.topMeshGameObject = tmObject; water2DTool.SetGPUWaterDefaultMaterial(); water2DTool.RecreateWaterMesh(); fmObject.transform.position = GetSpawnPos(); return(fmObject); }
static GameObject CreateWater2D(bool collider2D) { GameObject obj = new GameObject("New Water2D_FM"); Water2D_Tool water = obj.AddComponent <Water2D_Tool>(); obj.AddComponent <Water2D_Simulation>(); water.Add(new Vector2(0, 3)); water.Add(new Vector2(0, -3)); water.Add(new Vector2(-5, 0)); water.Add(new Vector2(5, 0)); if (!collider2D) { water.use3DCollider = true; } water.SetDefaultMaterial(); water.RecreateWaterMesh(); obj.transform.position = GetSpawnPos(); return(obj); }
void Start() { meshFilter = GetComponent<MeshFilter>().sharedMesh; water2D = GetComponent<Water2D_Tool>(); vertices = meshFilter.vertices; surfaceVertsCount = water2D.surfaceVertsCount / 2; UVs = meshFilter.uv; waterLineCurrentGlobalPos = transform.TransformPoint(vertices[surfaceVertsCount + 1]); waterLineCurrentLocalPos = vertices[surfaceVertsCount + 1].y; waterLinePreviousLocalPos = vertices[surfaceVertsCount + 1].y; defaultWaterHeight = Mathf.Abs(water2D.handlesPosition[0].y - water2D.handlesPosition[1].y); defaultWaterArea = Mathf.Abs(water2D.handlesPosition[0].y - water2D.handlesPosition[1].y) * Mathf.Abs(water2D.handlesPosition[2].x - water2D.handlesPosition[3].x); sineY = new List<float>(); floatingObjects3D = new List<Collider>(); floatingObjects2D = new List<Collider2D>(); waterLinePoints = new List<Vector2>(); foundObjOnPrevFrame = new List<bool>(); foundObjectIn = new List<int>(); tempObj2D = new List<Collider2D>(); tempObj3D = new List<Collider>(); velocities = new List<float>(); accelerations = new List<float>(); leftDeltas = new List<float>(); rightDeltas = new List<float>(); for (int i = 0; i < surfaceVertsCount; i++) { velocities.Add(0.0f); accelerations.Add(0.0f); leftDeltas.Add(0.0f); rightDeltas.Add(0.0f); sineY.Add(0.0f); if (particleSystemInstantiation == Water2D_ParticleSystem.PerVertex && i < surfaceVertsCount - 1) foundObjOnPrevFrame.Add(false); } if (topEdge != null) prevTopEdgeYPos = topEdge.transform.position.y; if (bottomEdge != null) prevBottomEdgeYPos = bottomEdge.transform.position.y; if (leftEdge != null) prevLeftEdgeXPos = leftEdge.transform.position.x; if (rightEdge != null) prevRightEdgeXPos = rightEdge.transform.position.x; if (sineWavesType == Water2D_SineWaves.MultipleSineWaves && randomValues) GenerateSineVariables(); if (surfaceVertsCount > meshSegmentsPerWaterLineSegment) { int n = 0; while (n < surfaceVertsCount) { waterLinePoints.Add(transform.TransformPoint(vertices[surfaceVertsCount + n])); n += meshSegmentsPerWaterLineSegment; } if (meshSegmentsPerWaterLineSegment != 1) { Vector2 lastVert = transform.TransformPoint(vertices[surfaceVertsCount + surfaceVertsCount - 1]); waterLinePoints.Add(new Vector2(lastVert.x, lastVert.y)); } } else { waterLinePoints.Add(transform.TransformPoint(vertices[surfaceVertsCount])); Vector2 lastVert = transform.TransformPoint(vertices[surfaceVertsCount + surfaceVertsCount - 1]); waterLinePoints.Add(new Vector2(lastVert.x, lastVert.y)); } }
private void UpdateHandles(Water2D_Tool water2D, GUIStyle iconStyle) { Quaternion inv = Quaternion.Inverse(water2D.transform.rotation); Handles.color = new Color(1, 1, 1, 0); Vector3 global; for (int i = 0; i < water2D.handlesPosition.Count; i++) { Vector3 pos = water2D.transform.position + Vector3.Scale(new Vector3(water2D.handlesPosition[i].x, water2D.handlesPosition[i].y, water2D.handlesPosition[i].z), water2D.transform.localScale); if (IsVisible(pos)) { SetScale(pos, texDot, ref iconStyle); Handles.Label(pos, new GUIContent(texDot), iconStyle); } if (i < 2) global = Handles.Slider(pos, Vector3.up, HandleScale(pos), Handles.CubeCap, 0); else { if (i == 4) global = Handles.Slider(pos, Vector3.forward, HandleScale(pos), Handles.CubeCap, 0); else global = Handles.Slider(pos, Vector3.right, HandleScale(pos), Handles.CubeCap, 0); } if (global != pos) { selectedPoints.Clear(); selectedPoints.Add(i); Vector3 local = inv * (global - water2D.transform.position); Vector3 relative = new Vector3(local.x / water2D.transform.localScale.x, local.y / water2D.transform.localScale.y, local.z / water2D.transform.localScale.z) - water2D.handlesPosition[i]; water2D.handlesPosition[selectedPoints[0]] += relative; if (i == 0 || i == 1) { float distance = Mathf.Abs(water2D.handlesPosition[0].y - water2D.handlesPosition[1].y); water2D.handlesPosition[2] = new Vector2(water2D.handlesPosition[2].x, water2D.handlesPosition[0].y - distance / 2); water2D.handlesPosition[3] = new Vector2(water2D.handlesPosition[3].x, water2D.handlesPosition[0].y - distance / 2); if(water2D.cubeWater) water2D.handlesPosition[4] = new Vector3(water2D.handlesPosition[0].x, water2D.handlesPosition[0].y, water2D.handlesPosition[4].z); } if (i == 2 || i == 3) { float distance = Mathf.Abs(water2D.handlesPosition[2].x - water2D.handlesPosition[3].x); water2D.handlesPosition[0] = new Vector2(water2D.handlesPosition[2].x + distance / 2, water2D.handlesPosition[0].y); water2D.handlesPosition[1] = new Vector2(water2D.handlesPosition[2].x + distance / 2, water2D.handlesPosition[1].y); if (water2D.cubeWater) water2D.handlesPosition[4] = new Vector3(water2D.handlesPosition[0].x, water2D.handlesPosition[0].y, water2D.handlesPosition[4].z); } if (i == 4) { float distance = Mathf.Abs(water2D.handlesPosition[0].z - water2D.handlesPosition[4].z); water2D.zSize = distance; } } } water2D.curentWaterArea = Mathf.Abs(water2D.handlesPosition[2].x - water2D.handlesPosition[3].x) * Mathf.Abs(water2D.handlesPosition[0].y - water2D.handlesPosition[1].y); }
private void Awake() { rend = GetComponent <Renderer>(); water2D = GetComponentInParent <Water2D_Tool>(); }
private void Awake() { water2D = GetComponentInParent <Water2D_Tool>(); }
//------------------------------------------------------------------------------ private void CustomInspector(Water2D_Tool water) { showVisuals = EditorGUILayout.Foldout(showVisuals, "Visual Properties"); if (showVisuals) { EditorGUI.indentLevel = 1; InspectorBox(10, () => { water.showMesh = !EditorGUILayout.Toggle(new GUIContent("Show Mesh", "Shows or hides the mesh of the water in the scene view"), !water.showMesh); water.verticalTiling = EditorGUILayout.Toggle(new GUIContent("Vertical Tiling", "When enabled will tile the texture horizontally " + "if the water height is greater than the max water height that can be created with the current texture."), water.verticalTiling); water.pixelsPerUnit = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Pixels To Units", "The number of pixels in 1 Unity unit."), water.pixelsPerUnit), 1, 768); water.segmentsPerUnit = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Segments To Units", "The number of horizontal segments " + "that should fit in 1 Unity unit."), water.segmentsPerUnit), 0, 100); Type utility = Type.GetType("UnityEditorInternal.InternalEditorUtility, UnityEditor"); if (utility != null) { PropertyInfo sortingLayerNames = utility.GetProperty("sortingLayerNames", BindingFlags.Static | BindingFlags.NonPublic); if (sortingLayerNames != null) { string[] layerNames = sortingLayerNames.GetValue(null, null) as string[]; string currName = water.GetComponent <Renderer>().sortingLayerName == "" ? "Default" : water.GetComponent <Renderer>().sortingLayerName; int nameID = EditorGUILayout.Popup("Sorting Layer", Array.IndexOf(layerNames, currName), layerNames); water.GetComponent <Renderer>().sortingLayerName = layerNames[nameID]; } else { water.GetComponent <Renderer>().sortingLayerID = EditorGUILayout.IntField("Sorting Layer", water.GetComponent <Renderer>().sortingLayerID); } } else { water.GetComponent <Renderer>().sortingLayerID = EditorGUILayout.IntField("Sorting Layer", water.GetComponent <Renderer>().sortingLayerID); } water.GetComponent <Renderer>().sortingOrder = EditorGUILayout.IntField("Order in Layer", water.GetComponent <Renderer>().sortingOrder); water.handleScale = EditorGUILayout.Slider(new GUIContent("Handle Scale", "Sets the scale of the water handles."), water.handleScale, 0.1f, 10f); pathScale = water.handleScale; water.cubeWater = EditorGUILayout.Toggle(new GUIContent("2.5D Water", "Adds a horizontal mesh at the top of the vertical water mesh."), water.cubeWater); if (water.cubeWater) { water.zSegments = Mathf.Clamp(EditorGUILayout.IntField(new GUIContent("Z Segments", "The number of segments, the horizontal water mesh will have."), water.zSegments), 1, 100); if (water.handlesPosition.Count == 4) { water.handlesPosition.Add(new Vector3(water.handlesPosition[0].x, water.handlesPosition[0].y, water.zSize)); } } water.useHandles = EditorGUILayout.Toggle(new GUIContent("Use Handles", "The water size is changed using handles."), water.useHandles); if (!water.useHandles) { water.waterHeight = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Water Height", "Water height."), water.waterHeight), 0, 1000); water.waterWidth = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Water Width", "Water width."), water.waterWidth), 0, 1000); float pos = water.waterHeight / 2f; water.handlesPosition[0] = new Vector2(0, pos); water.handlesPosition[1] = new Vector2(0, -pos); pos = water.waterWidth / 2f; water.handlesPosition[2] = new Vector2(-pos, 0); water.handlesPosition[3] = new Vector2(pos, 0); if (water.cubeWater) { water.zSize = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Water Z Length", "The size of the water on the Z axis."), water.zSize), 0, 1000); water.handlesPosition[4] = new Vector3(0, water.handlesPosition[0].y, water.zSize); } } if (!water.cubeWater && water.handlesPosition.Count > 4) { water.handlesPosition.RemoveAt(4); } EditorGUILayout.LabelField(new GUIContent("Current Water Area", "The value of this field is not used in any calculations. " + "When creating an animation that animates the area of the water, use this value as a guide to see how the water area changes between two positions."), new GUIContent(water.curentWaterArea.ToString())); }); } EditorGUI.indentLevel = 0; Water2D_Simulation water2D_Sim = water.GetComponent <Water2D_Simulation>(); if (water2D_Sim.waterType == Water2D_Type.Dynamic) { showCollider = EditorGUILayout.Foldout(showCollider, "Collider"); if (showCollider && water.createCollider) { EditorGUI.indentLevel = 1; InspectorBox(10, () => { if (water.createCollider) { water.colliderOffset = EditorGUILayout.FloatField(new GUIContent("Collider Top Offset", "Offsets the position of the top edge of the water collider. " + "This is done so that objects that are a little above the waterline are detected."), water.colliderOffset); if (water.use3DCollider) { water.boxColliderZOffset = EditorGUILayout.FloatField(new GUIContent("Box Collider Z Offset", "Offsets the center of the box collider on the Z axis."), water.boxColliderZOffset); water.boxColliderZSize = EditorGUILayout.FloatField(new GUIContent("Box Collider Z Size", "The size of the box collider on the Z axis."), water.boxColliderZSize); } } }); } EditorGUI.indentLevel = 0; } }
private void CustomInspector(Water2D_Simulation water2D_Sim) { showSpringProperties = EditorGUILayout.Foldout(showSpringProperties, "Spring"); if (showSpringProperties) { EditorGUI.indentLevel = 1; InspectorBox(10, () => { water2D_Sim.springSimulation = EditorGUILayout.Toggle(new GUIContent("Spring Simulation", "Enables the simulation of springs. This what makes the surface of the water react to objects."), water2D_Sim.springSimulation); if (water2D_Sim.springSimulation) { water2D_Sim.springConstant = EditorGUILayout.FloatField(new GUIContent("Spring Constant", "This value controls the stiffness of the springs. " + "A low spring constant will make the springs loose. This means a force will cause large waves that oscillate slowly. A high spring " + "constant will increase the tension in the spring. Forces will create small waves that oscillate quickly."), water2D_Sim.springConstant); water2D_Sim.damping = EditorGUILayout.FloatField(new GUIContent("Damping", "The damping slows down the oscillation of the springs. " + " A high dampening value will make the water look thick like molasses, while a low value will allow the waves to oscillate for a long time."), water2D_Sim.damping); water2D_Sim.spread = EditorGUILayout.FloatField(new GUIContent("Spread", "Controls how fast the waves spread."), water2D_Sim.spread); water2D_Sim.collisionVelocity = EditorGUILayout.FloatField(new GUIContent("Collision Velocity", "Limits the velocity " + " a spring will receive from a falling object."), water2D_Sim.collisionVelocity); water2D_Sim.waveSpeed = EditorGUILayout.FloatField(new GUIContent("Wave Speed", "Another variable to control the spread speed of the waves."), water2D_Sim.waveSpeed); Water2D_Tool water2D_Tool = water2D_Sim.GetComponent <Water2D_Tool>(); if (water2D_Tool.use3DCollider) { water2D_Sim.overlapSphereRadius = EditorGUILayout.FloatField(new GUIContent("Overlap Sphere Radius", "The radius of a sphere that will be used to check " + " if there is a 3D collider near a surface vertex."), water2D_Sim.overlapSphereRadius); } } }); EditorGUI.indentLevel = 0; } if (water2D_Sim.waterType == Water2D_Type.Dynamic) { showfloatingBuoyantForce = EditorGUILayout.Foldout(showfloatingBuoyantForce, "Buoyancy"); if (showfloatingBuoyantForce) { EditorGUI.indentLevel = 1; InspectorBox(10, () => { water2D_Sim.buoyantForceMode = (Water2D_BuoyantForceMode)EditorGUILayout.EnumPopup(new GUIContent("Buoyant Force", "List of methods to simulate the buoyant force. " + "This is what makes the objects float in the water"), water2D_Sim.buoyantForceMode); if (water2D_Sim.buoyantForceMode != Water2D_BuoyantForceMode.None) { if (water2D_Sim.buoyantForceMode == Water2D_BuoyantForceMode.Linear) { water2D_Sim.floatHeight = EditorGUILayout.FloatField(new GUIContent("Float Height", "Determines how much force should be applied to an object submerged " + "in the water. A value of 3 means that 3 m under the water the force applied to an object will be 2 times greater than the force applied at the " + "surface of the water."), water2D_Sim.floatHeight); water2D_Sim.bounceDamping = EditorGUILayout.FloatField(new GUIContent("Bounce Damping", "Slows down the vertical oscillation of the object."), water2D_Sim.bounceDamping); water2D_Sim.liniarBFDragCoefficient = EditorGUILayout.FloatField(new GUIContent("Drag Coefficient", "Determines how much drag force should be applied to an object."), water2D_Sim.liniarBFDragCoefficient); water2D_Sim.liniarBFAbgularDragCoefficient = EditorGUILayout.FloatField(new GUIContent("Angular Drag Coefficient", "Slow down the angular rotation of the object."), water2D_Sim.liniarBFAbgularDragCoefficient); water2D_Sim.forceScale = EditorGUILayout.FloatField(new GUIContent("Force Scale", "A value of 1 will make an object with the mass of " + " 1kg float at the surface of the water and an object with the mass of 2kg float 3m below the water surface if Float Height " + "is set to 3m."), water2D_Sim.forceScale); water2D_Sim.forcePositionOffset = EditorGUILayout.Vector3Field(new GUIContent("Force Position Offset", "By default the force will " + " be applied at the center of the object. Use this to offset the position where the force will be applied to an object."), water2D_Sim.forcePositionOffset); } else { water2D_Sim.clippingMethod = (Water2D_ClippingMethod)EditorGUILayout.EnumPopup(new GUIContent("Polygon Clipping", "Determines which clipping method will be used to calculate the shape of the polygon that is below the water. " + "The simple clipping is the cheapest option in terms of performance because the clipping polygon is always a horizontal line." + "The complex option is best to use when you want the objects to better react to water waves."), water2D_Sim.clippingMethod); if (water2D_Sim.clippingMethod == Water2D_ClippingMethod.Complex) { water2D_Sim.showClippingPlolygon = EditorGUILayout.Toggle(new GUIContent("Show Clipping Polygon", "When enabled will show in the Scene View the shape of the clipping polygon."), water2D_Sim.showClippingPlolygon); water2D_Sim.meshSegmentsPerWaterLineSegment = Mathf.Clamp(EditorGUILayout.IntField(new GUIContent("Water Line Segments", "The number of vertical mesh segments that should fit in a water line segment."), water2D_Sim.meshSegmentsPerWaterLineSegment), 1, 1000); } water2D_Sim.polygonCorners = Mathf.Clamp(EditorGUILayout.IntField(new GUIContent("Polygon Vertices", "When an object with a circleCollider2D " + "is detected an imaginary regular polygon collider is created based on its radius and position. " + "Use this to set the number of vertices the regular polygon collider should have."), water2D_Sim.polygonCorners), 3, 100); water2D_Sim.maxDrag = EditorGUILayout.FloatField(new GUIContent("Max Drag", "The max drag force that should be applied to an object."), water2D_Sim.maxDrag); water2D_Sim.dragCoefficient = EditorGUILayout.FloatField(new GUIContent("Drag Coefficient", "Determines how much drag force should be applied to an object."), water2D_Sim.dragCoefficient); water2D_Sim.maxLift = EditorGUILayout.FloatField(new GUIContent("Max Lift", "The max lift force that should be applied to an object."), water2D_Sim.maxLift); water2D_Sim.liftCoefficient = EditorGUILayout.FloatField(new GUIContent("Lift Coefficient", "Determines how much lift force should be applied to an object."), water2D_Sim.liftCoefficient); water2D_Sim.waterDensity = EditorGUILayout.FloatField(new GUIContent("Water Density", "Sets the water density. In a water with low " + " density the objects will submerge faster and come to the surface slower. If the water density is great the objects will " + "stay more at the surface of the water and will submerge slower."), water2D_Sim.waterDensity); water2D_Sim.showPolygon = EditorGUILayout.Toggle(new GUIContent("Show Polygon Shape", "When enabled will show in the Scene View the shape of the polygon that is below the waterline."), water2D_Sim.showPolygon); water2D_Sim.showForces = EditorGUILayout.Toggle(new GUIContent("Show Forces", "When enabled will show in the Scene View the velocity direction, drag direction, " + "lift direction and the normal of a leading edge."), water2D_Sim.showForces); } } }); EditorGUI.indentLevel = 0; showFlow = EditorGUILayout.Foldout(showFlow, "Flow"); if (showFlow) { EditorGUI.indentLevel = 1; InspectorBox(10, () => { water2D_Sim.waterFlow = EditorGUILayout.Toggle(new GUIContent("Water Flow", "When enabled, the water flow will affect the objects in the water."), water2D_Sim.waterFlow); if (water2D_Sim.waterFlow) { water2D_Sim.useAngles = EditorGUILayout.Toggle(new GUIContent("Use Angles", "Enable this if you want to control the direction of the water flow using custom angle values."), water2D_Sim.useAngles); if (!water2D_Sim.useAngles) { water2D_Sim.flowDirection = (Water2D_FlowDirection)EditorGUILayout.EnumPopup(new GUIContent("Flow Direction", "The direction of the water flow."), water2D_Sim.flowDirection); } if (water2D_Sim.useAngles) { water2D_Sim.flowAngle = EditorGUILayout.FloatField(new GUIContent("Flow Angle", "The angle of the water flow. " + "When set to 0 degrees the objects will be pushed to the left, " + "when set to 90 degrees the objects will be pushed down, when set to 180 degrees the objects will " + "be pushed to the right, when set to 270 degrees the objects will be pushed up."), water2D_Sim.flowAngle); } water2D_Sim.waterFlowForce = EditorGUILayout.FloatField(new GUIContent("Flow Force", "The force of the water flow."), water2D_Sim.waterFlowForce); } }); } } EditorGUI.indentLevel = 0; } showAnimation = EditorGUILayout.Foldout(showAnimation, "Animation"); if (showAnimation) { EditorGUI.indentLevel = 1; InspectorBox(10, () => { water2D_Sim.animationMethod = (Water2D_AnimationMethod)EditorGUILayout.EnumPopup(new GUIContent("Animation Method", "Determines the animation method for the handles position."), water2D_Sim.animationMethod); if (water2D_Sim.animationMethod != Water2D_AnimationMethod.None) { water2D_Sim.animateWaterArea = EditorGUILayout.Toggle(new GUIContent("Animate Water Area", "Enable this " + "if you want to animate the increase or decrease of the total water area."), water2D_Sim.animateWaterArea); if (!water2D_Sim.animateWaterArea) { water2D_Sim.topEdge = EditorGUILayout.ObjectField(new GUIContent("Top Edge", "Place here an animated object " + "you want the water line (the top of the water) to follow."), water2D_Sim.topEdge, typeof(Transform), true) as Transform; } water2D_Sim.bottomEdge = EditorGUILayout.ObjectField(new GUIContent("Bottom Edge", "Place here an animated object " + "you want the bottom edge of the water to follow."), water2D_Sim.bottomEdge, typeof(Transform), true) as Transform; water2D_Sim.leftEdge = EditorGUILayout.ObjectField(new GUIContent("Left Edge", "Place here an animated object you " + " want the left edge of the water to follow."), water2D_Sim.leftEdge, typeof(Transform), true) as Transform; water2D_Sim.rightEdge = EditorGUILayout.ObjectField(new GUIContent("Right Edge", "Place here an animated object " + "you want the right edge of the water to follow."), water2D_Sim.rightEdge, typeof(Transform), true) as Transform; if (water2D_Sim.animationMethod == Water2D_AnimationMethod.Snap) { if (!water2D_Sim.animateWaterArea) { water2D_Sim.topEdgeYOffset = EditorGUILayout.FloatField(new GUIContent("Top Edge Y Offset", "The offset on the Y axis from the position of a referenced object."), water2D_Sim.topEdgeYOffset); } water2D_Sim.bottomEdgeYOffset = EditorGUILayout.FloatField(new GUIContent("Bottom Edge Y Offset", "The offset on the Y axis from the position of a referenced object."), water2D_Sim.bottomEdgeYOffset); water2D_Sim.leftEdgeXOffset = EditorGUILayout.FloatField(new GUIContent("Left Edge X Offset", "The offset on the X axis from the position of a referenced object."), water2D_Sim.leftEdgeXOffset); water2D_Sim.rightEdgeXOffset = EditorGUILayout.FloatField(new GUIContent("Right Edge X Offset", "The offset on the X axis from the position of a referenced object."), water2D_Sim.rightEdgeXOffset); } if (water2D_Sim.animateWaterArea && water2D_Sim.topEdge != null) { water2D_Sim.topEdge = null; } } }); } EditorGUI.indentLevel = 0; showSurfaceWaves = EditorGUILayout.Foldout(showSurfaceWaves, "Surface Waves"); if (showSurfaceWaves) { EditorGUI.indentLevel = 1; InspectorBox(10, () => { water2D_Sim.surfaceWaves = (Water2D_SurfaceWaves)EditorGUILayout.EnumPopup(new GUIContent("Surface Waves", "List of methods to generate surface waves. Random" + " method generates small random splashes. Sine wave method overlaps a number of sine waves to get a final wave that changes the velocity of the surface vertices."), water2D_Sim.surfaceWaves); if (water2D_Sim.surfaceWaves != Water2D_SurfaceWaves.None) { if (water2D_Sim.surfaceWaves == Water2D_SurfaceWaves.SineWaves) { water2D_Sim.sineWavesType = (Water2D_SineWaves)EditorGUILayout.EnumPopup(new GUIContent("Sine Waves", "The type of sine waves to use. If you want to animate the amplitude and stretch of the sine wave use the Single Sine Wave option."), water2D_Sim.sineWavesType); if (water2D_Sim.springSimulation) { water2D_Sim.useControlPoints = EditorGUILayout.Toggle(new GUIContent("Control Points", "When enabled only the velocity of the control point will be affected by the sine wave."), water2D_Sim.useControlPoints); } if (water2D_Sim.useControlPoints && water2D_Sim.springSimulation) { water2D_Sim.controlPointPos = (Water2D_ControlPointPosition)EditorGUILayout.EnumPopup(new GUIContent("Control Point Position", "Sets the position of the control point. " + "The vertex whose velocity will be controlled by the animator or a script."), water2D_Sim.controlPointPos); } if (water2D_Sim.sineWavesType == Water2D_SineWaves.MultipleSineWaves) { water2D_Sim.randomValues = EditorGUILayout.Toggle(new GUIContent("Random Values", "When enabled, the amplitude, stretch and phase offset will be random values for each sine wave."), water2D_Sim.randomValues); } if (water2D_Sim.sineWavesType == Water2D_SineWaves.MultipleSineWaves) { water2D_Sim.sineWaves = Mathf.Clamp(EditorGUILayout.IntField(new GUIContent("Sine Waves Number", "The number of individual sine waves."), water2D_Sim.sineWaves), 1, 100); if (water2D_Sim.randomValues) { water2D_Sim.maxAmplitude = EditorGUILayout.FloatField(new GUIContent("Max Amplitude", "The constant is used to generate a random amplitude value between a Max and a Min. Controls the height of the sine wave."), water2D_Sim.maxAmplitude); water2D_Sim.minAmplitude = EditorGUILayout.FloatField(new GUIContent("Min Amplitude", "The constant is used to generate a random amplitude value between a Max and a Min. Controls the height of the sine wave."), water2D_Sim.minAmplitude); water2D_Sim.maxStretch = EditorGUILayout.FloatField(new GUIContent("Max Stretch", "The constant is used to generate a random sine wave stretch value between a Max and a Min. " + "The bigger the value of the stretch the more compact the waves are."), water2D_Sim.maxStretch); water2D_Sim.minStretch = EditorGUILayout.FloatField(new GUIContent("Min Stretch", "The constant is used to generate a random sine wave stretch value between a Max and a Min. " + "The bigger the value of the stretch the more compact the waves are."), water2D_Sim.minStretch); water2D_Sim.maxPhaseOffset = EditorGUILayout.FloatField(new GUIContent("Max Phase Offset", "The constant is used to generate a random phase offset value between a Max and a Min. " + "The bigger the value of the phase offset the faster the waves move to the left (right)."), water2D_Sim.maxPhaseOffset); water2D_Sim.minPhaseOffset = EditorGUILayout.FloatField(new GUIContent("Min Phase Offset", "The constant is used to generate a random phase offset value between a Max and a Min. " + "The bigger the value of the phase offset the faster the waves move to the left (right)."), water2D_Sim.minPhaseOffset); } else { if (water2D_Sim.sineAmplitudes.Count != water2D_Sim.sineWaves) { water2D_Sim.sineAmplitudes.Clear(); water2D_Sim.sineStretches.Clear(); water2D_Sim.phaseOffset.Clear(); for (int i = 0; i < water2D_Sim.sineWaves; i++) { water2D_Sim.sineAmplitudes.Add(Random.Range(water2D_Sim.minAmplitude, water2D_Sim.maxAmplitude)); water2D_Sim.sineStretches.Add(Random.Range(water2D_Sim.minStretch, water2D_Sim.maxStretch)); water2D_Sim.phaseOffset.Add(Random.Range(water2D_Sim.minPhaseOffset, water2D_Sim.maxPhaseOffset)); } } else { int n = 0; for (int i = 0; i < water2D_Sim.sineWaves; i++) { n = i + 1; EditorGUILayout.Foldout(true, "Sine Wave " + n); water2D_Sim.sineAmplitudes[i] = EditorGUILayout.FloatField(new GUIContent("Amplitude", "The amplitude of the wave. This value controls the height of the sine wave."), water2D_Sim.sineAmplitudes[i]); water2D_Sim.sineStretches[i] = EditorGUILayout.FloatField(new GUIContent("Stretch", "The bigger the value of the stretch the more compact the waves are."), water2D_Sim.sineStretches[i]); water2D_Sim.phaseOffset[i] = EditorGUILayout.FloatField(new GUIContent("Phase Offset", "The bigger the value of the phase offset the faster the waves move to the left (right). " + " A negative value will make the sine wave move to the right."), water2D_Sim.phaseOffset[i]); } } } } else { water2D_Sim.waveAmplitude = EditorGUILayout.FloatField(new GUIContent("Wave Amplitude", "The amplitude of the wave. This value controls the height of the sine wave."), water2D_Sim.waveAmplitude); water2D_Sim.waveStretch = EditorGUILayout.FloatField(new GUIContent("Wave Stretch", "The bigger the value of the stretch the more compact the waves are."), water2D_Sim.waveStretch); water2D_Sim.wavePhaseOffset = EditorGUILayout.FloatField(new GUIContent("Wave Phase Offset", "The bigger the value of the phase offset the faster the waves move to the left (right)." + " A negative value will make the sine wave move to the right."), water2D_Sim.wavePhaseOffset); } water2D_Sim.sineWaveVelocityScale = EditorGUILayout.FloatField(new GUIContent("Sine Wave Velocity Scale", "Will scale down (up) the velocity that is applied to a vertex from a sine wave."), water2D_Sim.sineWaveVelocityScale); } if (water2D_Sim.surfaceWaves == Water2D_SurfaceWaves.RandomSplashes) { water2D_Sim.timeStep = EditorGUILayout.FloatField(new GUIContent("Wave Time Step", "The time between splashes."), water2D_Sim.timeStep); water2D_Sim.maxVelocity = EditorGUILayout.FloatField(new GUIContent("Max Velocity", "The constant is used to generate a random velocity between a Max and a Min."), water2D_Sim.maxVelocity); water2D_Sim.minVelocity = EditorGUILayout.FloatField(new GUIContent("Min Velocity", "The constant is used to generate a random velocity between a Max and a Min."), water2D_Sim.minVelocity); water2D_Sim.neighborVertVelocityScale = EditorGUILayout.FloatField(new GUIContent("Neighbor Vertex Velocity Scale", "Will scale down (up) the velocity that " + "is applied to the neighbor vertices when RandomWave method is called."), water2D_Sim.neighborVertVelocityScale); } if (water2D_Sim.surfaceWaves == Water2D_SurfaceWaves.ControlPoint && water2D_Sim.springSimulation) { water2D_Sim.controlPointPos = (Water2D_ControlPointPosition)EditorGUILayout.EnumPopup(new GUIContent("Control Point Position", "Sets the position of the control point. " + "The vertex whose velocity will be controlled by the animator or a script."), water2D_Sim.controlPointPos); } if (water2D_Sim.surfaceWaves == Water2D_SurfaceWaves.ControlPoint && !water2D_Sim.springSimulation) { EditorGUILayout.HelpBox("The waves will not be generated if the spring simulation is disabled!", MessageType.Warning); } } }); EditorGUI.indentLevel = 0; } EditorGUI.indentLevel = 0; showMiscellaneous = EditorGUILayout.Foldout(showMiscellaneous, "Miscellaneous"); if (showMiscellaneous) { EditorGUI.indentLevel = 1; InspectorBox(10, () => { water2D_Sim.waterType = (Water2D_Type)EditorGUILayout.EnumPopup(new GUIContent("Water Type", "A list of water types. " + "A dynamic water can be animated and reacts to objects. A decorative water can be animated, but will not react " + " to objects and will not influence their position."), water2D_Sim.waterType); if (water2D_Sim.waterType == Water2D_Type.Decorative) { Water2D_Tool water2D_Tool = water2D_Sim.GetComponent <Water2D_Tool>(); if (water2D_Tool.createCollider) { water2D_Tool.createCollider = false; water2D_Tool.RecreateWaterMesh(); } } else { Water2D_Tool water2D_Tool = water2D_Sim.GetComponent <Water2D_Tool>(); if (!water2D_Tool.createCollider) { water2D_Tool.createCollider = true; water2D_Tool.RecreateWaterMesh(); } } if (water2D_Sim.waterType == Water2D_Type.Dynamic) { water2D_Sim.velocityFilter = EditorGUILayout.FloatField(new GUIContent("Velocity Filter", "An object with a velocity on the Y axis " + " greater than the value of Velocity Filter will not create splashes."), water2D_Sim.velocityFilter); water2D_Sim.interactionRegion = EditorGUILayout.FloatField(new GUIContent("Interaction Region", "The bottom region of a colliders bounding box " + "that can affect the velocity of a vertex. This value is used to limit the ability of the objects with big bounding boxes to affect the " + "velocity of the surface vertices. A value of 1 means that only the first 1m of the bottom of the bounding box will affect the velocity " + "of the surface vertices. "), water2D_Sim.interactionRegion); water2D_Sim.playerBoundingBoxSize = EditorGUILayout.Vector2Field(new GUIContent("Player BBox Size", "The size for the players bounding box. In most cases the player character will have more than one collider. " + "So to simplify the things, Water2D uses this variable to set the size for an imaginary bounding box that will be used when applying buoyant force. "), water2D_Sim.playerBoundingBoxSize); water2D_Sim.playerBoundingBoxCenter = EditorGUILayout.Vector2Field(new GUIContent("Player BBox Center", "By default the center of the bounding box will be " + "the transform.position of the object. Use this variable to offset the players bounding box center."), water2D_Sim.playerBoundingBoxCenter); water2D_Sim.playerBuoyantForceScale = EditorGUILayout.FloatField(new GUIContent("Player Buoyant Force Scale", "Depending on what character controller you are using, you may have a big character " + "that must have a small mass. As a result the Player will not submerge in the water because of its low mass that results in low density. To resolve this problem use this variable to scale " + "down the buoyant force applied to the Player."), water2D_Sim.playerBuoyantForceScale); water2D_Sim.waterDisplacement = EditorGUILayout.Toggle(new GUIContent("Water Displacement", "Floating objects will influence the final water area."), water2D_Sim.waterDisplacement); } water2D_Sim.constantWaterArea = EditorGUILayout.Toggle(new GUIContent("Constant Water Area", "If the width of the water changes, the height will " + " change too, to keep a constant water Area."), water2D_Sim.constantWaterArea); if (water2D_Sim.waterType == Water2D_Type.Dynamic) { water2D_Sim.particleSystemInstantiation = (Water2D_ParticleSystem)EditorGUILayout.EnumPopup(new GUIContent("PS Instantiation", "Controls how the particle systems are instantiated. " + "When Per Object option is selected, a single particle system will be instantiated per object. When Per Vertex option is selected, a particle system object will " + "be instantiated for every vertex that is overlapping the interaction region of the object in the water."), water2D_Sim.particleSystemInstantiation); water2D_Sim.particleS = EditorGUILayout.ObjectField(new GUIContent("PS Prefab", "A particle system prefab used to simulate the water splash effect."), water2D_Sim.particleS, typeof(GameObject), true) as GameObject; water2D_Sim.particleSystemPosOffset = EditorGUILayout.Vector3Field(new GUIContent("PS Position Offset", "Offsets the position where the particle systems are created on the Z axis."), water2D_Sim.particleSystemPosOffset); water2D_Sim.particleSystemSorting = EditorGUILayout.Toggle(new GUIContent("PS Sorting", "Enable this toggle if you want to set the sorting layer and order in layer of the particle system when it is instantiated."), water2D_Sim.particleSystemSorting); if (water2D_Sim.particleSystemSorting) { water2D_Sim.particleSystemSortingLayerName = EditorGUILayout.TextField(new GUIContent("PS Sorting Layer Name", "Insert here the sorting layer name for the particle system."), water2D_Sim.particleSystemSortingLayerName); water2D_Sim.particleSystemOrderInLayer = EditorGUILayout.IntField(new GUIContent("PS Order In Layer", "Insert here the order in layer for the particle system."), water2D_Sim.particleSystemOrderInLayer); } water2D_Sim.splashSound = EditorGUILayout.ObjectField(new GUIContent("Sound Effect", "A sound effect generated when an object hits the water surface."), water2D_Sim.splashSound, typeof(AudioClip), true) as AudioClip; } }); } EditorGUI.indentLevel = 0; }
private void CustomInspector(Water2D_Ripple water2D_Ripple) { Water2D_Tool water2D = water2D_Ripple.GetComponent <Water2D_Tool>(); Water2D_Simulation water2DSim = water2D_Ripple.GetComponent <Water2D_Simulation>(); BoldFontStyle(() => { water2D_Ripple.showWaterRipple = EditorGUILayout.Foldout(water2D_Ripple.showWaterRipple, "Water Properties"); }); if (water2D_Ripple.showWaterRipple) { InspectorBox(10, () => { EditorGUI.BeginChangeCheck(); water2D_Ripple.rippleSimulationUpdate = (Water2D_RippleSimulationUpdate)EditorGUILayout.EnumPopup(new GUIContent("Run Simulation In"), water2D_Ripple.rippleSimulationUpdate); if (water2D_Ripple.rippleSimulationUpdate == Water2D_RippleSimulationUpdate.FixedUpdateMethod) { EditorGUILayout.HelpBox("For smooth looking wave movement it is recommended to use Fixed Update Method with physics based character controllers.", MessageType.Info); } if (water2D_Ripple.rippleSimulationUpdate == Water2D_RippleSimulationUpdate.UpdateMethod) { EditorGUILayout.HelpBox("For smooth looking wave movement it is recommended to use Update Method with raycast based character controllers.", MessageType.Info); } if (EditorGUI.EndChangeCheck() && Application.isPlaying) { water2D_Ripple.rainTimeCounter = 0; water2D_Ripple.heightMapTimeCounter = 0; } if (water2D_Ripple.rippleSimulationUpdate == Water2D_RippleSimulationUpdate.UpdateMethod) { EditorGUI.BeginChangeCheck(); water2D_Ripple.rippleWaterFPSCap = EditorGUILayout.Slider(new GUIContent("Simulation Speed", "Determines how many times per second should the height map be processed through the shader that simulates ripple propagation."), water2D_Ripple.rippleWaterFPSCap, 1, 120); if (EditorGUI.EndChangeCheck()) { water2D_Ripple.heightUpdateMapTimeStep = 1f / water2D_Ripple.rippleWaterFPSCap; water2D_Ripple.heightMapTimeCounter = 0; water2D_Ripple.interactionsTimeCounter = 0; } } EditorGUI.BeginChangeCheck(); water2D_Ripple.waterDamping = EditorGUILayout.Slider(new GUIContent("Damping", "Damping parameter for the water propagation simulation."), water2D_Ripple.waterDamping, 0, 1); if (EditorGUI.EndChangeCheck() && Application.isPlaying) { water2D_Ripple.UpdateRippleShaderParameters(); } EditorGUI.BeginChangeCheck(); water2D_Ripple.rtPixelsToUnits = EditorGUILayout.IntField(new GUIContent("RT Pixels To Units", "The number of Render Texture pixels that should fit in 1 unit of Unity space."), water2D_Ripple.rtPixelsToUnits); if (EditorGUI.EndChangeCheck()) { water2D.RecreateWaterMesh(); } water2D_Ripple.bicubicResampling = EditorGUILayout.Toggle(new GUIContent("Bicubic Resampling", "Applies a smoothing effect to the heightmap." + " Eliminates pixelation artifacts. This makes the generated normal map look smoother."), water2D_Ripple.bicubicResampling); EditorGUI.BeginChangeCheck(); water2D_Ripple.drawBothSides = EditorGUILayout.Toggle(new GUIContent("Draw Both Sides", "Enabling this will make both sides of the top mesh to be drawn when the camera is below the water line."), water2D_Ripple.drawBothSides); if (EditorGUI.EndChangeCheck() && Application.isPlaying) { water2D_Ripple.SetTopMeshCulling(); } EditorGUI.BeginChangeCheck(); water2D_Ripple.waveHeightScale = EditorGUILayout.FloatField(new GUIContent("Wave Height Scale", "The scale of the ripples created by objects or rain."), water2D_Ripple.waveHeightScale); if (EditorGUI.EndChangeCheck()) { if (Application.isPlaying) { water2D_Ripple.SetWaveHeightScale(); } else { water2D.GetComponent <Renderer>().sharedMaterial.SetFloat("_WaveHeightScale", water2D_Ripple.waveHeightScale); water2D.topMeshGameObject.GetComponent <Renderer>().sharedMaterial.SetFloat("_WaveHeightScale", water2D_Ripple.waveHeightScale); } } EditorGUI.BeginChangeCheck(); water2D_Ripple.obstructionType = (Water2D_ObstructionType)EditorGUILayout.EnumPopup(new GUIContent("Obstruction Type", "List of obstruction methods."), water2D_Ripple.obstructionType); if (EditorGUI.EndChangeCheck() && Application.isPlaying) { water2D_Ripple.UpdateRippleShaderParameters(); } if (water2D_Ripple.obstructionType == Water2D_ObstructionType.DynamicObstruction && !water2D.use3DCollider) { EditorGUILayout.HelpBox("Dynamic Obstruction only works with objects that have a Box Collider or a Sphere Collider", MessageType.Warning); } if (water2D_Ripple.obstructionType == Water2D_ObstructionType.DynamicObstruction) { water2D_Ripple.obstructionLayers = (LayerMask)EditorGUILayout.MaskField("Obstruction Layers", water2D_Ripple.obstructionLayers, InternalEditorUtility.layers); } if (water2D_Ripple.obstructionType == Water2D_ObstructionType.TextureObstruction) { water2D_Ripple.obstructionTexture = EditorGUILayout.ObjectField(new GUIContent("Obstruction Texture"), water2D_Ripple.obstructionTexture, typeof(Texture2D), true) as Texture2D; } }); } BoldFontStyle(() => { water2D_Ripple.showDynamicObjects = EditorGUILayout.Foldout(water2D_Ripple.showDynamicObjects, "Dynamic Objects"); }); if (water2D_Ripple.showDynamicObjects) { InspectorBox(10, () => { if (water2D.use3DCollider) { water2D_Ripple.fixedRadius = EditorGUILayout.Toggle(new GUIContent("Fixed Radius", "When enabled, the radius of the ripple created by dynamic objects will be the same for all objects. " + "When disabled the radius of the ripple depends on the collider of that object."), water2D_Ripple.fixedRadius); } if (!water2D.use3DCollider && !water2D_Ripple.fixedRadius) { water2D_Ripple.fixedRadius = true; } if (water2D_Ripple.fixedRadius) { water2D_Ripple.objectRippleRadius = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Radius", "The radius of the ripple created by a dynamic object."), water2D_Ripple.objectRippleRadius), 0.000001f, 100f); } if (!water2D_Ripple.fixedRadius) { water2D_Ripple.objectRadiusScale = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Radius Scale", "Scales up or down the ripple radius. " + "The radius of the ripple created by dynamic objects depends on the size of that objects collider."), water2D_Ripple.objectRadiusScale), 0.000001f, 1000f); } water2D_Ripple.objectRippleStrength = EditorGUILayout.FloatField(new GUIContent("Strength", "The strength of the ripple created by dynamic objects."), water2D_Ripple.objectRippleStrength); water2D_Ripple.strengthScale = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Y Axis Strength Scale", "Used to scale up or down the strength of the ripples " + "created by dynamic objects when the Abs value of the velocity on the Y axis is greater than the Abs value of the velocity on the X axis."), water2D_Ripple.strengthScale), 0.000001f, 1000f); water2D_Ripple.objectVelocityFilter = EditorGUILayout.FloatField(new GUIContent("Velocity Filter", "If the Abs value of a dynamic object velocity on the X and Y axis is smaller than the value of this field, no ripples will be generated by that object."), water2D_Ripple.objectVelocityFilter); water2D_Ripple.objectXAxisRippleOffset = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("X Axis Relative Offset", "Offsets the ripple position on the X axis based on the width of the colliders bounding box. A value of 0 means that the ripple will be generated at the center of the collider. " + " A value of 0.5f means that the ripple will be positioned at the left or right edge of the colliders bounding box."), water2D_Ripple.objectXAxisRippleOffset), 0, 100f); }); } EditorGUI.indentLevel = 0; BoldFontStyle(() => { water2D_Ripple.showPlayer = EditorGUILayout.Foldout(water2D_Ripple.showPlayer, "Player"); }); if (water2D_Ripple.showPlayer) { InspectorBox(10, () => { water2D_Ripple.playerRippleRadius = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Radius", "The radius of the ripple created by the player."), water2D_Ripple.playerRippleRadius), 0.0000001f, 1000f); water2D_Ripple.playerRippleStrength = EditorGUILayout.FloatField(new GUIContent("Strength", "The strength of the ripple created by the player."), water2D_Ripple.playerRippleStrength); if (water2DSim.characterControllerType == Water2D_CharacterControllerType.PhysicsBased) { water2D_Ripple.playerVelocityFilter = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Velocity Filter", "If the Abs value of the player velocity on the X and Y axis is smaller than the value of this field, no ripples will be generated by the player."), water2D_Ripple.playerVelocityFilter), 0.0000001f, 100f); } water2D_Ripple.playerRippleXOffset = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("X Axis Position Offset", "Offsets the position of the ripple created by the player on the X axis."), water2D_Ripple.playerRippleXOffset), 0, 1000f); }); } EditorGUI.indentLevel = 0; BoldFontStyle(() => { water2D_Ripple.showRain = EditorGUILayout.Foldout(water2D_Ripple.showRain, "Rain"); }); if (water2D_Ripple.showRain) { InspectorBox(10, () => { water2D_Ripple.rainDrops = EditorGUILayout.Toggle(new GUIContent("Enable Rain", "Enables the simulation of rain."), water2D_Ripple.rainDrops); if (water2D_Ripple.rainDrops) { water2D_Ripple.rainDropRadius = EditorGUILayout.FloatField(new GUIContent("Drop Radius", "The radius of a rain drop in Unity space."), water2D_Ripple.rainDropRadius); water2D_Ripple.rainDropStrength = EditorGUILayout.FloatField(new GUIContent("Drop Strength", "The strength of a rain drop."), water2D_Ripple.rainDropStrength); water2D_Ripple.rainDropFrequency = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Drop Frequency", "The number of water drops that should fall in a second."), water2D_Ripple.rainDropFrequency), 0.0001f, 1000f); } }); } BoldFontStyle(() => { water2D_Ripple.showRippleSourcesList = EditorGUILayout.Foldout(water2D_Ripple.showRippleSourcesList, "Ripple Sources"); }); if (water2D_Ripple.showRippleSourcesList) { InspectorBox(10, () => { water2D_Ripple.rippleSources = EditorGUILayout.Toggle(new GUIContent("Enable Ripple Sources"), water2D_Ripple.rippleSources); if (water2D_Ripple.rippleSources) { water2D_Ripple.rippleSourcesSize = Mathf.Clamp(EditorGUILayout.IntField(new GUIContent("Size"), water2D_Ripple.rippleSourcesSize), 1, 200); if (water2D_Ripple.rippleSourcesList == null) { water2D_Ripple.rippleSourcesList.Add(null); } if (water2D_Ripple.rippleSourcesSize != water2D_Ripple.rippleSourcesList.Count) { if (water2D_Ripple.rippleSourcesSize > water2D_Ripple.rippleSourcesList.Count) { while (water2D_Ripple.rippleSourcesSize > water2D_Ripple.rippleSourcesList.Count) { water2D_Ripple.rippleSourcesList.Add(null); } } else { while (water2D_Ripple.rippleSourcesSize < water2D_Ripple.rippleSourcesList.Count) { int last = water2D_Ripple.rippleSourcesList.Count - 1; water2D_Ripple.rippleSourcesList.RemoveAt(last); } } } for (int i = 0; i < water2D_Ripple.rippleSourcesList.Count; i++) { water2D_Ripple.rippleSourcesList[i] = EditorGUILayout.ObjectField(new GUIContent("Element " + i), water2D_Ripple.rippleSourcesList[i], typeof(RippleSource), true) as RippleSource; } } }); } if (water2D.use3DCollider) { BoldFontStyle(() => { water2D_Ripple.showMouse = EditorGUILayout.Foldout(water2D_Ripple.showMouse, "Mouse Interaction"); }); if (water2D_Ripple.showMouse) { InspectorBox(10, () => { water2D_Ripple.mouseInteraction = EditorGUILayout.Toggle(new GUIContent("Enable Mouse Interaction", "Enables the ability to interact with the water using the mouse arrow."), water2D_Ripple.mouseInteraction); if (water2D_Ripple.mouseInteraction) { water2D_Ripple.mouseRadius = EditorGUILayout.FloatField(new GUIContent("Mouse Radius", "The radius of the ripple created by the mouse arrow, in Unity space."), water2D_Ripple.mouseRadius); water2D_Ripple.mouseStregth = EditorGUILayout.FloatField(new GUIContent("Mouse Strength", "The strength of the ripple created by the mouse arrow."), water2D_Ripple.mouseStregth); } }); } } BoldFontStyle(() => { water2D_Ripple.showAmbiantWaves = EditorGUILayout.Foldout(water2D_Ripple.showAmbiantWaves, "Ambient Waves"); }); if (water2D_Ripple.showAmbiantWaves) { InspectorBox(10, () => { EditorGUI.BeginChangeCheck(); water2D_Ripple.ambientWaves = EditorGUILayout.Toggle(new GUIContent("Enable Ambient Waves", "Enable this to simulate waves created by the wind."), water2D_Ripple.ambientWaves); if (water2D_Ripple.ambientWaves) { water2D_Ripple.amplitudeZAxisFade = EditorGUILayout.Toggle(new GUIContent("Z Axis Amplitude Fade", "When enabled the amplitude of the sine waves will fade along the Z axis."), water2D_Ripple.amplitudeZAxisFade); if (water2D_Ripple.amplitudeZAxisFade) { water2D_Ripple.amplitudeFadeStart = EditorGUILayout.Slider(new GUIContent("Fade Start", "The start point of the amplitude fade. Can also be used to set the direction of the amplitude fade. If the start point value is greater than the end point, the amplitude will fade from back to front."), water2D_Ripple.amplitudeFadeStart, 0, 1.0f); water2D_Ripple.amplitudeFadeEnd = EditorGUILayout.Slider(new GUIContent("Fade End", "The end point of the amplitude fade. Can also be used to set the direction of the amplitude fade. If the end point value is greater than the start point, the amplitude will fade towards the back of the water."), water2D_Ripple.amplitudeFadeEnd, 0, 1.0f); } EditorGUILayout.LabelField(new GUIContent("Wave 1"), EditorStyles.boldLabel); water2D_Ripple.amplitude1 = EditorGUILayout.FloatField(new GUIContent("Amplitude", "Sine wave amplitude. The bigger the value the higher the wave top will be."), water2D_Ripple.amplitude1); water2D_Ripple.waveLength1 = EditorGUILayout.FloatField(new GUIContent("Wave Length", "The distance between 2 consecutive points of a sine wave."), water2D_Ripple.waveLength1); water2D_Ripple.phaseOffset1 = EditorGUILayout.FloatField(new GUIContent("Phase Offset", "Sine wave phase offset. The bigger the value of the phase offset the faster the waves move to the left (right)."), water2D_Ripple.phaseOffset1); EditorGUILayout.LabelField(new GUIContent("Wave 2"), EditorStyles.boldLabel); water2D_Ripple.amplitude2 = EditorGUILayout.FloatField(new GUIContent("Amplitude", "Sine wave amplitude. The bigger the value the higher the wave top will be."), water2D_Ripple.amplitude2); water2D_Ripple.waveLength2 = EditorGUILayout.FloatField(new GUIContent("Wave Length", "The distance between 2 consecutive points of a sine wave."), water2D_Ripple.waveLength2); water2D_Ripple.phaseOffset2 = EditorGUILayout.FloatField(new GUIContent("Phase Offset", "Sine wave phase offset. The bigger the value of the phase offset the faster the waves move to the left (right)."), water2D_Ripple.phaseOffset2); EditorGUILayout.LabelField(new GUIContent("Wave 3"), EditorStyles.boldLabel); water2D_Ripple.amplitude3 = EditorGUILayout.FloatField(new GUIContent("Amplitude", "Sine wave amplitude. The bigger the value the higher the wave top will be."), water2D_Ripple.amplitude3); water2D_Ripple.waveLength3 = EditorGUILayout.FloatField(new GUIContent("Wave Length", "The distance between 2 consecutive points of a sine wave."), water2D_Ripple.waveLength3); water2D_Ripple.phaseOffset3 = EditorGUILayout.FloatField(new GUIContent("Phase Offset", "Sine wave phase offset. The bigger the value of the phase offset the faster the waves move to the left (right)."), water2D_Ripple.phaseOffset3); } if (EditorGUI.EndChangeCheck() && Application.isPlaying) { water2D_Ripple.SetAmbientWavesShaderParameters(); } }); } }
//------------------------------------------------------------------------------ private void CustomInspector(Water2D_Tool water) { BoldFontStyle(() => { water.showVisuals = EditorGUILayout.Foldout(water.showVisuals, "Mesh Properties"); }); if (water.showVisuals) { InspectorBox(10, () => { water.showMesh = EditorGUILayout.Toggle(new GUIContent("Show Mesh", "Shows or hides the mesh of the water in the scene view"), water.showMesh); if (!water.water2DRippleScript) { water.pixelsPerUnit = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Pixels To Units", "The number of pixels in 1 Unity unit."), water.pixelsPerUnit), 1, 768); } water.useHandles = EditorGUILayout.Toggle(new GUIContent("Use Handles", "The water size is changed using handles."), water.useHandles); if (water.useHandles) { water.handleScale = EditorGUILayout.Slider(new GUIContent("Handle Scale", "Sets the scale of the water handles."), water.handleScale, 0.1f, 10f); pathScale = water.handleScale; } if (!water.useHandles) { water.waterHeight = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Water Height", "Water height."), water.waterHeight), 0, 5000); water.waterWidth = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Water Width", "Water width."), water.waterWidth), 0, 5000); float pos = water.waterHeight / 2f; water.handlesPosition[0] = new Vector2(0, pos); water.handlesPosition[1] = new Vector2(0, -pos); pos = water.waterWidth / 2f; water.handlesPosition[2] = new Vector2(-pos, 0); water.handlesPosition[3] = new Vector2(pos, 0); if (water.cubeWater) { water.zSize = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Water Z Length", "The size of the water on the Z axis."), water.zSize), 0, 5000); water.handlesPosition[4] = new Vector3(0, water.handlesPosition[0].y, water.zSize); } } if (!water.quadMesh) { water.segmentsPerUnit = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Segments To Units", "The number of horizontal segments " + "that should fit in 1 Unity unit."), water.segmentsPerUnit), 0.00001f, 500f); } water.quadMesh = EditorGUILayout.Toggle(new GUIContent("Single Quad Mesh", "What Enabled, the front mesh and top mesh will always be a quad and have only 4 vertices each."), water.quadMesh); Type utility = Type.GetType("UnityEditorInternal.InternalEditorUtility, UnityEditor"); GUILayout.Space(5); EditorGUILayout.LabelField(new GUIContent("Front Mesh"), EditorStyles.boldLabel); if (utility != null) { PropertyInfo sortingLayerNames = utility.GetProperty("sortingLayerNames", BindingFlags.Static | BindingFlags.NonPublic); if (sortingLayerNames != null) { string[] layerNames = sortingLayerNames.GetValue(null, null) as string[]; string currName = water.GetComponent <Renderer>().sortingLayerName == "" ? "Default" : water.GetComponent <Renderer>().sortingLayerName; int nameID = EditorGUILayout.Popup("Sorting Layer", Array.IndexOf(layerNames, currName), layerNames); water.GetComponent <Renderer>().sortingLayerName = layerNames[nameID]; } else { water.GetComponent <Renderer>().sortingLayerID = EditorGUILayout.IntField("Sorting Layer", water.GetComponent <Renderer>().sortingLayerID); } } else { water.GetComponent <Renderer>().sortingLayerID = EditorGUILayout.IntField("Sorting Layer", water.GetComponent <Renderer>().sortingLayerID); } water.GetComponent <Renderer>().sortingOrder = EditorGUILayout.IntField("Order in Layer", water.GetComponent <Renderer>().sortingOrder); if (water.cubeWater) { GUILayout.Space(5); EditorGUILayout.LabelField(new GUIContent("Top Mesh"), EditorStyles.boldLabel); if (utility != null) { PropertyInfo sortingLayerNames = utility.GetProperty("sortingLayerNames", BindingFlags.Static | BindingFlags.NonPublic); if (sortingLayerNames != null) { string[] layerNames = sortingLayerNames.GetValue(null, null) as string[]; string currName = water.topMeshGameObject.GetComponent <Renderer>().sortingLayerName == "" ? "Default" : water.topMeshGameObject.GetComponent <Renderer>().sortingLayerName; int nameID = EditorGUILayout.Popup("Sorting Layer", Array.IndexOf(layerNames, currName), layerNames); water.topMeshGameObject.GetComponent <Renderer>().sortingLayerName = layerNames[nameID]; } else { water.topMeshGameObject.GetComponent <Renderer>().sortingLayerID = EditorGUILayout.IntField("Sorting Layer", water.topMeshGameObject.GetComponent <Renderer>().sortingLayerID); } } else { water.topMeshGameObject.GetComponent <Renderer>().sortingLayerID = EditorGUILayout.IntField("Sorting Layer", water.topMeshGameObject.GetComponent <Renderer>().sortingLayerID); } water.topMeshGameObject.GetComponent <Renderer>().sortingOrder = EditorGUILayout.IntField("Order in Layer", water.topMeshGameObject.GetComponent <Renderer>().sortingOrder); } }); } EditorGUI.indentLevel = 0; BoldFontStyle(() => { water.showCubeWater = EditorGUILayout.Foldout(water.showCubeWater, "2.5D Water"); }); if (water.showCubeWater) { InspectorBox(10, () => { water.cubeWater = EditorGUILayout.Toggle(new GUIContent("Enable 2.5D Water", "Adds a horizontal mesh at the top of the vertical water mesh."), water.cubeWater); if (water.cubeWater && !water.quadMesh) { if (!water.quadMesh) { water.squareSegments = EditorGUILayout.Toggle(new GUIContent("TM Square Segments", "When enabled, the top mesh quads will have the same width and length."), water.squareSegments); } if (water.squareSegments) { water.zSegmentsCap = EditorGUILayout.Toggle(new GUIContent("Z Segments Limit", "Limits the number of segments the top mesh has on the Z axis."), water.zSegmentsCap); } if (!water.squareSegments || (water.squareSegments && water.zSegmentsCap)) { water.zSegmentsSize = Mathf.Clamp(EditorGUILayout.IntField(new GUIContent("Z Segments", "The number of segments, the top water mesh will have."), water.zSegmentsSize), 1, 500); } } if (water.cubeWater && water.handlesPosition.Count == 4) { water.handlesPosition.Add(new Vector3(water.handlesPosition[0].x, water.handlesPosition[0].y, water.zSize)); } if (!water.cubeWater && water.topMeshGameObject) { DestroyImmediate(water.topMeshGameObject.gameObject); } if (water.cubeWater) { CreateTopMeshObject(water); } if (!water.cubeWater && water.handlesPosition.Count > 4) { water.handlesPosition.RemoveAt(4); } }); } Water2D_Simulation water2D_Sim = water.GetComponent <Water2D_Simulation>(); if (water2D_Sim.waterType == Water2D_Type.Dynamic) { BoldFontStyle(() => { water.showCollider = EditorGUILayout.Foldout(water.showCollider, "Collider"); }); if (water.showCollider && water.createCollider) { InspectorBox(10, () => { if (water.createCollider) { water.colliderYAxisOffset = EditorGUILayout.FloatField(new GUIContent("Collider Top Offset", "Offsets the position of the top edge of the water collider. " + "This is done so that objects that are a little above the waterline are detected."), water.colliderYAxisOffset); if (water.use3DCollider) { water.boxColliderCenterOffset = EditorGUILayout.Vector3Field(new GUIContent("BC Center Offset", "Info."), water.boxColliderCenterOffset); water.boxColliderSizeOffset = EditorGUILayout.Vector3Field(new GUIContent("BC Size Offset", "Info."), water.boxColliderSizeOffset); if (!water.cubeWater) { water.boxColliderZSize = EditorGUILayout.FloatField(new GUIContent("Box Collider Z Size", "The size of the box collider on the Z axis."), water.boxColliderZSize); } if (!water.water2DRippleScript) { water.overlapingSphereZOffset = EditorGUILayout.FloatField(new GUIContent("Overlaping Sphere Z Offset", "Info."), water.overlapingSphereZOffset); } } } }); } } BoldFontStyle(() => { water.showInfo = EditorGUILayout.Foldout(water.showInfo, "Mesh Info"); }); if (water.showInfo) { InspectorBox(10, () => { water.showMeshInfo = EditorGUILayout.Toggle("Show Mesh Info", water.showMeshInfo); if (water.showMeshInfo) { if (water.cubeWater) { EditorGUILayout.LabelField(new GUIContent("Top Mesh"), EditorStyles.boldLabel); EditorGUILayout.LabelField(new GUIContent("Mesh Grid"), new GUIContent(water.xVerts.ToString() + " x " + water.zVerts.ToString())); EditorGUILayout.LabelField(new GUIContent("Mesh Vertices", "The number of vertices the top mesh currently has."), new GUIContent((water.zVerts * water.xVerts).ToString())); GUILayout.Space(5); EditorGUILayout.LabelField(new GUIContent("Front Mesh"), EditorStyles.boldLabel); EditorGUILayout.LabelField(new GUIContent("Mesh Grid"), new GUIContent(water.xVerts.ToString() + " x " + 2)); EditorGUILayout.LabelField(new GUIContent("Mesh Vertices", "The number of vertices the front mesh currently has."), new GUIContent((water.xVerts * 2).ToString())); if (water.GetComponent <Water2D_Ripple>()) { GUILayout.Space(5); EditorGUILayout.LabelField(new GUIContent("Render Texture"), EditorStyles.boldLabel); EditorGUILayout.LabelField(new GUIContent("Resolution", "The resolution of the Render Texture that will be created when the game starts."), new GUIContent(water.renderTextureWidth.ToString() + " x " + water.renderTextureHeight.ToString())); } } else { EditorGUILayout.LabelField(new GUIContent("Front Mesh"), EditorStyles.boldLabel); EditorGUILayout.LabelField(new GUIContent("Mesh Grid"), new GUIContent(water.xVerts.ToString() + " x " + 2)); EditorGUILayout.LabelField(new GUIContent("Mesh Vertices", "The number of vertices the front mesh currently has."), new GUIContent((water.xVerts * 2).ToString())); } } }); } }
// This is called when it's known that the object will be rendered by some // camera. We render reflections and do other updates here. // Because the script executes in edit mode, reflections for the scene view // camera will just work! public void OnWillRenderObject() { if (water2D == null) { water2D = GetComponentInParent <Water2D_Tool>(); } if (rend == null) { rend = GetComponent <Renderer>(); } if (!enabled || !rend || !rend.sharedMaterial || !rend.enabled) { return; } Camera cam = Camera.current; if (!cam) { return; } #if UNITY_EDITOR if (SceneView.sceneViews.Count > 0) { SceneView sv = SceneView.sceneViews[0] as SceneView; if (sv != null && !sv.maximized && sv.in2DMode) { return; } } #endif // Safeguard from recursive reflections. if (s_InsideRendering) { return; } s_InsideRendering = true; Camera reflectionCamera; CreateMirrorObjects(cam, out reflectionCamera); if (getComponent) { sky = cam.GetComponent(typeof(Skybox)) as Skybox; mysky = reflectionCamera.GetComponent(typeof(Skybox)) as Skybox; if (Application.isPlaying) { getComponent = false; } } Vector3 pos = Vector3.zero; if (water2D != null) { pos = transform.TransformPoint(water2D.handlesPosition[0]); } else { pos = transform.position + new Vector3(0, -0.065f, 0); } Vector3 normal = transform.up; // Optionally disable pixel lights for reflection int oldPixelLightCount = QualitySettings.pixelLightCount; if (m_DisablePixelLights) { QualitySettings.pixelLightCount = 0; } UpdateCameraModes(cam, reflectionCamera); // Render reflection // Reflect camera around reflection plane float d = -Vector3.Dot(normal, pos) - m_ClipPlaneOffset; Vector4 reflectionPlane = new Vector4(normal.x, normal.y, normal.z, d); Matrix4x4 reflection = Matrix4x4.zero; CalculateReflectionMatrix(ref reflection, reflectionPlane); Vector3 oldpos = cam.transform.position; Vector3 newpos = reflection.MultiplyPoint(oldpos); reflectionCamera.worldToCameraMatrix = cam.worldToCameraMatrix * reflection; // Setup oblique projection matrix so that near plane is our reflection // plane. This way we clip everything below/above it for free. Vector4 clipPlane = CameraSpacePlane(reflectionCamera, pos, normal, 1.0f); //Matrix4x4 projection = cam.projectionMatrix; Matrix4x4 projection = cam.CalculateObliqueMatrix(clipPlane); reflectionCamera.projectionMatrix = projection; reflectionCamera.cullingMask = ~(1 << 4) & m_ReflectLayers.value; // never render water layer reflectionCamera.targetTexture = m_ReflectionTexture; GL.invertCulling = true; reflectionCamera.transform.position = newpos; Vector3 euler = cam.transform.eulerAngles; reflectionCamera.transform.eulerAngles = new Vector3(0, euler.y, euler.z); reflectionCamera.Render(); reflectionCamera.transform.position = oldpos; GL.invertCulling = false; Material mat = rend.sharedMaterial; if (mat.HasProperty("_ReflectionTex")) { mat.SetTexture("_ReflectionTex", m_ReflectionTexture); } // Restore pixel light count if (m_DisablePixelLights) { QualitySettings.pixelLightCount = oldPixelLightCount; } s_InsideRendering = false; }
void OnSceneGUI() { Water2D_Tool water2D_Tool = (Water2D_Tool)target; if (water2D_Tool.showMesh) { EditorUtility.SetSelectedRenderState(water2D_Tool.gameObject.GetComponent <Renderer>(), EditorSelectedRenderState.Wireframe); if (water2D_Tool.cubeWater) { EditorUtility.SetSelectedRenderState(water2D_Tool.topMeshGameObject.gameObject.GetComponent <Renderer>(), EditorSelectedRenderState.Wireframe); } } else { EditorUtility.SetSelectedRenderState(water2D_Tool.gameObject.GetComponent <Renderer>(), EditorSelectedRenderState.Highlight); if (water2D_Tool.cubeWater) { EditorUtility.SetSelectedRenderState(water2D_Tool.topMeshGameObject.gameObject.GetComponent <Renderer>(), EditorSelectedRenderState.Highlight); } } GUIStyle iconStyle = new GUIStyle(); iconStyle.alignment = TextAnchor.MiddleCenter; // Setup undoing things Undo.RecordObject(target, "Handles Position"); if (Event.current.type == EventType.Repaint) { ResetChildTransform(water2D_Tool); DrawRectangle(water2D_Tool); } // Draw and interact with the handles. if (water2D_Tool.useHandles) { UpdateHandles(water2D_Tool, iconStyle); } if (water2D_Tool.use3DCollider && !water2D_Tool.GetComponent <Water2D_Ripple>() && Event.current.type == EventType.Repaint) { DrawOverlapSphereGizmo(water2D_Tool); } // Update everything that relies on the handles, if the GUI changed. if (GUI.changed) { water2D_Tool.RecreateWaterMesh(); EditorUtility.SetDirty(target); prevChanged = true; } else if (Event.current.type == EventType.Used) { if (prevChanged == true) { water2D_Tool.RecreateWaterMesh(); } prevChanged = false; } }
void RenderReflectionFor(Camera cam, Camera reflectCamera) { if (!reflectCamera) { return; } if (m_SharedMaterial && !m_SharedMaterial.HasProperty(reflectionSampler)) { return; } #if UNITY_EDITOR if (SceneView.sceneViews.Count > 0) { SceneView sv = SceneView.sceneViews[0] as SceneView; if (sv != null && !sv.maximized && sv.in2DMode) { return; } if (sv != null && sv.rotation.eulerAngles.x == 0 && sv.rotation.eulerAngles.z == 0) { return; } } #endif #if UNITY_EDITOR int rtWidth = Mathf.FloorToInt(cam.pixelWidth / (1 + 10 - reflectionQuality)); int rtHeight = Mathf.FloorToInt(cam.pixelHeight / (1 + 10 - reflectionQuality)); if (reflectCamera.targetTexture.width != rtWidth || reflectCamera.targetTexture.height != rtHeight) { DestroyImmediate(reflectCamera.targetTexture); reflectCamera.targetTexture = CreateTextureFor(cam); } #endif reflectCamera.cullingMask = reflectionMask & ~(1 << LayerMask.NameToLayer("Water")); SaneCameraSettings(reflectCamera); reflectCamera.backgroundColor = clearColor; reflectCamera.clearFlags = reflectSkybox ? CameraClearFlags.Skybox : CameraClearFlags.SolidColor; if (getComponent) { mainCameraSkybox = cam.GetComponent(typeof(Skybox)) as Skybox; refCameraSkybox = reflectCamera.GetComponent(typeof(Skybox)) as Skybox; if (Application.isPlaying) { getComponent = false; } } if (reflectSkybox) { if (mainCameraSkybox != null) { if (!refCameraSkybox) { refCameraSkybox = (Skybox)reflectCamera.gameObject.AddComponent(typeof(Skybox)); } refCameraSkybox.material = mainCameraSkybox.material; } } GL.invertCulling = true; Transform reflectiveSurface = transform; //waterHeight; Vector3 eulerA = cam.transform.eulerAngles; reflectCamera.transform.eulerAngles = new Vector3(-eulerA.x, eulerA.y, eulerA.z); reflectCamera.transform.position = cam.transform.position; if (water2D == null) { water2D = GetComponentInParent <Water2D_Tool>(); } Vector3 pos = Vector3.zero; if (water2D != null) { pos = transform.TransformPoint(water2D.handlesPosition[0]); } else { pos = transform.position; } Vector3 normal = reflectiveSurface.transform.up; float d = -Vector3.Dot(normal, pos) - clipPlaneOffset; Vector4 reflectionPlane = new Vector4(normal.x, normal.y, normal.z, d); Matrix4x4 reflection = Matrix4x4.zero; reflection = CalculateReflectionMatrix(reflection, reflectionPlane); m_Oldpos = cam.transform.position; Vector3 newpos = reflection.MultiplyPoint(m_Oldpos); reflectCamera.worldToCameraMatrix = cam.worldToCameraMatrix * reflection; Vector4 clipPlane = CameraSpacePlane(reflectCamera, pos, normal, 1.0f); Matrix4x4 projection = cam.projectionMatrix; projection = CalculateObliqueMatrix(projection, clipPlane); reflectCamera.projectionMatrix = projection; reflectCamera.transform.position = newpos; Vector3 euler = cam.transform.eulerAngles; reflectCamera.transform.eulerAngles = new Vector3(-euler.x, euler.y, euler.z); reflectCamera.Render(); GL.invertCulling = false; }
private void UpdateHandles(Water2D_Tool water2D, GUIStyle iconStyle) { Quaternion inv = Quaternion.Inverse(water2D.transform.rotation); SceneView sv = SceneView.sceneViews[0] as SceneView; if (sv.in2DMode) { Handles.color = new Color(1, 1, 1, 0); } else { Handles.color = new Color(1, 1, 1, 1); } Vector3 global; for (int i = 0; i < water2D.handlesPosition.Count; i++) { Vector3 pos = water2D.transform.position + Vector3.Scale(new Vector3(water2D.handlesPosition[i].x, water2D.handlesPosition[i].y, water2D.handlesPosition[i].z), water2D.transform.localScale); if (IsVisible(pos)) { SetScale(pos, texDot, ref iconStyle); if (sv.in2DMode) { Handles.Label(pos, new GUIContent(texDot), iconStyle); } } if (i < 2) { global = Handles.Slider(pos, Vector3.up, HandleScale(pos), Handles.CubeHandleCap, 0); } else { if (i == 4) { global = Handles.Slider(pos, Vector3.forward, HandleScale(pos), Handles.CubeHandleCap, 0); } else { global = Handles.Slider(pos, Vector3.right, HandleScale(pos), Handles.CubeHandleCap, 0); } } if (global != pos) { selectedPoints.Clear(); selectedPoints.Add(i); Vector3 local = inv * (global - water2D.transform.position); Vector3 relative = new Vector3(local.x / water2D.transform.localScale.x, local.y / water2D.transform.localScale.y, local.z / water2D.transform.localScale.z) - water2D.handlesPosition[i]; water2D.handlesPosition[selectedPoints[0]] += relative; if (i == 0 || i == 1) { float distance = Mathf.Abs(water2D.handlesPosition[0].y - water2D.handlesPosition[1].y); water2D.waterHeight = distance; water2D.handlesPosition[2] = new Vector2(water2D.handlesPosition[2].x, water2D.handlesPosition[0].y - distance / 2); water2D.handlesPosition[3] = new Vector2(water2D.handlesPosition[3].x, water2D.handlesPosition[0].y - distance / 2); if (water2D.cubeWater) { water2D.handlesPosition[4] = new Vector3(water2D.handlesPosition[0].x, water2D.handlesPosition[0].y, water2D.handlesPosition[4].z); } } if (i == 2 || i == 3) { float distance = Mathf.Abs(water2D.handlesPosition[2].x - water2D.handlesPosition[3].x); water2D.waterWidth = distance; water2D.handlesPosition[0] = new Vector2(water2D.handlesPosition[2].x + distance / 2, water2D.handlesPosition[0].y); water2D.handlesPosition[1] = new Vector2(water2D.handlesPosition[2].x + distance / 2, water2D.handlesPosition[1].y); if (water2D.cubeWater) { water2D.handlesPosition[4] = new Vector3(water2D.handlesPosition[0].x, water2D.handlesPosition[0].y, water2D.handlesPosition[4].z); } } if (i == 4) { float distance = Mathf.Abs(water2D.handlesPosition[0].z - water2D.handlesPosition[4].z); water2D.zSize = distance; } } } water2D.curentWaterArea = Mathf.Abs(water2D.handlesPosition[2].x - water2D.handlesPosition[3].x) * Mathf.Abs(water2D.handlesPosition[0].y - water2D.handlesPosition[1].y); }
private void DrawOverlapSphereGizmo(Water2D_Tool water) { UnityEditor.Handles.color = Color.blue; Vector3[] vertices = water.GetComponent<MeshFilter>().sharedMesh.vertices; Water2D_Simulation water2D_Sim = water.GetComponent<Water2D_Simulation>(); int surfaceVertsCount = water.surfaceVertsCount / 2; ; for (int i = 0; i < surfaceVertsCount; i++) { Vector3 vertexGlobalPos = water.transform.TransformPoint(vertices[i + surfaceVertsCount]); UnityEditor.Handles.DrawWireDisc(new Vector3(vertexGlobalPos.x, vertexGlobalPos.y, vertexGlobalPos.z + water.boxColliderZOffset), Vector3.up, water2D_Sim.overlapSphereRadius); UnityEditor.Handles.DrawWireDisc(new Vector3(vertexGlobalPos.x, vertexGlobalPos.y, vertexGlobalPos.z + water.boxColliderZOffset), Vector3.forward, water2D_Sim.overlapSphereRadius); } }
private void DrawFlowDirection(Water2D_Tool water) { Handles.color = Color.white; Water2D_Simulation sim = water.GetComponent<Water2D_Simulation>(); float angleInDeg = 0; if (sim.waterFlow) { if (sim.useAngles) { angleInDeg = sim.flowAngle; Handles.ArrowCap(0, water.transform.position, Quaternion.Euler(new Vector3(angleInDeg, 90f, 0)), 1.5f); } } }
//------------------------------------------------------------------------------ private void CustomInspector(Water2D_Tool water) { showVisuals = EditorGUILayout.Foldout(showVisuals, "Visual Properties"); if (showVisuals) { EditorGUI.indentLevel = 1; InspectorBox(10, () => { water.showMesh = !EditorGUILayout.Toggle(new GUIContent("Show Mesh", "Shows or hides the mesh of the water in the scene view"), !water.showMesh); water.verticalTiling = EditorGUILayout.Toggle(new GUIContent("Vertical Tiling", "When enabled will tile the texture horizontally " + "if the water height is greater than the max water height that can be created with the current texture."), water.verticalTiling); water.pixelsPerUnit = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Pixels To Units", "The number of pixels in 1 Unity unit."), water.pixelsPerUnit), 1, 768); water.segmentsPerUnit = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Segments To Units", "The number of horizontal segments " + "that should fit in 1 Unity unit."), water.segmentsPerUnit), 0, 100); Type utility = Type.GetType("UnityEditorInternal.InternalEditorUtility, UnityEditor"); if (utility != null) { PropertyInfo sortingLayerNames = utility.GetProperty("sortingLayerNames", BindingFlags.Static | BindingFlags.NonPublic); if (sortingLayerNames != null) { string[] layerNames = sortingLayerNames.GetValue(null, null) as string[]; string currName = water.GetComponent<Renderer>().sortingLayerName == "" ? "Default" : water.GetComponent<Renderer>().sortingLayerName; int nameID = EditorGUILayout.Popup("Sorting Layer", Array.IndexOf(layerNames, currName), layerNames); water.GetComponent<Renderer>().sortingLayerName = layerNames[nameID]; } else { water.GetComponent<Renderer>().sortingLayerID = EditorGUILayout.IntField("Sorting Layer", water.GetComponent<Renderer>().sortingLayerID); } } else { water.GetComponent<Renderer>().sortingLayerID = EditorGUILayout.IntField("Sorting Layer", water.GetComponent<Renderer>().sortingLayerID); } water.GetComponent<Renderer>().sortingOrder = EditorGUILayout.IntField("Order in Layer", water.GetComponent<Renderer>().sortingOrder); water.handleScale = EditorGUILayout.Slider(new GUIContent("Handle Scale", "Sets the scale of the water handles."), water.handleScale, 0.1f, 10f); pathScale = water.handleScale; water.cubeWater = EditorGUILayout.Toggle(new GUIContent("2.5D Water", "Adds a horizontal mesh at the top of the vertical water mesh."), water.cubeWater); if (water.cubeWater) { water.zSegments = Mathf.Clamp(EditorGUILayout.IntField(new GUIContent("Z Segments", "The number of segments, the horizontal water mesh will have."), water.zSegments), 1, 100); if (water.handlesPosition.Count == 4) { water.handlesPosition.Add(new Vector3(water.handlesPosition[0].x, water.handlesPosition[0].y, water.zSize)); } } if (!water.cubeWater && water.handlesPosition.Count > 4) water.handlesPosition.RemoveAt(4); EditorGUILayout.LabelField(new GUIContent("Current Water Area", "The value of this field is not used in any calculations. " + "When creating an animation that animates the area of the water, use this value as a guide to see how the water area changes between two positions."), new GUIContent(water.curentWaterArea.ToString())); }); } EditorGUI.indentLevel = 0; Water2D_Simulation water2D_Sim = water.GetComponent<Water2D_Simulation>(); if (water2D_Sim.waterType == Water2D_Type.Dynamic) { showCollider = EditorGUILayout.Foldout(showCollider, "Collider"); if (showCollider && water.createCollider) { EditorGUI.indentLevel = 1; InspectorBox(10, () => { if (water.createCollider) { water.colliderOffset = EditorGUILayout.FloatField(new GUIContent("Collider Top Offset", "Offsets the position of the top edge of the water collider. " + "This is done so that objects that are a little above the waterline are detected."), water.colliderOffset); if (water.use3DCollider) { water.boxColliderZOffset = EditorGUILayout.FloatField(new GUIContent("Box Collider Z Offset", "Offsets the center of the box collider on the Z axis."), water.boxColliderZOffset); water.boxColliderZSize = EditorGUILayout.FloatField(new GUIContent("Box Collider Z Size", "The size of the box collider on the Z axis."), water.boxColliderZSize); } } }); } EditorGUI.indentLevel = 0; } }