/// <summary> /// Returns the mesh managers suitable for a shadow. /// </summary> /// <param name="shadow"> /// The shadow to get mesh manager for. /// </param> /// <returns> /// The <see cref="ShadowMeshManager"/>. /// </returns> private ShadowMeshManager GetMeshManager(SwiftShadow shadow) { ShadowMeshManager meshManager; if (_meshManagers.TryGetValue(shadow.GetMeshManagerHashCode(), out meshManager)) { return(meshManager); } if (shadow.Material == null) { throw new ArgumentNullException("shadow.material"); } if (_meshManagersNew.TryGetValue(shadow.GetMeshManagerHashCode(), out meshManager)) { return(meshManager); } meshManager = new ShadowMeshManager(shadow.Material, shadow.Layer, shadow.IsStatic); if (_isRecalculatingMesh) { _meshManagersNew.Add(meshManager.GetInstanceHashCode(), meshManager); } else { _meshManagers.Add(meshManager.GetInstanceHashCode(), meshManager); } return(meshManager); }
/// <summary> /// Recalculates the geometry of every attached shadow and builds a batched mesh. /// </summary> /// <param name="frustumPlanes"> /// The frustum planes of camera that renders the scene. /// Ignored when recalculating static shadows. /// </param> /// <param name="skipRecalculate"> /// Whether to skip recalculation of shadow geometry. /// </param> private void RecalculateGeometry(Plane[] frustumPlanes, bool skipRecalculate) { // No need to rebuild static mesh when it hasn't changed bool mustRebuildMesh = !_isStatic || _isStaticDirty; int currentVisibleShadowsCount = 0; if (_isStatic) { frustumPlanes = null; } for (int i = 0, shadowCount = _shadowsList.Count; i < shadowCount; i++) { SwiftShadow shadow = _shadowsList.Items[i]; if (!skipRecalculate) { SwiftShadow.RecalculateShadowResult recalculateResult = shadow.RecalculateShadow(frustumPlanes, false); switch (recalculateResult) { case SwiftShadow.RecalculateShadowResult.ChangedManager: i--; shadowCount = _shadowsList.Count; continue; case SwiftShadow.RecalculateShadowResult.Recalculated: mustRebuildMesh = true; break; } } if (shadow.IsVisible) { currentVisibleShadowsCount++; } } if (!mustRebuildMesh || (_visibleShadowsCount == 0 && currentVisibleShadowsCount == 0)) { return; } _visibleShadowsCount = currentVisibleShadowsCount; if (_visibleShadowsCount != 0) { bool isMeshNull = _mesh == null; if (isMeshNull) { CreateMesh(); } RebuildMesh(isMeshNull || _isStatic || _isStaticDirty); _isStaticDirty = false; } _lastVisibleShadowsCount = _visibleShadowsCount; }
/// <summary> /// Registers the shadow in this manager. /// </summary> /// <param name="shadow"> /// The shadow to register. /// </param> public void RegisterShadow(SwiftShadow shadow) { if (_isStatic) { shadow.RecalculateShadow(null, true); } _shadowsList.Add(shadow); _isStaticDirty = true; }
/// <summary> /// Unregisters the shadow. /// </summary> /// <param name="shadow"> /// The shadow to unregister. /// </param> public void UnregisterShadow(SwiftShadow shadow) { ShadowMeshManager meshManager; int shadowHash = shadow.GetMeshManagerHashCode(); if (_meshManagers.TryGetValue(shadowHash, out meshManager)) { meshManager.UnregisterShadow(shadow); } }
/// <summary> /// Rebuilds the batched mesh. /// </summary> /// <param name="forceRebuildTriangles"> /// Whether to force the rebuild of vertex indices. /// </param> private void RebuildMesh(bool forceRebuildTriangles) { bool mustRebuildTriangles = forceRebuildTriangles || _lastVisibleShadowsCount != _visibleShadowsCount; _meshData.EnsureCapacity(_visibleShadowsCount); Vector3 meshBoundsMin; meshBoundsMin.x = float.MaxValue; meshBoundsMin.y = float.MaxValue; meshBoundsMin.z = float.MaxValue; Vector3 meshBoundsMax; meshBoundsMax.x = float.MinValue; meshBoundsMax.y = float.MinValue; meshBoundsMax.z = float.MinValue; int index = 1; int triangleIndex = 0; for (int i = 0, shadowsCount = _shadowsList.Count; i < shadowsCount; i++) { SwiftShadow shadow = _shadowsList.Items[i]; if (!shadow.IsVisible) { continue; } Vector3[] shadowVertices = shadow.ShadowVertices; #if SET_MESH_NORMALS Vector3 normal = shadow.Normal; #endif Vector2[] textureUV = shadow.TextureUV; Color32 color32 = shadow.CurrentColor; _meshData.Vertices[index] = shadowVertices[0]; _meshData.Vertices[index + 1] = shadowVertices[1]; _meshData.Vertices[index + 2] = shadowVertices[2]; _meshData.Vertices[index + 3] = shadowVertices[3]; // Calculate min/max X if (shadowVertices[0].x < meshBoundsMin.x) { meshBoundsMin.x = shadowVertices[0].x; } else if (shadowVertices[0].x > meshBoundsMax.x) { meshBoundsMax.x = shadowVertices[0].x; } if (shadowVertices[1].x < meshBoundsMin.x) { meshBoundsMin.x = shadowVertices[1].x; } else if (shadowVertices[1].x > meshBoundsMax.x) { meshBoundsMax.x = shadowVertices[1].x; } if (shadowVertices[2].x < meshBoundsMin.x) { meshBoundsMin.x = shadowVertices[2].x; } else if (shadowVertices[2].x > meshBoundsMax.x) { meshBoundsMax.x = shadowVertices[2].x; } if (shadowVertices[3].x < meshBoundsMin.x) { meshBoundsMin.x = shadowVertices[3].x; } else if (shadowVertices[3].x > meshBoundsMax.x) { meshBoundsMax.x = shadowVertices[3].x; } // Calculate min/max Y if (shadowVertices[0].y < meshBoundsMin.y) { meshBoundsMin.y = shadowVertices[0].y; } else if (shadowVertices[0].y > meshBoundsMax.y) { meshBoundsMax.y = shadowVertices[0].y; } if (shadowVertices[1].y < meshBoundsMin.y) { meshBoundsMin.y = shadowVertices[1].y; } else if (shadowVertices[1].y > meshBoundsMax.y) { meshBoundsMax.y = shadowVertices[1].y; } if (shadowVertices[2].y < meshBoundsMin.y) { meshBoundsMin.y = shadowVertices[2].y; } else if (shadowVertices[2].y > meshBoundsMax.y) { meshBoundsMax.y = shadowVertices[2].y; } if (shadowVertices[3].y < meshBoundsMin.y) { meshBoundsMin.y = shadowVertices[3].y; } else if (shadowVertices[3].y > meshBoundsMax.y) { meshBoundsMax.y = shadowVertices[3].y; } // Calculate min/max Z if (shadowVertices[0].z < meshBoundsMin.z) { meshBoundsMin.z = shadowVertices[0].z; } else if (shadowVertices[0].z > meshBoundsMax.z) { meshBoundsMax.z = shadowVertices[0].z; } if (shadowVertices[1].z < meshBoundsMin.z) { meshBoundsMin.z = shadowVertices[1].z; } else if (shadowVertices[1].z > meshBoundsMax.z) { meshBoundsMax.z = shadowVertices[1].z; } if (shadowVertices[2].z < meshBoundsMin.z) { meshBoundsMin.z = shadowVertices[2].z; } else if (shadowVertices[2].z > meshBoundsMax.z) { meshBoundsMax.z = shadowVertices[2].z; } if (shadowVertices[3].z < meshBoundsMin.z) { meshBoundsMin.z = shadowVertices[3].z; } else if (shadowVertices[3].z > meshBoundsMax.z) { meshBoundsMax.z = shadowVertices[3].z; } _meshData.UV[index] = textureUV[0]; _meshData.UV[index + 1] = textureUV[1]; _meshData.UV[index + 2] = textureUV[2]; _meshData.UV[index + 3] = textureUV[3]; #if SET_MESH_NORMALS _meshData.Normals[index] = normal; _meshData.Normals[index + 1] = normal; _meshData.Normals[index + 2] = normal; _meshData.Normals[index + 3] = normal; #endif _meshData.Colors32[index] = color32; _meshData.Colors32[index + 1] = color32; _meshData.Colors32[index + 2] = color32; _meshData.Colors32[index + 3] = color32; if (mustRebuildTriangles) { _meshData.Indices[triangleIndex] = index + 0; _meshData.Indices[triangleIndex + 1] = index + 1; _meshData.Indices[triangleIndex + 2] = index + 2; _meshData.Indices[triangleIndex + 3] = index + 0; _meshData.Indices[triangleIndex + 4] = index + 2; _meshData.Indices[triangleIndex + 5] = index + 3; triangleIndex += 6; } index += 4; } _mesh.vertices = _meshData.Vertices; #if SET_MESH_NORMALS _mesh.normals = _meshData.Normals; #endif _mesh.uv = _meshData.UV; _mesh.colors32 = _meshData.Colors32; if (mustRebuildTriangles) { _mesh.triangles = _meshData.Indices; } if (meshBoundsMax.x == float.MinValue) { meshBoundsMax.x = meshBoundsMin.x; } if (meshBoundsMax.y == float.MinValue) { meshBoundsMax.y = meshBoundsMin.y; } if (meshBoundsMax.z == float.MinValue) { meshBoundsMax.z = meshBoundsMin.z; } Vector3 meshBoundsExtents = meshBoundsMax - meshBoundsMin; Vector3 meshBoundsCenter = meshBoundsMin + meshBoundsExtents * 0.5f; _mesh.bounds = new Bounds(meshBoundsCenter, meshBoundsExtents); }
/// <summary> /// Unregisters the shadow from this manager. /// </summary> /// <param name="shadow"> /// The shadow to unregister. /// </param> public void UnregisterShadow(SwiftShadow shadow) { _shadowsList.Remove(shadow); _isStaticDirty = true; }
/// <summary> /// Registers the shadow. /// </summary> /// <param name="shadow"> /// The shadow to register. /// </param> public void RegisterShadow(SwiftShadow shadow) { GetMeshManager(shadow).RegisterShadow(shadow); }