static void SwappingEditUVMode(ShortcutArguments args) { //If editor is not there, then the selected GameObject does not contains a DecalProjector DecalProjector activeDecalProjector = Selection.activeGameObject?.GetComponent <DecalProjector>(); if (activeDecalProjector == null || activeDecalProjector.Equals(null)) { return; } SceneViewEditMode targetMode = SceneViewEditMode.None; switch (editMode) { case k_EditShapePreservingUV: case k_EditUVAndPivot: targetMode = k_EditShapeWithoutPreservingUV; break; case k_EditShapeWithoutPreservingUV: targetMode = k_EditShapePreservingUV; break; } if (targetMode != SceneViewEditMode.None) { ChangeEditMode(targetMode, GetBoundsGetter(activeDecalProjector)(), FindEditorFromSelection()); } }
void DrawPivotHandles(DecalProjector decalProjector) { Vector3 scale = decalProjector.effectiveScale; Vector3 scaledPivot = Vector3.Scale(decalProjector.pivot, scale); Vector3 scaledSize = Vector3.Scale(decalProjector.size, scale); using (new Handles.DrawingScope(fullColor, Matrix4x4.TRS(Vector3.zero, decalProjector.transform.rotation, Vector3.one))) { EditorGUI.BeginChangeCheck(); Vector3 newPosition = ProjectedTransform.DrawHandles(decalProjector.transform.position, .5f * scaledSize.z - scaledPivot.z, decalProjector.transform.rotation); if (EditorGUI.EndChangeCheck()) { Undo.RecordObjects(new UnityEngine.Object[] { decalProjector, decalProjector.transform }, "Decal Projector Change"); scaledPivot += Quaternion.Inverse(decalProjector.transform.rotation) * (decalProjector.transform.position - newPosition); decalProjector.pivot = new Vector3( scale.x != 0f ? scaledPivot.x / scale.x : decalProjector.pivot.x, scale.y != 0f ? scaledPivot.y / scale.y : decalProjector.pivot.y, scale.z != 0f ? scaledPivot.z / scale.z : decalProjector.pivot.z); decalProjector.transform.position = newPosition; ReinitSavedRatioSizePivotPosition(); } } }
public void UpdateMaterialEditor() { int validMaterialsCount = 0; for (int index = 0; index < targets.Length; ++index) { DecalProjector decalProjector = (targets[index] as DecalProjector); if ((decalProjector != null) && (decalProjector.material != null)) { validMaterialsCount++; } } // Update material editor with the new material UnityEngine.Object[] materials = new UnityEngine.Object[validMaterialsCount]; validMaterialsCount = 0; for (int index = 0; index < targets.Length; ++index) { DecalProjector decalProjector = (targets[index] as DecalProjector); if ((decalProjector != null) && (decalProjector.material != null)) { materials[validMaterialsCount++] = (targets[index] as DecalProjector).material; } } m_MaterialEditor = (MaterialEditor)CreateEditor(materials); }
static void DrawGizmosSelected(DecalProjector decalProjector, GizmoType gizmoType) { //draw them scale independent using (new Handles.DrawingScope(Color.white, Matrix4x4.TRS(decalProjector.transform.position, decalProjector.transform.rotation, Vector3.one))) { handle.center = decalProjector.offset; handle.size = decalProjector.size; bool inEditMode = editMode == k_EditShapePreservingUV || editMode == k_EditShapeWithoutPreservingUV; handle.DrawHull(inEditMode); Quaternion arrowRotation = Quaternion.LookRotation(Vector3.down, Vector3.right); float arrowSize = decalProjector.size.z * 0.25f; Vector3 pivot = decalProjector.offset; Vector3 projectedPivot = pivot + decalProjector.size.z * 0.5f * Vector3.back; Handles.ArrowHandleCap(0, projectedPivot, Quaternion.identity, arrowSize, EventType.Repaint); //[TODO: add editable pivot. Uncomment this when ready] //draw pivot //Handles.SphereHandleCap(controlID, pivot, Quaternion.identity, 0.02f, EventType.Repaint); //Color c = Color.white; //c.a = 0.2f; //Handles.color = c; //Handles.DrawLine(projectedPivot, projectedPivot + decalProjector.m_Size.x * 0.5f * Vector3.right); //Handles.DrawLine(projectedPivot, projectedPivot + decalProjector.m_Size.y * 0.5f * Vector3.up); //Handles.DrawLine(projectedPivot, projectedPivot + decalProjector.m_Size.z * 0.5f * Vector3.forward); //draw UV and bolder edges using (new Handles.DrawingScope(Matrix4x4.TRS(decalProjector.transform.position - decalProjector.transform.rotation * (decalProjector.size * 0.5f + decalProjector.offset.z * Vector3.back), decalProjector.transform.rotation, Vector3.one))) { if (inEditMode) { Vector2 size = new Vector2( (decalProjector.uvScale.x > 100000 || decalProjector.uvScale.x < -100000 ? 0f : 1f / decalProjector.uvScale.x) * decalProjector.size.x, (decalProjector.uvScale.y > 100000 || decalProjector.uvScale.y < -100000 ? 0f : 1f / decalProjector.uvScale.y) * decalProjector.size.y ); Vector2 start = (Vector2)projectedPivot - new Vector2(decalProjector.uvBias.x * size.x, decalProjector.uvBias.y * size.y); Handles.DrawDottedLines( new Vector3[] { start, start + new Vector2(size.x, 0), start + new Vector2(size.x, 0), start + size, start + size, start + new Vector2(0, size.y), start + new Vector2(0, size.y), start }, 5f); } Vector2 halfSize = decalProjector.size * .5f; Vector2 halfSize2 = new Vector2(halfSize.x, -halfSize.y); Vector2 center = (Vector2)projectedPivot + halfSize; Handles.DrawLine(center - halfSize, center - halfSize2, 3f); Handles.DrawLine(center - halfSize2, center + halfSize, 3f); Handles.DrawLine(center + halfSize, center + halfSize2, 3f); Handles.DrawLine(center + halfSize2, center - halfSize, 3f); } } }
static Func <Bounds> GetBoundsGetter(DecalProjector decalProjector) { return(() => { var bounds = new Bounds(); var decalTransform = decalProjector.transform; bounds.Encapsulate(decalTransform.position); return bounds; }); }
void DrawUVHandles(DecalProjector decalProjector) { Vector3 scale = decalProjector.effectiveScale; Vector3 scaledPivot = Vector3.Scale(decalProjector.pivot, scale); Vector3 scaledSize = Vector3.Scale(decalProjector.size, scale); using (new Handles.DrawingScope(Matrix4x4.TRS(decalProjector.transform.position + decalProjector.transform.rotation * (scaledPivot - .5f * scaledSize), decalProjector.transform.rotation, scale))) { Vector2 uvScale = decalProjector.uvScale; Vector2 uvBias = decalProjector.uvBias; Vector2 uvSize = new Vector2( (uvScale.x > k_Limit || uvScale.x < -k_Limit) ? 0f : decalProjector.size.x / uvScale.x, (uvScale.y > k_Limit || uvScale.y < -k_Limit) ? 0f : decalProjector.size.y / uvScale.y ); Vector2 uvCenter = uvSize * .5f - new Vector2(uvBias.x * uvSize.x, uvBias.y * uvSize.y); uvHandles.center = uvCenter; uvHandles.size = uvSize; EditorGUI.BeginChangeCheck(); uvHandles.DrawHandle(); if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(decalProjector, "Decal Projector Change"); for (int channel = 0; channel < 2; channel++) { // Preserve serialized state for axes with the scaled size 0. if (scaledSize[channel] != 0f) { float handleSize = uvHandles.size[channel]; float minusNewUVStart = .5f * handleSize - uvHandles.center[channel]; float decalSize = decalProjector.size[channel]; float limit = k_LimitInv * decalSize; if (handleSize > limit || handleSize < -limit) { uvScale[channel] = decalSize / handleSize; uvBias[channel] = minusNewUVStart / handleSize; } else { // TODO: Decide if uvHandles.size should ever have negative value. It can't currently. uvScale[channel] = k_Limit * Mathf.Sign(handleSize); uvBias[channel] = k_Limit * minusNewUVStart / decalSize; } } } decalProjector.uvScale = uvScale; decalProjector.uvBias = uvBias; } } }
static void EnterEditModePivotPreservingUV(ShortcutArguments args) { //If editor is not there, then the selected GameObject does not contains a DecalProjector DecalProjector activeDecalProjector = Selection.activeGameObject?.GetComponent <DecalProjector>(); if (activeDecalProjector == null || activeDecalProjector.Equals(null)) { return; } ChangeEditMode(k_EditUVAndPivot, GetBoundsGetter(activeDecalProjector)(), FindEditorFromSelection()); }
public void showAt(Vector3 position, Quaternion rotation) { if (prefab == null) { prefab = Game.Instantiate(Game.Instance.breakAnimationPrefab, Vector3.zero, Quaternion.identity); decalProjector = prefab.GetComponent <DecalProjector>(); } prefab.transform.position = position; prefab.transform.rotation = rotation; reset(); prefab.SetActive(true); }
static void ExitEditMode(ShortcutArguments args) { //If editor is not there, then the selected GameObject does not contains a DecalProjector DecalProjector activeDecalProjector = Selection.activeGameObject?.GetComponent <DecalProjector>(); if (activeDecalProjector == null || activeDecalProjector.Equals(null)) { return; } QuitEditMode(); }
public virtual void displayRange() { CombatExecutor ce = GameDataTracker.combatExecutor; GameObject[,] blockGrid = CombatExecutor.blockGrid; Vector2Int mapShape = CombatExecutor.mapShape; if (rangeIndicator != null) { List <GameObject> characterTarget = new List <GameObject>(); characterTarget.Add(character); List <Vector2Int> possibleTargets; if (targetShape == TargetShape.Square) { possibleTargets = findGoalsSquare( characterTarget ).Item1; } else if (targetShape == TargetShape.Diamond) { possibleTargets = findGoalsDiamond( characterTarget ).Item1; } else if (targetShape == TargetShape.Cross) { possibleTargets = findGoalsCross( characterTarget ).Item1; } else if (targetShape == TargetShape.X) { possibleTargets = findGoalsX( characterTarget ).Item1; } else { possibleTargets = new List <Vector2Int>(); } foreach (Vector2 possibleTarget in possibleTargets) { GameObject newProjector = new GameObject("Projector"); DecalProjector projector = newProjector.AddComponent <DecalProjector>(); projector.material = rangeIndicator; newProjector.transform.localRotation = Quaternion.Euler(90, 0, 0); newProjector.transform.position = blockGrid[(int)possibleTarget.x, (int)possibleTarget.y].transform.position; decalProjectors.Add(newProjector); } } }
static void DrawGizmosSelected(DecalProjector decalProjector, GizmoType gizmoType) { UpdateColorsInHandlesIfRequired(); const float k_DotLength = 5f; // Draw them with scale applied to size and pivot instead of the matrix to keep the proportions of the arrow and lines. using (new Handles.DrawingScope(fullColor, Matrix4x4.TRS(decalProjector.transform.position, decalProjector.transform.rotation, Vector3.one))) { Vector3 scale = decalProjector.effectiveScale; Vector3 scaledPivot = Vector3.Scale(decalProjector.pivot, scale); Vector3 scaledSize = Vector3.Scale(decalProjector.size, scale); boxHandle.center = scaledPivot; boxHandle.size = scaledSize; bool isVolumeEditMode = editMode == k_EditShapePreservingUV || editMode == k_EditShapeWithoutPreservingUV; bool isPivotEditMode = editMode == k_EditUVAndPivot; boxHandle.DrawHull(isVolumeEditMode); Vector3 pivot = Vector3.zero; Vector3 projectedPivot = new Vector3(0, 0, scaledPivot.z - .5f * scaledSize.z); if (isPivotEditMode) { Handles.DrawDottedLines(new[] { projectedPivot, pivot }, k_DotLength); } else { float arrowSize = scaledSize.z * 0.25f; Handles.ArrowHandleCap(0, projectedPivot, Quaternion.identity, arrowSize, EventType.Repaint); } //draw UV and bolder edges using (new Handles.DrawingScope(Matrix4x4.TRS(decalProjector.transform.position + decalProjector.transform.rotation * new Vector3(scaledPivot.x, scaledPivot.y, scaledPivot.z - .5f * scaledSize.z), decalProjector.transform.rotation, Vector3.one))) { Vector2 UVSize = new Vector2( (decalProjector.uvScale.x > k_Limit || decalProjector.uvScale.x < -k_Limit) ? 0f : scaledSize.x / decalProjector.uvScale.x, (decalProjector.uvScale.y > k_Limit || decalProjector.uvScale.y < -k_Limit) ? 0f : scaledSize.y / decalProjector.uvScale.y ); Vector2 UVCenter = UVSize * .5f - new Vector2(decalProjector.uvBias.x * UVSize.x, decalProjector.uvBias.y * UVSize.y) - (Vector2)scaledSize * .5f; uvHandles.center = UVCenter; uvHandles.size = UVSize; uvHandles.DrawRect(dottedLine: true, screenSpaceSize: k_DotLength); uvHandles.center = default; uvHandles.size = scaledSize; uvHandles.DrawRect(dottedLine: false, thickness: 3f); } } }
void DrawHandles() { DecalProjector decalProjector = target as DecalProjector; if (editMode == k_EditShapePreservingUV || editMode == k_EditShapeWithoutPreservingUV) { DrawBoxTransformationHandles(decalProjector); } else if (editMode == k_EditUVAndPivot) { DrawPivotHandles(decalProjector); DrawUVHandles(decalProjector); } }
void DrawBoxTransformationHandles(DecalProjector decalProjector) { using (new Handles.DrawingScope(fullColor, Matrix4x4.TRS(decalProjector.transform.position, decalProjector.transform.rotation, Vector3.one))) { Vector3 centerStart = decalProjector.pivot; boxHandle.center = centerStart; boxHandle.size = decalProjector.size; Vector3 boundsSizePreviousOS = boxHandle.size; Vector3 boundsMinPreviousOS = boxHandle.size * -0.5f + boxHandle.center; EditorGUI.BeginChangeCheck(); boxHandle.DrawHandle(); if (EditorGUI.EndChangeCheck()) { // Adjust decal transform if handle changed. Undo.RecordObject(decalProjector, "Decal Projector Change"); decalProjector.size = boxHandle.size; decalProjector.pivot += boxHandle.center - centerStart; Vector3 boundsSizeCurrentOS = boxHandle.size; Vector3 boundsMinCurrentOS = boxHandle.size * -0.5f + boxHandle.center; if (editMode == k_EditShapePreservingUV) { // Treat decal projector bounds as a crop tool, rather than a scale tool. // Compute a new uv scale and bias terms to pin decal projection pixels in world space, irrespective of projector bounds. Vector2 uvScale = decalProjector.uvScale; uvScale.x *= Mathf.Max(1e-5f, boundsSizeCurrentOS.x) / Mathf.Max(1e-5f, boundsSizePreviousOS.x); uvScale.y *= Mathf.Max(1e-5f, boundsSizeCurrentOS.y) / Mathf.Max(1e-5f, boundsSizePreviousOS.y); decalProjector.uvScale = uvScale; Vector2 uvBias = decalProjector.uvBias; uvBias.x += (boundsMinCurrentOS.x - boundsMinPreviousOS.x) / Mathf.Max(1e-5f, boundsSizeCurrentOS.x) * decalProjector.uvScale.x; uvBias.y += (boundsMinCurrentOS.y - boundsMinPreviousOS.y) / Mathf.Max(1e-5f, boundsSizeCurrentOS.y) * decalProjector.uvScale.y; decalProjector.uvBias = uvBias; } if (PrefabUtility.IsPartOfNonAssetPrefabInstance(decalProjector)) { PrefabUtility.RecordPrefabInstancePropertyModifications(decalProjector); } // Smoothly update the decal image projected DecalSystem.instance.UpdateCachedData(decalProjector.Handle, decalProjector.GetCachedDecalData()); } } }
void DrawPivotHandles(DecalProjector decalProjector) { using (new Handles.DrawingScope(fullColor, Matrix4x4.TRS(Vector3.zero, decalProjector.transform.rotation, Vector3.one))) { EditorGUI.BeginChangeCheck(); Vector3 newPosition = ProjectedTransform.DrawHandles(decalProjector.transform.position, .5f * decalProjector.size.z - decalProjector.pivot.z, decalProjector.transform.rotation); if (EditorGUI.EndChangeCheck()) { Undo.RecordObjects(new UnityEngine.Object[] { decalProjector, decalProjector.transform }, "Decal Projector Change"); decalProjector.pivot += Quaternion.Inverse(decalProjector.transform.rotation) * (decalProjector.transform.position - newPosition); decalProjector.transform.position = newPosition; } } }
void DrawUVHandles(DecalProjector decalProjector) { using (new Handles.DrawingScope(Matrix4x4.TRS(decalProjector.transform.position + decalProjector.transform.rotation * (decalProjector.pivot - .5f * decalProjector.size), decalProjector.transform.rotation, Vector3.one))) { Vector2 uvSize = new Vector2( (decalProjector.uvScale.x > k_Limit || decalProjector.uvScale.x < -k_Limit) ? 0f : decalProjector.size.x / decalProjector.uvScale.x, (decalProjector.uvScale.y > k_Limit || decalProjector.uvScale.y < -k_Limit) ? 0f : decalProjector.size.y / decalProjector.uvScale.y ); Vector2 uvCenter = uvSize * .5f - new Vector2(decalProjector.uvBias.x * uvSize.x, decalProjector.uvBias.y * uvSize.y); uvHandles.center = uvCenter; uvHandles.size = uvSize; EditorGUI.BeginChangeCheck(); uvHandles.DrawHandle(); if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(decalProjector, "Decal Projector Change"); Vector2 limit = new Vector2(Mathf.Abs(decalProjector.size.x * k_LimitInv), Mathf.Abs(decalProjector.size.y * k_LimitInv)); Vector2 uvScale = uvHandles.size; for (int channel = 0; channel < 2; channel++) { if (Mathf.Abs(uvScale[channel]) > limit[channel]) { uvScale[channel] = decalProjector.size[channel] / uvScale[channel]; } else { uvScale[channel] = Mathf.Sign(decalProjector.size[channel]) * Mathf.Sign(uvScale[channel]) * k_Limit; } } decalProjector.uvScale = uvScale; var newUVStart = uvHandles.center - .5f * uvHandles.size; decalProjector.uvBias = -new Vector2( (uvHandles.size.x < k_LimitInv) && (uvHandles.size.x > -k_LimitInv) ? k_Limit * newUVStart.x / decalProjector.size.x : newUVStart.x / uvHandles.size.x, //parenthesis to force format tool (uvHandles.size.y < k_LimitInv) && (uvHandles.size.y > -k_LimitInv) ? k_Limit * newUVStart.y / decalProjector.size.y : newUVStart.y / uvHandles.size.y //parenthesis to force format tool ); } } }
static void DrawGizmosSelected(DecalProjector decalProjector, GizmoType gizmoType) { //draw them scale independent using (new Handles.DrawingScope(Color.white, Matrix4x4.TRS(decalProjector.transform.position, decalProjector.transform.rotation, Vector3.one))) { handle.center = decalProjector.offset; handle.size = decalProjector.size; handle.DrawHull(editMode == k_EditShapePreservingUV || editMode == k_EditShapeWithoutPreservingUV); int controlID = GUIUtility.GetControlID(handle.GetHashCode(), FocusType.Passive); Quaternion arrowRotation = Quaternion.LookRotation(Vector3.down, Vector3.right); float arrowSize = decalProjector.size.z * 0.25f; Vector3 pivot = decalProjector.offset; Vector3 projectedPivot = pivot + decalProjector.size.z * 0.5f * Vector3.back; Handles.ArrowHandleCap(controlID, projectedPivot, Quaternion.identity, arrowSize, EventType.Repaint); //[TODO: add editable pivot. Uncomment this when ready] //draw pivot //Handles.SphereHandleCap(controlID, pivot, Quaternion.identity, 0.02f, EventType.Repaint); //Color c = Color.white; //c.a = 0.2f; //Handles.color = c; //Handles.DrawLine(projectedPivot, projectedPivot + decalProjector.m_Size.x * 0.5f * Vector3.right); //Handles.DrawLine(projectedPivot, projectedPivot + decalProjector.m_Size.y * 0.5f * Vector3.up); //Handles.DrawLine(projectedPivot, projectedPivot + decalProjector.m_Size.z * 0.5f * Vector3.forward); //draw UV Color face = Color.green; face.a = 0.1f; Vector2 size = new Vector2( (decalProjector.uvScale.x > 100000 || decalProjector.uvScale.x < -100000 ? 0f : 1f / decalProjector.uvScale.x) * decalProjector.size.x, (decalProjector.uvScale.x > 100000 || decalProjector.uvScale.x < -100000 ? 0f : 1f / decalProjector.uvScale.y) * decalProjector.size.y ); Vector2 start = (Vector2)projectedPivot - new Vector2(decalProjector.uvBias.x * size.x, decalProjector.uvBias.y * size.y); using (new Handles.DrawingScope(face, Matrix4x4.TRS(decalProjector.transform.position - decalProjector.transform.rotation * (decalProjector.size * 0.5f + decalProjector.offset.z * Vector3.back), decalProjector.transform.rotation, Vector3.one))) { Handles.DrawSolidRectangleWithOutline(new Rect(start, size), face, Color.white); } } }
public static List <GameObject> RectangleDisplay(Material projectorMaterial, GameObject[,] blockGrid, Vector2Int pos, Vector2Int shape) { List <GameObject> decalProjectors = new List <GameObject>(); for (int x = pos.x; x < pos.x + shape.x; x++) { if (x < blockGrid.GetLength(0)) { for (int y = pos.y; y < pos.y + shape.y; y++) { if (y < blockGrid.GetLength(1)) { GameObject newProjector = new GameObject("Projector"); DecalProjector projector = newProjector.AddComponent <DecalProjector>(); projector.material = projectorMaterial; newProjector.transform.localRotation = Quaternion.Euler(90, 0, 0); newProjector.transform.position = blockGrid[x, y].transform.position; decalProjectors.Add(newProjector); } } } } return(decalProjectors); }
private void Update() { if (Input.GetKeyDown (KeyCode.C)) { // Remove all projectors. while (m_DecalProjectors.Count > 0) { m_DecalsMesh.ClearAll (); m_DecalProjectors.Clear (); // Clearing of the decals mesh means we need to initialize it again. m_DecalsMesh.Initialize (m_DecalsInstance); } m_DecalsInstance.UpdateDecalsMeshes (m_DecalsMesh); } if (Input.GetButtonDown ("Fire1")) { Ray l_Ray = Camera.main.ViewportPointToRay (new Vector3 (0.5f, 0.5f, 0.0f)); RaycastHit l_RaycastHit; if (Physics.Raycast (l_Ray, out l_RaycastHit, Mathf.Infinity)) { // Collider hit. // Make sure there are not too many projectors. if (m_DecalProjectors.Count >= m_MaximumNumberOfProjectors) { // If there are more than the maximum number of projectors, we delete // the oldest one. DecalProjector l_DecalProjector = m_DecalProjectors [0]; m_DecalProjectors.RemoveAt (0); m_DecalsMesh.RemoveProjector (l_DecalProjector); } // Calculate the position and rotation for the new decal projector. Vector3 l_ProjectorPosition = l_RaycastHit.point - (m_DecalProjectorOffset * l_Ray.direction.normalized); Quaternion l_ProjectorRotation = ProjectorRotationUtility.ProjectorRotation (Camera.main.transform.forward, Vector3.up); // Randomize the rotation. Quaternion l_RandomRotation = Quaternion.Euler (0.0f, Random.Range (0.0f, 360.0f), 0.0f); l_ProjectorRotation = l_ProjectorRotation * l_RandomRotation; TerrainCollider l_TerrainCollider = l_RaycastHit.collider as TerrainCollider; if (l_TerrainCollider != null) { // Terrain collider hit. Terrain l_Terrain = l_TerrainCollider.GetComponent <Terrain> (); if (l_Terrain != null) { // Create the decal projector with all the required information. DecalProjector l_DecalProjector = new DecalProjector (l_ProjectorPosition, l_ProjectorRotation, m_DecalProjectorScale, m_CullingAngle, m_MeshOffset, m_UVRectangleIndex, m_UVRectangleIndex, CurrentColor, 0.0f); // Add the projector to our list and the decals mesh, such that both are // synchronized. All the mesh data that is now added to the decals mesh // will belong to this projector. m_DecalProjectors.Add (l_DecalProjector); m_DecalsMesh.AddProjector (l_DecalProjector); // The terrain data has to be converted to the decals instance's space. Matrix4x4 l_TerrainToDecalsMatrix = m_WorldToDecalsMatrix * Matrix4x4.TRS (l_Terrain.transform.position, Quaternion.identity, Vector3.one); // Pass the terrain data with the corresponding conversion to the decals mesh. m_DecalsMesh.Add (l_Terrain, l_TerrainToDecalsMatrix); // Cut and offset the decals mesh. m_DecalsMeshCutter.CutDecalsPlanes (m_DecalsMesh); m_DecalsMesh.OffsetActiveProjectorVertices (); // The changes are only present in the decals mesh at the moment. We have // to pass them to the decals instance to visualize them. m_DecalsInstance.UpdateDecalsMeshes (m_DecalsMesh); // For the next hit, use a new uv rectangle. Usually, you would select the uv rectangle // based on the surface you have hit. NextUVRectangleIndex (); NextColorIndex (); } else { Debug.LogError ("Terrain is null!"); } } else { // We hit a collider. Next we have to find the mesh that belongs to the collider. // That step depends on how you set up your mesh filters and collider relative to // each other in the game objects. It is important to have a consistent way in order // to have a simpler implementation. MeshCollider l_MeshCollider = l_RaycastHit.collider.GetComponent <MeshCollider> (); MeshFilter l_MeshFilter = l_RaycastHit.collider.GetComponent <MeshFilter> (); if (l_MeshCollider != null || l_MeshFilter != null) { Mesh l_Mesh = null; if (l_MeshCollider != null) { // Mesh collider was hit. Just use the mesh data from that one. l_Mesh = l_MeshCollider.sharedMesh; } else if (l_MeshFilter != null) { // Otherwise take the data from the shared mesh. l_Mesh = l_MeshFilter.sharedMesh; } if (l_Mesh != null) { // Create the decal projector. DecalProjector l_DecalProjector = new DecalProjector (l_ProjectorPosition, l_ProjectorRotation, m_DecalProjectorScale, m_CullingAngle, m_MeshOffset, m_UVRectangleIndex, m_UVRectangleIndex, CurrentColor, 0.0f); // Add the projector to our list and the decals mesh, such that both are // synchronized. All the mesh data that is now added to the decals mesh // will belong to this projector. m_DecalProjectors.Add (l_DecalProjector); m_DecalsMesh.AddProjector (l_DecalProjector); // Get the required matrices. Matrix4x4 l_WorldToMeshMatrix = l_RaycastHit.collider.renderer.transform.worldToLocalMatrix; Matrix4x4 l_MeshToWorldMatrix = l_RaycastHit.collider.renderer.transform.localToWorldMatrix; // Add the mesh data to the decals mesh, cut and offset it. m_DecalsMesh.Add (l_Mesh, l_WorldToMeshMatrix, l_MeshToWorldMatrix); m_DecalsMeshCutter.CutDecalsPlanes (m_DecalsMesh); m_DecalsMesh.OffsetActiveProjectorVertices (); // The changes are only present in the decals mesh at the moment. We have // to pass them to the decals instance to visualize them. m_DecalsInstance.UpdateDecalsMeshes (m_DecalsMesh); // For the next hit, use a new uv rectangle. Usually, you would select the uv rectangle // based on the surface you have hit. NextUVRectangleIndex (); NextColorIndex (); } } } } } }
public void AddDecalProjector(Ray a_Ray, RaycastHit a_RaycastHit) { // Make sure there are not too many projectors. if (m_DecalProjectors.Count >= m_MaximumNumberOfProjectors) { // If there are more than the maximum number of projectors, we delete // the oldest one. DecalProjector l_DecalProjector = m_DecalProjectors [0]; m_DecalProjectors.RemoveAt(0); m_DecalsMesh.RemoveProjector(l_DecalProjector); } // Calculate the position and rotation for the new decal projector. Vector3 l_ProjectorPosition = a_RaycastHit.point - (m_DecalProjectorOffset * a_Ray.direction.normalized); Quaternion l_ProjectorRotation = ProjectorRotationUtility.ProjectorRotation(Camera.main.transform.forward, Vector3.up); // Randomize the rotation. Quaternion l_RandomRotation = Quaternion.Euler(0.0f, Random.Range(0.0f, 360.0f), 0.0f); l_ProjectorRotation = l_ProjectorRotation * l_RandomRotation; // We hit a collider. Next we have to find the mesh that belongs to the collider. // That step depends on how you set up your mesh filters and collider relative to // each other in the game objects. It is important to have a consistent way in order // to have a simpler implementation. MeshCollider l_MeshCollider = a_RaycastHit.collider.GetComponent <MeshCollider> (); MeshFilter l_MeshFilter = a_RaycastHit.collider.GetComponent <MeshFilter> (); if (l_MeshCollider != null || l_MeshFilter != null) { Mesh l_Mesh = null; if (l_MeshCollider != null) { // Mesh collider was hit. Just use the mesh data from that one. l_Mesh = l_MeshCollider.sharedMesh; } else if (l_MeshFilter != null) { // Otherwise take the data from the shared mesh. l_Mesh = l_MeshFilter.sharedMesh; } if (l_Mesh != null) { // Create the decal projector. DecalProjector l_DecalProjector = new DecalProjector(l_ProjectorPosition, l_ProjectorRotation, m_DecalProjectorScale, m_CullingAngle, m_MeshOffset, m_UVRectangleIndex, m_UVRectangleIndex); // Add the projector to our list and the decals mesh, such that both are // synchronized. All the mesh data that is now added to the decals mesh // will belong to this projector. m_DecalProjectors.Add(l_DecalProjector); m_DecalsMesh.AddProjector(l_DecalProjector); // Get the required matrices. Matrix4x4 l_WorldToMeshMatrix = a_RaycastHit.collider.renderer.transform.worldToLocalMatrix; Matrix4x4 l_MeshToWorldMatrix = a_RaycastHit.collider.renderer.transform.localToWorldMatrix; // Add the mesh data to the decals mesh, cut and offset it. m_DecalsMesh.Add(l_Mesh, l_WorldToMeshMatrix, l_MeshToWorldMatrix); m_DecalsMeshCutter.CutDecalsPlanes(m_DecalsMesh); m_DecalsMesh.OffsetActiveProjectorVertices(); // The changes are only present in the decals mesh at the moment. We have // to pass them to the decals instance to visualize them. m_DecalsInstance.UpdateDecalsMeshes(m_DecalsMesh); NextUVRectangleIndex(); } } }
public void AddDecalProjector(Ray a_Ray, RaycastHit a_RaycastHit) { // Make sure there are not too many projectors. if (m_DecalProjectors.Count >= m_MaximumNumberOfProjectors) { // If there are more than the maximum number of projectors, we delete // the oldest one. DecalProjector l_DecalProjector = m_DecalProjectors [0]; m_DecalProjectors.RemoveAt (0); m_DecalsMesh.RemoveProjector (l_DecalProjector); } // Calculate the position and rotation for the new decal projector. Vector3 l_ProjectorPosition = a_RaycastHit.point - (m_DecalProjectorOffset * a_Ray.direction.normalized); Quaternion l_ProjectorRotation = ProjectorRotationUtility.ProjectorRotation (Camera.main.transform.forward, Vector3.up); // Randomize the rotation. Quaternion l_RandomRotation = Quaternion.Euler (0.0f, Random.Range (0.0f, 360.0f), 0.0f); l_ProjectorRotation = l_ProjectorRotation * l_RandomRotation; // We hit a collider. Next we have to find the mesh that belongs to the collider. // That step depends on how you set up your mesh filters and collider relative to // each other in the game objects. It is important to have a consistent way in order // to have a simpler implementation. MeshCollider l_MeshCollider = a_RaycastHit.collider.GetComponent <MeshCollider> (); MeshFilter l_MeshFilter = a_RaycastHit.collider.GetComponent <MeshFilter> (); if (l_MeshCollider != null || l_MeshFilter != null) { Mesh l_Mesh = null; if (l_MeshCollider != null) { // Mesh collider was hit. Just use the mesh data from that one. l_Mesh = l_MeshCollider.sharedMesh; } else if (l_MeshFilter != null) { // Otherwise take the data from the shared mesh. l_Mesh = l_MeshFilter.sharedMesh; } if (l_Mesh != null) { // Create the decal projector. DecalProjector l_DecalProjector = new DecalProjector (l_ProjectorPosition, l_ProjectorRotation, m_DecalProjectorScale, m_CullingAngle, m_MeshOffset, m_UVRectangleIndex, m_UVRectangleIndex); // Add the projector to our list and the decals mesh, such that both are // synchronized. All the mesh data that is now added to the decals mesh // will belong to this projector. m_DecalProjectors.Add (l_DecalProjector); m_DecalsMesh.AddProjector (l_DecalProjector); // Get the required matrices. Matrix4x4 l_WorldToMeshMatrix = a_RaycastHit.collider.renderer.transform.worldToLocalMatrix; Matrix4x4 l_MeshToWorldMatrix = a_RaycastHit.collider.renderer.transform.localToWorldMatrix; // Add the mesh data to the decals mesh, cut and offset it. m_DecalsMesh.Add (l_Mesh, l_WorldToMeshMatrix, l_MeshToWorldMatrix); m_DecalsMeshCutter.CutDecalsPlanes (m_DecalsMesh); m_DecalsMesh.OffsetActiveProjectorVertices (); // The changes are only present in the decals mesh at the moment. We have // to pass them to the decals instance to visualize them. m_DecalsInstance.UpdateDecalsMeshes (m_DecalsMesh); NextUVRectangleIndex (); } } }
private void Update() { if (Input.GetButtonDown ("Fire1")) { Ray l_Ray = Camera.main.ViewportPointToRay (new Vector3 (0.5f, 0.5f, 0.0f)); RaycastHit l_RaycastHit; if (Physics.Raycast (l_Ray, out l_RaycastHit, Mathf.Infinity)) { // Collider hit. // Make sure there are not too many projectors. if (m_DecalProjectors.Count >= 50) { // If there are more than 50 projectors, we remove the first one from // our list and certainly from the decals mesh (the intermediate mesh // format). All the mesh data that belongs to this projector will // be removed. DecalProjector l_DecalProjector = m_DecalProjectors [0]; m_DecalProjectors.RemoveAt (0); m_DecalsMesh.RemoveProjector (l_DecalProjector); } // Calculate the position and rotation for the new decal projector. Vector3 l_ProjectorPosition = l_RaycastHit.point - (decalProjectorOffset * l_Ray.direction.normalized); Vector3 l_ForwardDirection = Camera.main.transform.up; Vector3 l_UpDirection = - Camera.main.transform.forward; Quaternion l_ProjectorRotation = Quaternion.LookRotation (l_ForwardDirection, l_UpDirection); // Randomize the rotation. Quaternion l_RandomRotation = Quaternion.Euler (0.0f, Random.Range (0.0f, 360.0f), 0.0f); l_ProjectorRotation = l_ProjectorRotation * l_RandomRotation; TerrainCollider l_TerrainCollider = l_RaycastHit.collider as TerrainCollider; if (l_TerrainCollider != null) { // Terrain collider hit. Terrain l_Terrain = l_TerrainCollider.GetComponent <Terrain> (); if (l_Terrain != null) { // Create the decal projector with all the required information. DecalProjector l_DecalProjector = new DecalProjector (l_ProjectorPosition, l_ProjectorRotation, decalProjectorScale, cullingAngle, meshOffset, m_UVRectangleIndex, m_UVRectangleIndex); // Add the projector to our list and the decals mesh, such that both are // synchronized. All the mesh data that is now added to the decals mesh // will belong to this projector. m_DecalProjectors.Add (l_DecalProjector); m_DecalsMesh.AddProjector (l_DecalProjector); // The terrain data has to be converted to the decals instance's space. Matrix4x4 l_TerrainToDecalsMatrix = Matrix4x4.TRS (l_Terrain.transform.position, Quaternion.identity, Vector3.one) * m_WorldToDecalsMatrix; // Pass the terrain data with the corresponding conversion to the decals mesh. m_DecalsMesh.Add (l_Terrain, l_TerrainToDecalsMatrix); // Cut the data in the decals mesh accoring to the size and position of the decal projector. Offset the // vertices afterwards and pass the newly computed mesh to the decals instance, such that it becomes // visible. m_DecalsMeshCutter.CutDecalsPlanes (m_DecalsMesh); m_DecalsMesh.OffsetActiveProjectorVertices (); m_Decals.UpdateDecalsMeshes (m_DecalsMesh); // For the next hit, use a new uv rectangle. Usually, you would select the uv rectangle // based on the surface you have hit. NextUVRectangleIndex (); } else { Debug.Log ("Terrain is null!"); } } else { // We hit a collider. Next we have to find the mesh that belongs to the collider. // That step depends on how you set up your mesh filters and collider relative to // each other in the game objects. It is important to have a consistent way in order // to have a simpler implementation. MeshCollider l_MeshCollider = l_RaycastHit.collider.GetComponent <MeshCollider> (); MeshFilter l_MeshFilter = l_RaycastHit.collider.GetComponent <MeshFilter> (); if (l_MeshCollider != null || l_MeshFilter != null) { Mesh l_Mesh = null; if (l_MeshCollider != null) { // Mesh collider was hit. Just use the mesh data from that one. l_Mesh = l_MeshCollider.sharedMesh; } else if (l_MeshFilter != null) { // Otherwise take the data from the shared mesh. l_Mesh = l_MeshFilter.sharedMesh; } if (l_Mesh != null) { // Create the decal projector. DecalProjector l_DecalProjector = new DecalProjector (l_ProjectorPosition, l_ProjectorRotation, decalProjectorScale, cullingAngle, meshOffset, m_UVRectangleIndex, m_UVRectangleIndex); // Add the projector to our list and the decals mesh, such that both are // synchronized. All the mesh data that is now added to the decals mesh // will belong to this projector. m_DecalProjectors.Add (l_DecalProjector); m_DecalsMesh.AddProjector (l_DecalProjector); // Get the required matrices. Matrix4x4 l_WorldToMeshMatrix = l_RaycastHit.collider.renderer.transform.worldToLocalMatrix; Matrix4x4 l_MeshToWorldMatrix = l_RaycastHit.collider.renderer.transform.localToWorldMatrix; // Add the mesh data to the decals mesh, cut and offset it before we pass it // to the decals instance to be displayed. m_DecalsMesh.Add (l_Mesh, l_WorldToMeshMatrix, l_MeshToWorldMatrix); m_DecalsMeshCutter.CutDecalsPlanes (m_DecalsMesh); m_DecalsMesh.OffsetActiveProjectorVertices (); m_Decals.UpdateDecalsMeshes (m_DecalsMesh); // For the next hit, use a new uv rectangle. Usually, you would select the uv rectangle // based on the surface you have hit. NextUVRectangleIndex (); } } } } } }
public void ShowDecal(Vector3 position, Vector3 direction) { DecalProjector decalProjector = Instantiate(DecalHitEffect, position, Quaternion.LookRotation(direction)); decalProjector.transform.parent = this.gameObject.transform; }
private void Update() { if (Input.GetKeyDown (KeyCode.C)) { // Remove all decals instances. foreach (DS_Decals l_DecalsInstance in m_DecalsInstances) { Destroy (l_DecalsInstance.gameObject); } m_DecalsInstances.Clear (); } if (Input.GetButtonDown ("Fire1")) { Ray l_Ray = Camera.main.ViewportPointToRay (new Vector3 (0.5f, 0.5f, 0.0f)); RaycastHit l_RaycastHit; // Terrains have no uv2, so we just skip them. if (Physics.Raycast (l_Ray, out l_RaycastHit, Mathf.Infinity) && l_RaycastHit.collider as TerrainCollider == null) { // Collider hit. // Make sure there are not too many decals instances. if (m_DecalsInstances.Count >= m_MaximumNumberOfDecals) { DS_Decals l_FirstDecalsInstance = m_DecalsInstances [0]; Destroy (l_FirstDecalsInstance); m_DecalsInstances.RemoveAt (0); } // Instantiate the prefab and get its decals instance. DS_Decals l_DecalsInstance = Instantiate (m_DecalsPrefab) as DS_Decals; // Reuse the decals mesh, but be sure to initialize it always for the current // decals instance. m_DecalsMesh.Initialize (l_DecalsInstance); // Calculate the position and rotation for the new decal projector. Vector3 l_ProjectorPosition = l_RaycastHit.point - (m_DecalProjectorOffset * l_Ray.direction.normalized); Quaternion l_ProjectorRotation = ProjectorRotationUtility.ProjectorRotation (Camera.main.transform.forward, Vector3.up); // Randomize the rotation. Quaternion l_RandomRotation = Quaternion.Euler (0.0f, Random.Range (0.0f, 360.0f), 0.0f); l_ProjectorRotation = l_ProjectorRotation * l_RandomRotation; // We hit a collider. Next we have to find the mesh that belongs to the collider. // That step depends on how you set up your mesh filters and collider relative to // each other in the game objects. It is important to have a consistent way in order // to have a simpler implementation. MeshCollider l_MeshCollider = l_RaycastHit.collider.GetComponent <MeshCollider> (); MeshFilter l_MeshFilter = l_RaycastHit.collider.GetComponent <MeshFilter> (); MeshRenderer l_MeshRenderer = l_RaycastHit.collider.GetComponent <MeshRenderer> (); if (l_MeshCollider != null || l_MeshFilter != null) { Mesh l_Mesh = null; if (l_MeshCollider != null) { // Mesh collider was hit. Just use the mesh data from that one. l_Mesh = l_MeshCollider.sharedMesh; } else if (l_MeshFilter != null) { // Otherwise take the data from the shared mesh. l_Mesh = l_MeshFilter.sharedMesh; } if (l_Mesh != null) { // Create the decal projector. DecalProjector l_DecalProjector = new DecalProjector (l_ProjectorPosition, l_ProjectorRotation, m_DecalProjectorScale, m_CullingAngle, m_MeshOffset, m_UVRectangleIndex, m_UVRectangleIndex); // Add the decals instance to our list and the projector // to the decals mesh. // All the mesh data that is now added to the decals mesh // will belong to this projector. m_DecalsInstances.Add (l_DecalsInstance); m_DecalsMesh.AddProjector (l_DecalProjector); // Get the required matrices. Matrix4x4 l_WorldToMeshMatrix = l_RaycastHit.collider.renderer.transform.worldToLocalMatrix; Matrix4x4 l_MeshToWorldMatrix = l_RaycastHit.collider.renderer.transform.localToWorldMatrix; // Add the mesh data to the decals mesh, cut and offset it. m_DecalsMesh.Add (l_Mesh, l_WorldToMeshMatrix, l_MeshToWorldMatrix); m_DecalsMeshCutter.CutDecalsPlanes (m_DecalsMesh); m_DecalsMesh.OffsetActiveProjectorVertices (); // The changes are only present in the decals mesh at the moment. We have // to pass them to the decals instance to visualize them. l_DecalsInstance.UpdateDecalsMeshes (m_DecalsMesh); // Lightmapping l_DecalsInstance.DecalsMeshRenderers [0].MeshRenderer.lightmapIndex = l_MeshRenderer.lightmapIndex; l_DecalsInstance.DecalsMeshRenderers [0].MeshRenderer.lightmapTilingOffset = l_MeshRenderer.lightmapTilingOffset; // For the next hit, use a new uv rectangle. Usually, you would select the uv rectangle // based on the surface you have hit. NextUVRectangleIndex (l_DecalsInstance); } } } } }
private void Start() { cam = Camera.main; projector = projectorObject.transform.GetChild(0).gameObject.GetComponent <DecalProjector>(); }
void Start() { _decalProjector = GetComponent <DecalProjector>(); }
private void Update() { if (Input.GetButtonDown("Fire1")) { Ray l_Ray = Camera.main.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0.0f)); RaycastHit l_RaycastHit; // Terrains have no uv2, so we just skip them. if (Physics.Raycast(l_Ray, out l_RaycastHit, Mathf.Infinity) && l_RaycastHit.collider as TerrainCollider == null) { // Collider hit. // Make sure there are not too many decals instances. if (m_DecalsInstances.Count >= 50) { m_DecalsInstances.RemoveAt(0); } // Instantiate the prefab and get its decals instance. GameObject l_Instance = Instantiate(decalsPrefab) as GameObject; DS_Decals l_Decals = l_Instance.GetComponentInChildren <DS_Decals> (); // Reuse the decals mesh, but be sure to initialize it always for the current // decals instance. m_DecalsMesh.Initialize(l_Decals); // Calculate the position and rotation for the new decal projector. Vector3 l_ProjectorPosition = l_RaycastHit.point - (decalProjectorOffset * l_Ray.direction.normalized); Vector3 l_ForwardDirection = Camera.main.transform.up; Vector3 l_UpDirection = -Camera.main.transform.forward; Quaternion l_ProjectorRotation = Quaternion.LookRotation(l_ForwardDirection, l_UpDirection); // Randomize the rotation. Quaternion l_RandomRotation = Quaternion.Euler(0.0f, Random.Range(0.0f, 360.0f), 0.0f); l_ProjectorRotation = l_ProjectorRotation * l_RandomRotation; // We hit a collider. Next we have to find the mesh that belongs to the collider. // That step depends on how you set up your mesh filters and collider relative to // each other in the game objects. It is important to have a consistent way in order // to have a simpler implementation. MeshCollider l_MeshCollider = l_RaycastHit.collider.GetComponent <MeshCollider> (); MeshFilter l_MeshFilter = l_RaycastHit.collider.GetComponent <MeshFilter> (); MeshRenderer l_MeshRenderer = l_RaycastHit.collider.GetComponent <MeshRenderer> (); if (l_MeshCollider != null || l_MeshFilter != null) { Mesh l_Mesh = null; if (l_MeshCollider != null) { // Mesh collider was hit. Just use the mesh data from that one. l_Mesh = l_MeshCollider.sharedMesh; } else if (l_MeshFilter != null) { // Otherwise take the data from the shared mesh. l_Mesh = l_MeshFilter.sharedMesh; } if (l_Mesh != null) { // Create the decal projector. DecalProjector l_DecalProjector = new DecalProjector(l_ProjectorPosition, l_ProjectorRotation, decalProjectorScale, cullingAngle, meshOffset, m_UVRectangleIndex, m_UVRectangleIndex); // All the mesh data that is now added to the decals mesh // will belong to this projector. m_DecalsMesh.AddProjector(l_DecalProjector); // Get the required matrices. Matrix4x4 l_WorldToMeshMatrix = l_RaycastHit.collider.renderer.transform.worldToLocalMatrix; Matrix4x4 l_MeshToWorldMatrix = l_RaycastHit.collider.renderer.transform.localToWorldMatrix; // Add the mesh data to the decals mesh, cut and offset it before we pass it // to the decals instance to be displayed. m_DecalsMesh.Add(l_Mesh, l_WorldToMeshMatrix, l_MeshToWorldMatrix); m_DecalsMeshCutter.CutDecalsPlanes(m_DecalsMesh); m_DecalsMesh.OffsetActiveProjectorVertices(); l_Decals.UpdateDecalsMeshes(m_DecalsMesh); // Lightmapping l_Decals.DecalsMeshRenderers [0].MeshRenderer.lightmapIndex = l_MeshRenderer.lightmapIndex; l_Decals.DecalsMeshRenderers [0].MeshRenderer.lightmapTilingOffset = l_MeshRenderer.lightmapTilingOffset; // For the next hit, use a new uv rectangle. Usually, you would select the uv rectangle // based on the surface you have hit. NextUVRectangleIndex(l_Decals); } } } } }
public Bounds OnGetFrameBounds() { DecalProjector decalProjector = target as DecalProjector; return(new Bounds(decalProjector.transform.position, boxHandle.size)); }
private void Update() { if (Input.GetButtonDown("Fire1")) { Ray l_Ray = Camera.main.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0.0f)); RaycastHit l_RaycastHit; if (Physics.Raycast(l_Ray, out l_RaycastHit, Mathf.Infinity)) { // Collider hit. // Make sure there are not too many projectors. if (m_DecalProjectors.Count >= 50) { // If there are more than 50 projectors, we remove the first one from // our list and certainly from the decals mesh (the intermediate mesh // format). All the mesh data that belongs to this projector will // be removed. DecalProjector l_DecalProjector = m_DecalProjectors [0]; // The vertex color list has to be updated as well. m_VertexColors.RemoveRange(0, l_DecalProjector.DecalsMeshUpperVertexIndex + 1); m_DecalProjectors.RemoveAt(0); m_DecalsMesh.RemoveProjector(l_DecalProjector); } // Calculate the position and rotation for the new decal projector. Vector3 l_ProjectorPosition = l_RaycastHit.point - (decalProjectorOffset * l_Ray.direction.normalized); Vector3 l_ForwardDirection = Camera.main.transform.up; Vector3 l_UpDirection = -Camera.main.transform.forward; Quaternion l_ProjectorRotation = Quaternion.LookRotation(l_ForwardDirection, l_UpDirection); // Randomize the rotation. Quaternion l_RandomRotation = Quaternion.Euler(0.0f, Random.Range(0.0f, 360.0f), 0.0f); l_ProjectorRotation = l_ProjectorRotation * l_RandomRotation; TerrainCollider l_TerrainCollider = l_RaycastHit.collider as TerrainCollider; if (l_TerrainCollider != null) { // Terrain collider hit. Terrain l_Terrain = l_TerrainCollider.GetComponent <Terrain> (); if (l_Terrain != null) { // Create the decal projector with all the required information. DecalProjector l_DecalProjector = new DecalProjector(l_ProjectorPosition, l_ProjectorRotation, decalProjectorScale, cullingAngle, meshOffset, m_UVRectangleIndex, m_UVRectangleIndex); // Add the projector to our list and the decals mesh, such that both are // synchronized. All the mesh data that is now added to the decals mesh // will belong to this projector. m_DecalProjectors.Add(l_DecalProjector); m_DecalsMesh.AddProjector(l_DecalProjector); // The terrain data has to be converted to the decals instance's space. Matrix4x4 l_TerrainToDecalsMatrix = Matrix4x4.TRS(l_Terrain.transform.position, Quaternion.identity, Vector3.one) * m_WorldToDecalsMatrix; // Pass the terrain data with the corresponding conversion to the decals mesh. m_DecalsMesh.Add(l_Terrain, l_TerrainToDecalsMatrix); // Cut the data in the decals mesh accoring to the size and position of the decal projector. Offset the // vertices afterwards and pass the newly computed mesh to the decals instance, such that it becomes // visible. m_DecalsMeshCutter.CutDecalsPlanes(m_DecalsMesh); m_DecalsMesh.OffsetActiveProjectorVertices(); m_Decals.UpdateDecalsMeshes(m_DecalsMesh); // Update the vertex colors too. Color l_VertexColor = CurrentColor; int l_VertexCount = l_DecalProjector.DecalsMeshUpperVertexIndex - l_DecalProjector.DecalsMeshLowerVertexIndex + 1; for (int i = 0; i < l_VertexCount; i = i + 1) { m_VertexColors.Add(l_VertexColor); } m_Decals.DecalsMeshRenderers [0].MeshFilter.mesh.colors = m_VertexColors.ToArray(); // For the next hit, use a new uv rectangle. Usually, you would select the uv rectangle // based on the surface you have hit. NextUVRectangleIndex(); NextColorIndex(); } else { Debug.Log("Terrain is null!"); } } else { // We hit a collider. Next we have to find the mesh that belongs to the collider. // That step depends on how you set up your mesh filters and collider relative to // each other in the game objects. It is important to have a consistent way in order // to have a simpler implementation. MeshCollider l_MeshCollider = l_RaycastHit.collider.GetComponent <MeshCollider> (); MeshFilter l_MeshFilter = l_RaycastHit.collider.GetComponent <MeshFilter> (); if (l_MeshCollider != null || l_MeshFilter != null) { Mesh l_Mesh = null; if (l_MeshCollider != null) { // Mesh collider was hit. Just use the mesh data from that one. l_Mesh = l_MeshCollider.sharedMesh; } else if (l_MeshFilter != null) { // Otherwise take the data from the shared mesh. l_Mesh = l_MeshFilter.sharedMesh; } if (l_Mesh != null) { // Create the decal projector. DecalProjector l_DecalProjector = new DecalProjector(l_ProjectorPosition, l_ProjectorRotation, decalProjectorScale, cullingAngle, meshOffset, m_UVRectangleIndex, m_UVRectangleIndex); // Add the projector to our list and the decals mesh, such that both are // synchronized. All the mesh data that is now added to the decals mesh // will belong to this projector. m_DecalProjectors.Add(l_DecalProjector); m_DecalsMesh.AddProjector(l_DecalProjector); // Get the required matrices. Matrix4x4 l_WorldToMeshMatrix = l_RaycastHit.collider.renderer.transform.worldToLocalMatrix; Matrix4x4 l_MeshToWorldMatrix = l_RaycastHit.collider.renderer.transform.localToWorldMatrix; // Add the mesh data to the decals mesh, cut and offset it before we pass it // to the decals instance to be displayed. m_DecalsMesh.Add(l_Mesh, l_WorldToMeshMatrix, l_MeshToWorldMatrix); m_DecalsMeshCutter.CutDecalsPlanes(m_DecalsMesh); m_DecalsMesh.OffsetActiveProjectorVertices(); m_Decals.UpdateDecalsMeshes(m_DecalsMesh); // Update the vertex colors too. Color l_VertexColor = CurrentColor; int l_VertexCount = l_DecalProjector.DecalsMeshUpperVertexIndex - l_DecalProjector.DecalsMeshLowerVertexIndex + 1; for (int i = 0; i < l_VertexCount; i = i + 1) { m_VertexColors.Add(l_VertexColor); } m_Decals.DecalsMeshRenderers [0].MeshFilter.mesh.colors = m_VertexColors.ToArray(); // For the next hit, use a new uv rectangle. Usually, you would select the uv rectangle // based on the surface you have hit. NextUVRectangleIndex(); NextColorIndex(); } } } } } }
void DrawBoxTransformationHandles(DecalProjector decalProjector) { Vector3 scale = decalProjector.effectiveScale; using (new Handles.DrawingScope(fullColor, Matrix4x4.TRS(decalProjector.transform.position, decalProjector.transform.rotation, scale))) { Vector3 centerStart = decalProjector.pivot; boxHandle.center = centerStart; boxHandle.size = decalProjector.size; Vector3 boundsSizePreviousOS = boxHandle.size; Vector3 boundsMinPreviousOS = boxHandle.size * -0.5f + boxHandle.center; EditorGUI.BeginChangeCheck(); boxHandle.DrawHandle(); if (EditorGUI.EndChangeCheck()) { // Adjust decal transform if handle changed. Undo.RecordObject(decalProjector, "Decal Projector Change"); bool xChangeIsValid = scale.x != 0f; bool yChangeIsValid = scale.y != 0f; bool zChangeIsValid = scale.z != 0f; // Preserve serialized state for axes with scale 0. decalProjector.size = new Vector3( xChangeIsValid ? boxHandle.size.x : decalProjector.size.x, yChangeIsValid ? boxHandle.size.y : decalProjector.size.y, zChangeIsValid ? boxHandle.size.z : decalProjector.size.z); decalProjector.pivot = new Vector3( xChangeIsValid ? boxHandle.center.x : decalProjector.pivot.x, yChangeIsValid ? boxHandle.center.y : decalProjector.pivot.y, zChangeIsValid ? boxHandle.center.z : decalProjector.pivot.z); Vector3 boundsSizeCurrentOS = boxHandle.size; Vector3 boundsMinCurrentOS = boxHandle.size * -0.5f + boxHandle.center; if (editMode == k_EditShapePreservingUV) { // Treat decal projector bounds as a crop tool, rather than a scale tool. // Compute a new uv scale and bias terms to pin decal projection pixels in world space, irrespective of projector bounds. // Preserve serialized state for axes with scale 0. Vector2 uvScale = decalProjector.uvScale; Vector2 uvBias = decalProjector.uvBias; if (xChangeIsValid) { uvScale.x *= Mathf.Max(k_LimitInv, boundsSizeCurrentOS.x) / Mathf.Max(k_LimitInv, boundsSizePreviousOS.x); uvBias.x += (boundsMinCurrentOS.x - boundsMinPreviousOS.x) / Mathf.Max(k_LimitInv, boundsSizeCurrentOS.x) * uvScale.x; } if (yChangeIsValid) { uvScale.y *= Mathf.Max(k_LimitInv, boundsSizeCurrentOS.y) / Mathf.Max(k_LimitInv, boundsSizePreviousOS.y); uvBias.y += (boundsMinCurrentOS.y - boundsMinPreviousOS.y) / Mathf.Max(k_LimitInv, boundsSizeCurrentOS.y) * uvScale.y; } decalProjector.uvScale = uvScale; decalProjector.uvBias = uvBias; } if (PrefabUtility.IsPartOfNonAssetPrefabInstance(decalProjector)) { PrefabUtility.RecordPrefabInstancePropertyModifications(decalProjector); } // Smoothly update the decal image projected DecalSystem.instance.UpdateCachedData(decalProjector.Handle, decalProjector.GetCachedDecalData()); } } }
void DrawHandles() { //Note: each target need to be handled individually to allow multi edition DecalProjector decalProjector = target as DecalProjector; if (editMode == k_EditShapePreservingUV || editMode == k_EditShapeWithoutPreservingUV) { using (new Handles.DrawingScope(Color.white, Matrix4x4.TRS(decalProjector.transform.position, decalProjector.transform.rotation, Vector3.one))) { bool needToRefreshDecalProjector = false; handle.center = decalProjector.offset; handle.size = decalProjector.size; Vector3 boundsSizePreviousOS = handle.size; Vector3 boundsMinPreviousOS = handle.size * -0.5f + handle.center; EditorGUI.BeginChangeCheck(); handle.DrawHandle(); if (EditorGUI.EndChangeCheck()) { needToRefreshDecalProjector = true; // Adjust decal transform if handle changed. Undo.RecordObject(decalProjector, "Decal Projector Change"); decalProjector.size = handle.size; decalProjector.offset = handle.center; Vector3 boundsSizeCurrentOS = handle.size; Vector3 boundsMinCurrentOS = handle.size * -0.5f + handle.center; if (editMode == k_EditShapePreservingUV) { // Treat decal projector bounds as a crop tool, rather than a scale tool. // Compute a new uv scale and bias terms to pin decal projection pixels in world space, irrespective of projector bounds. Vector2 uvScale = decalProjector.uvScale; uvScale.x *= Mathf.Max(1e-5f, boundsSizeCurrentOS.x) / Mathf.Max(1e-5f, boundsSizePreviousOS.x); uvScale.y *= Mathf.Max(1e-5f, boundsSizeCurrentOS.y) / Mathf.Max(1e-5f, boundsSizePreviousOS.y); decalProjector.uvScale = uvScale; Vector2 uvBias = decalProjector.uvBias; uvBias.x += (boundsMinCurrentOS.x - boundsMinPreviousOS.x) / Mathf.Max(1e-5f, boundsSizeCurrentOS.x) * decalProjector.uvScale.x; uvBias.y += (boundsMinCurrentOS.y - boundsMinPreviousOS.y) / Mathf.Max(1e-5f, boundsSizeCurrentOS.y) * decalProjector.uvScale.y; decalProjector.uvBias = uvBias; } if (PrefabUtility.IsPartOfNonAssetPrefabInstance(decalProjector)) { PrefabUtility.RecordPrefabInstancePropertyModifications(decalProjector); } } // [TODO: remove this part. As soon as you select component that are old enough to have Offset not reseted, it will change the position // It is also incompatible with pivot management] // Automatically recenter our transform component if necessary. // In order to correctly handle world-space snapping, we only perform this recentering when the user is no longer interacting with the gizmo. if ((GUIUtility.hotControl == 0) && (decalProjector.offset != Vector3.zero)) { needToRefreshDecalProjector = true; // Both the DecalProjectorComponent, and the transform will be modified. // The undo system will automatically group all RecordObject() calls here into a single action. Undo.RecordObject(decalProjector, "Decal Projector Change"); // Re-center the transform to the center of the decal projector bounds, // while maintaining the world-space coordinates of the decal projector boundings vertices. decalProjector.transform.Translate(decalProjector.offset, Space.Self); decalProjector.offset = Vector3.zero; if (PrefabUtility.IsPartOfNonAssetPrefabInstance(decalProjector)) { PrefabUtility.RecordPrefabInstancePropertyModifications(decalProjector); } } if (needToRefreshDecalProjector) { // Smoothly update the decal image projected Matrix4x4 sizeOffset = Matrix4x4.Translate(decalProjector.decalOffset) * Matrix4x4.Scale(decalProjector.decalSize); DecalSystem.instance.UpdateCachedData(decalProjector.position, decalProjector.rotation, sizeOffset, decalProjector.drawDistance, decalProjector.fadeScale, decalProjector.uvScaleBias, decalProjector.affectsTransparency, decalProjector.Handle, decalProjector.gameObject.layer, decalProjector.fadeFactor); } } } //[TODO: add editable pivot. Uncomment this when ready] //else if (editMode == k_EditUV) //{ // //here should be handles code to manipulate the pivot without changing the UV //} }
private void Update() { if (Input.GetKeyDown(KeyCode.C)) { // Remove all projectors. while (m_DecalProjectors.Count > 0) { m_DecalsMesh.ClearAll(); m_DecalProjectors.Clear(); // Clearing of the decals mesh means we need to initialize it again. m_DecalsMesh.Initialize(m_DecalsInstance); } m_DecalsInstance.UpdateDecalsMeshes(m_DecalsMesh); } if (Input.GetButtonDown("Fire1")) { Ray l_Ray = Camera.main.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0.0f)); RaycastHit l_RaycastHit; if (Physics.Raycast(l_Ray, out l_RaycastHit, Mathf.Infinity)) { // Collider hit. // Make sure there are not too many projectors. if (m_DecalProjectors.Count >= m_MaximumNumberOfProjectors) { // If there are more than the maximum number of projectors, we delete // the oldest one. DecalProjector l_DecalProjector = m_DecalProjectors [0]; m_DecalProjectors.RemoveAt(0); m_DecalsMesh.RemoveProjector(l_DecalProjector); } // Calculate the position and rotation for the new decal projector. Vector3 l_ProjectorPosition = l_RaycastHit.point - (m_DecalProjectorOffset * l_Ray.direction.normalized); Quaternion l_ProjectorRotation = ProjectorRotationUtility.ProjectorRotation(Camera.main.transform.forward, Vector3.up); // Randomize the rotation. Quaternion l_RandomRotation = Quaternion.Euler(0.0f, Random.Range(0.0f, 360.0f), 0.0f); l_ProjectorRotation = l_ProjectorRotation * l_RandomRotation; TerrainCollider l_TerrainCollider = l_RaycastHit.collider as TerrainCollider; if (l_TerrainCollider != null) { // Terrain collider hit. Terrain l_Terrain = l_TerrainCollider.GetComponent <Terrain> (); if (l_Terrain != null) { // Create the decal projector with all the required information. DecalProjector l_DecalProjector = new DecalProjector(l_ProjectorPosition, l_ProjectorRotation, m_DecalProjectorScale, m_CullingAngle, m_MeshOffset, m_UVRectangleIndex, m_UVRectangleIndex); // Add the projector to our list and the decals mesh, such that both are // synchronized. All the mesh data that is now added to the decals mesh // will belong to this projector. m_DecalProjectors.Add(l_DecalProjector); m_DecalsMesh.AddProjector(l_DecalProjector); // The terrain data has to be converted to the decals instance's space. Matrix4x4 l_TerrainToDecalsMatrix = m_WorldToDecalsMatrix * Matrix4x4.TRS(l_Terrain.transform.position, Quaternion.identity, Vector3.one); // Pass the terrain data with the corresponding conversion to the decals mesh. m_DecalsMesh.Add(l_Terrain, l_TerrainToDecalsMatrix); // Cut and offset the decals mesh. m_DecalsMeshCutter.CutDecalsPlanes(m_DecalsMesh); m_DecalsMesh.OffsetActiveProjectorVertices(); // The changes are only present in the decals mesh at the moment. We have // to pass them to the decals instance to visualize them. m_DecalsInstance.UpdateDecalsMeshes(m_DecalsMesh); // For the next hit, use a new uv rectangle. Usually, you would select the uv rectangle // based on the surface you have hit. NextUVRectangleIndex(); } else { Debug.LogError("Terrain is null!"); } } else { // We hit a collider. Next we have to find the mesh that belongs to the collider. // That step depends on how you set up your mesh filters and collider relative to // each other in the game objects. It is important to have a consistent way in order // to have a simpler implementation. MeshCollider l_MeshCollider = l_RaycastHit.collider.GetComponent <MeshCollider> (); MeshFilter l_MeshFilter = l_RaycastHit.collider.GetComponent <MeshFilter> (); if (l_MeshCollider != null || l_MeshFilter != null) { Mesh l_Mesh = null; if (l_MeshCollider != null) { // Mesh collider was hit. Just use the mesh data from that one. l_Mesh = l_MeshCollider.sharedMesh; } else if (l_MeshFilter != null) { // Otherwise take the data from the shared mesh. l_Mesh = l_MeshFilter.sharedMesh; } if (l_Mesh != null) { // Create the decal projector. DecalProjector l_DecalProjector = new DecalProjector(l_ProjectorPosition, l_ProjectorRotation, m_DecalProjectorScale, m_CullingAngle, m_MeshOffset, m_UVRectangleIndex, m_UVRectangleIndex); // Add the projector to our list and the decals mesh, such that both are // synchronized. All the mesh data that is now added to the decals mesh // will belong to this projector. m_DecalProjectors.Add(l_DecalProjector); m_DecalsMesh.AddProjector(l_DecalProjector); // Get the required matrices. Matrix4x4 l_WorldToMeshMatrix = l_RaycastHit.collider.renderer.transform.worldToLocalMatrix; Matrix4x4 l_MeshToWorldMatrix = l_RaycastHit.collider.renderer.transform.localToWorldMatrix; // Add the mesh data to the decals mesh, cut and offset it. m_DecalsMesh.Add(l_Mesh, l_WorldToMeshMatrix, l_MeshToWorldMatrix); m_DecalsMeshCutter.CutDecalsPlanes(m_DecalsMesh); m_DecalsMesh.OffsetActiveProjectorVertices(); // The changes are only present in the decals mesh at the moment. We have // to pass them to the decals instance to visualize them. m_DecalsInstance.UpdateDecalsMeshes(m_DecalsMesh); // For the next hit, use a new uv rectangle. Usually, you would select the uv rectangle // based on the surface you have hit. NextUVRectangleIndex(); } } } } } }
protected override void Awake() { m_decal = GetComponent <DecalProjector>(); base.Awake(); }
private void Start() { _mainCamera = Camera.main.gameObject; _target = GetComponent <DecalProjector>(); SceneManager.sceneLoaded += OnSceneLoaded; }