Vector3[] _pointsViewSpace = new Vector3[8]; // cached these values void CalculateMinMax(out Vector3 min, out Vector3 max, bool forceFrustrumUpdate) { if (_frustrumPoints == null || forceFrustrumUpdate) { if (lightType == LightTypes.Point || lightType == LightTypes.Area) { VLightGeometryUtil.RecalculateFrustrumPoints(cam.orthographic, pointLightRadius, spotAngle, -pointLightRadius, pointLightRadius, aspect, out _frustrumPoints); } else { VLightGeometryUtil.RecalculateFrustrumPoints(cam.orthographic, orthoSize, spotAngle, Mathf.Max(0.01f, spotNear), spotRange, aspect, out _frustrumPoints); } } Vector3 vecMinBounds = new Vector3(Mathf.NegativeInfinity, Mathf.NegativeInfinity, Mathf.NegativeInfinity); Vector3 vecMaxBounds = new Vector3(Mathf.Infinity, Mathf.Infinity, Mathf.Infinity); Matrix4x4 minMaxMatrix = _viewWorldToCameraMatrixCached * _localToWorldMatrix; for (int i = 0; i < _frustrumPoints.Length; i++) { _pointsViewSpace[i] = minMaxMatrix.MultiplyPoint3x4(_frustrumPoints[i]); vecMinBounds.x = (vecMinBounds.x > _pointsViewSpace[i].x) ? vecMinBounds.x : _pointsViewSpace[i].x; vecMinBounds.y = (vecMinBounds.y > _pointsViewSpace[i].y) ? vecMinBounds.y : _pointsViewSpace[i].y; vecMinBounds.z = (vecMinBounds.z > _pointsViewSpace[i].z) ? vecMinBounds.z : _pointsViewSpace[i].z; vecMaxBounds.x = (vecMaxBounds.x <= _pointsViewSpace[i].x) ? vecMaxBounds.x : _pointsViewSpace[i].x; vecMaxBounds.y = (vecMaxBounds.y <= _pointsViewSpace[i].y) ? vecMaxBounds.y : _pointsViewSpace[i].y; vecMaxBounds.z = (vecMaxBounds.z <= _pointsViewSpace[i].z) ? vecMaxBounds.z : _pointsViewSpace[i].z; } min = vecMinBounds; max = vecMaxBounds; }
private void CalculateMinMax(out Vector3 min, out Vector3 max, bool forceFrustrumUpdate) { if (_frustrumPoints == null || forceFrustrumUpdate) { VLightGeometryUtil.RecalculateFrustrumPoints(camera, 1.0f, out _frustrumPoints); } Vector3[] pointsViewSpace = new Vector3[8]; Vector3 vecMinBounds = new Vector3(Mathf.NegativeInfinity, Mathf.NegativeInfinity, Mathf.NegativeInfinity); Vector3 vecMaxBounds = new Vector3(Mathf.Infinity, Mathf.Infinity, Mathf.Infinity); Matrix4x4 minMaxMatrix = _viewWorldToCameraMatrixCached * _localToWorldMatrix; for (int i = 0; i < _frustrumPoints.Length; i++) { pointsViewSpace[i] = minMaxMatrix.MultiplyPoint((_frustrumPoints[i])); vecMinBounds.x = (vecMinBounds.x > pointsViewSpace[i].x) ? vecMinBounds.x : pointsViewSpace[i].x; vecMinBounds.y = (vecMinBounds.y > pointsViewSpace[i].y) ? vecMinBounds.y : pointsViewSpace[i].y; vecMinBounds.z = (vecMinBounds.z > pointsViewSpace[i].z) ? vecMinBounds.z : pointsViewSpace[i].z; vecMaxBounds.x = (vecMaxBounds.x <= pointsViewSpace[i].x) ? vecMaxBounds.x : pointsViewSpace[i].x; vecMaxBounds.y = (vecMaxBounds.y <= pointsViewSpace[i].y) ? vecMaxBounds.y : pointsViewSpace[i].y; vecMaxBounds.z = (vecMaxBounds.z <= pointsViewSpace[i].z) ? vecMaxBounds.z : pointsViewSpace[i].z; } min = vecMinBounds; max = vecMaxBounds; }
// [SerializeField] // private AnimationCurve _planeDistribution = AnimationCurve.Linear(0, 0, 1, 1); void BuildMesh(bool manualPositioning, int planeCount, Vector3 minBounds, Vector3 maxBounds) { if (meshContainer == null || meshContainer.name.IndexOf(GetInstanceID().ToString(), System.StringComparison.OrdinalIgnoreCase) != 0) { #if DEBUG_MODE Debug.Log("Creating new mesh container"); #endif meshContainer = new Mesh(); meshContainer.MarkDynamic(); meshContainer.hideFlags = HideFlags.HideAndDontSave; meshContainer.name = GetInstanceID().ToString(); } if (_meshFilter == null) { _meshFilter = GetComponent <MeshFilter>(); } Vector3[] vertBucket = new Vector3[VERT_COUNT]; int[] triBucket = new int[TRI_COUNT]; int vertBucketCount = 0; int triBucketCount = 0; float depthOffset = 1.0f / (float)(planeCount - 1); float depth = (manualPositioning) ? 1f : 0f; float xLeft = 0f; float xRight = 1f; float xBottom = 0f; float xTop = 1f; int vertOffset = 0; for (int i = 0; i < planeCount; i++) { Vector3[] verts = new Vector3[4]; Vector3[] results; if (manualPositioning) { Plane[] planes = GeometryUtility.CalculateFrustumPlanes(_projectionMatrixCached * cam.worldToCameraMatrix); for (int j = 0; j < planes.Length; j++) { Vector3 centre = planes[j].normal * -planes[j].distance; planes[j] = new Plane(_viewWorldToCameraMatrixCached.MultiplyVector(planes[j].normal), _viewWorldToCameraMatrixCached.MultiplyPoint3x4(centre)); } verts[0] = CalculateTriLerp(new Vector3(xLeft, xBottom, depth), minBounds, maxBounds); verts[1] = CalculateTriLerp(new Vector3(xLeft, xTop, depth), minBounds, maxBounds); verts[2] = CalculateTriLerp(new Vector3(xRight, xTop, depth), minBounds, maxBounds); verts[3] = CalculateTriLerp(new Vector3(xRight, xBottom, depth), minBounds, maxBounds); results = VLightGeometryUtil.ClipPolygonAgainstPlane(verts, planes); } else { // var dp = _planeDistribution.Evaluate(depth); var dp = depth; verts[0] = new Vector3(xLeft, xBottom, dp); verts[1] = new Vector3(xLeft, xTop, dp); verts[2] = new Vector3(xRight, xTop, dp); verts[3] = new Vector3(xRight, xBottom, dp); results = verts; } depth += (manualPositioning) ? -depthOffset : depthOffset; if (results.Length > 2) { Array.Copy(results, 0, vertBucket, vertBucketCount, results.Length); vertBucketCount += results.Length; int[] tris = new int[(results.Length - 2) * 3]; int vertOff = 0; for (int j = 0; j < tris.Length; j += 3) { tris[j + 0] = vertOffset + 0; tris[j + 1] = vertOffset + (vertOff + 1); tris[j + 2] = vertOffset + (vertOff + 2); vertOff++; #if DEBUG_MODE Color lightBlue = new Color(0, 0, 1, 0.05f); Matrix4x4 cameraToWorld = _viewCameraToWorldMatrixCached; Debug.DrawLine(cameraToWorld.MultiplyPoint(vertBucket[tris[j + 0]]), cameraToWorld.MultiplyPoint(vertBucket[tris[j + 1]]), lightBlue); Debug.DrawLine(cameraToWorld.MultiplyPoint(vertBucket[tris[j + 1]]), cameraToWorld.MultiplyPoint(vertBucket[tris[j + 2]]), lightBlue); Debug.DrawLine(cameraToWorld.MultiplyPoint(vertBucket[tris[j + 2]]), cameraToWorld.MultiplyPoint(vertBucket[tris[j + 0]]), lightBlue); #endif } vertOffset += results.Length; Array.Copy(tris, 0, triBucket, triBucketCount, tris.Length); triBucketCount += tris.Length; } } meshContainer.Clear(); Vector3[] newVerts = new Vector3[vertBucketCount]; Array.Copy(vertBucket, newVerts, vertBucketCount); meshContainer.vertices = newVerts; int[] newTris = new int[triBucketCount]; Array.Copy(triBucket, newTris, triBucketCount); meshContainer.triangles = newTris; meshContainer.normals = new Vector3[vertBucketCount]; meshContainer.uv = new Vector2[vertBucketCount]; Vector3 centrePT = Vector3.zero; foreach (var vert in _frustrumPoints) { centrePT += vert; } centrePT /= _frustrumPoints.Length; Bounds localBounds = new Bounds(centrePT, Vector3.zero); foreach (var vert in _frustrumPoints) { localBounds.Encapsulate(vert); } _meshFilter.sharedMesh = meshContainer; localBounds.center += _boundsCentreOffset; _meshFilter.sharedMesh.bounds = localBounds; }
// private void OnGUI() // { // var bounds = new Bounds(); // var vlights = GameObject.FindObjectsOfType<VLight>(); // foreach(var vlight in vlights) // { // bounds.max = Camera.main.cameraToWorldMatrix.MultiplyPoint(vlight.MaxBounds); // bounds.min = Camera.main.cameraToWorldMatrix.MultiplyPoint(vlight.MinBounds); // // var rect = VLightGeometryUtil.BoundsToRect(bounds, Camera.main); // rect.y = rect.y; // GUI.Box(rect, ""); // } // } private void OnRenderImage(RenderTexture source, RenderTexture destination) { var cam = Camera.current; var planes = GeometryUtility.CalculateFrustumPlanes(cam); if (!Application.isPlaying) { _vlights = GameObject.FindObjectsOfType <VLight>(); } if (lightsModified) { lightsModified = false; _vlights = GameObject.FindObjectsOfType <VLight>(); } var bounds = new Bounds(); var lightsVisible = false; var renderInterleaved = false; for (var i = 0; i < _vlights.Length; i++) { var vlight = _vlights[i]; if (GeometryUtility.TestPlanesAABB(planes, vlight.MeshRender.bounds)) { bounds.max = cam.cameraToWorldMatrix.MultiplyPoint(vlight.MaxBounds); bounds.min = cam.cameraToWorldMatrix.MultiplyPoint(vlight.MinBounds); var rect = VLightGeometryUtil.BoundsToRect(bounds, cam); var area = rect.width * rect.height; if (area > (minInterleavedRes * minInterleavedRes)) { renderInterleaved = true; } lightsVisible = true; } } if (!lightsVisible) { Graphics.Blit(source, destination); return; } var downsampleFactor = Mathf.Clamp(downSample, 1, 20); blurIterations = Mathf.Clamp(blurIterations, 0, 20); if (_useBilateralFiltering) { downsampleFactor = 2; } var width = cam.pixelWidth; var height = cam.pixelHeight; var dsWidth = cam.pixelWidth / downsampleFactor; var dsHeight = cam.pixelHeight / downsampleFactor; var frameBufferFormat = _useHighPrecisionFrameBuffer ? RenderTextureFormat.ARGBFloat : RenderTextureFormat.ARGB32; #if UNITY_EDITOR if (!SystemInfo.SupportsRenderTextureFormat(frameBufferFormat)) { frameBufferFormat = RenderTextureFormat.ARGBHalf; if (!SystemInfo.SupportsRenderTextureFormat(frameBufferFormat)) { frameBufferFormat = RenderTextureFormat.ARGB32; Debug.LogWarning("Platform does not support floating point textures"); } } #endif // 4 samples for the interleaved buffer var bufferA = RenderTexture.GetTemporary(dsWidth, dsHeight, 0, frameBufferFormat); if (interleavedBuffer != null && (interleavedBuffer.width != width || interleavedBuffer.height != height)) { if (Application.isPlaying) { Destroy(interleavedBuffer); } else { DestroyImmediate(interleavedBuffer); } interleavedBuffer = null; } if (interleavedBuffer == null) { interleavedBuffer = new RenderTexture(width, height, 0); interleavedBuffer.hideFlags = HideFlags.HideAndDontSave; } var ppCamera = GetPPCamera(); ppCamera.CopyFrom(cam); ppCamera.enabled = false; ppCamera.depthTextureMode = DepthTextureMode.None; ppCamera.clearFlags = CameraClearFlags.SolidColor; ppCamera.cullingMask = _volumeLightLayer; ppCamera.useOcclusionCulling = false; ppCamera.backgroundColor = Color.clear; ppCamera.renderingPath = RenderingPath.VertexLit; renderingInterleaved = false; if (useInterleavedSampling && renderInterleaved) { var bufferB = RenderTexture.GetTemporary(dsWidth, dsHeight, 0, frameBufferFormat); var bufferC = RenderTexture.GetTemporary(dsWidth, dsHeight, 0, frameBufferFormat); var bufferD = RenderTexture.GetTemporary(dsWidth, dsHeight, 0, frameBufferFormat); // For odd projection matrices ppCamera.projectionMatrix = cam.projectionMatrix; ppCamera.pixelRect = new Rect( 0, 0, cam.pixelWidth / cam.rect.width + Screen.width / cam.rect.width, cam.pixelHeight / cam.rect.height + Screen.height / cam.rect.height); // Render the interleaved samples float offset = 0.0f; renderCount = 0; RenderSample(offset, ppCamera, bufferA); if (renderCount == 0) { Graphics.Blit(source, destination); RenderTexture.ReleaseTemporary(bufferA); RenderTexture.ReleaseTemporary(bufferB); RenderTexture.ReleaseTemporary(bufferC); RenderTexture.ReleaseTemporary(bufferD); return; } renderingInterleaved = true; offset += ditherOffset; RenderSample(offset, ppCamera, bufferB); offset += ditherOffset; RenderSample(offset, ppCamera, bufferC); offset += ditherOffset; RenderSample(offset, ppCamera, bufferD); //Combine the 4 samples to make an interleaved image and the edge border PostMaterial.SetTexture("_MainTexA", bufferA); PostMaterial.SetTexture("_MainTexB", bufferB); PostMaterial.SetTexture("_MainTexC", bufferC); PostMaterial.SetTexture("_MainTexD", bufferD); interleavedBuffer.DiscardContents(); Graphics.Blit(null, interleavedBuffer, PostMaterial, 0); RenderTexture.ReleaseTemporary(bufferB); RenderTexture.ReleaseTemporary(bufferC); RenderTexture.ReleaseTemporary(bufferD); } else { ppCamera.projectionMatrix = cam.projectionMatrix; ppCamera.pixelRect = new Rect( 0, 0, cam.pixelWidth / cam.rect.width + Screen.width / cam.rect.width, cam.pixelHeight / cam.rect.height + Screen.height / cam.rect.height); renderCount = 0; RenderSample(0, ppCamera, bufferA); if (renderCount == 0) { Graphics.Blit(source, destination); RenderTexture.ReleaseTemporary(bufferA); return; } Graphics.Blit(bufferA, interleavedBuffer); } renderingInterleaved = false; var pingPong = RenderTexture.GetTemporary(width, height, 0); pingPong.DiscardContents(); PostMaterial.SetFloat("_BlurSize", blurRadius); if (_useBilateralFiltering) { var quarterDepthTexture = RenderTexture.GetTemporary(dsWidth, dsHeight, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear, 1); //quarterDepthTexture.filterMode = FilterMode.Point; quarterDepthTexture.wrapMode = TextureWrapMode.Clamp; Graphics.Blit(source, quarterDepthTexture, DownscaleDepthMaterial); PostMaterial.SetFloat("BlurDepthFalloff", _blurDepth); PostMaterial.SetTexture("LowResDepthTexture", quarterDepthTexture); for (int i = 0; i < blurIterations; i++) { PostMaterial.SetVector("BlurDir", new Vector2(0, blurRadius)); Graphics.Blit(interleavedBuffer, pingPong, PostMaterial, 4); PostMaterial.SetVector("BlurDir", new Vector2(blurRadius, 0)); Graphics.Blit(pingPong, interleavedBuffer, PostMaterial, 4); PostMaterial.SetVector("BlurDir", new Vector2(0, blurRadius)); Graphics.Blit(interleavedBuffer, pingPong, PostMaterial, 4); PostMaterial.SetVector("BlurDir", new Vector2(blurRadius, 0)); Graphics.Blit(pingPong, interleavedBuffer, PostMaterial, 4); } RenderTexture.ReleaseTemporary(pingPong); RenderTexture.ReleaseTemporary(bufferA); PostMaterial.SetFloat("DepthThreshold", _depthThreshold); var interleavedBufferPoint = RenderTexture.GetTemporary(dsWidth, dsHeight, 0, RenderTextureFormat.ARGB32); Graphics.Blit(interleavedBuffer, interleavedBufferPoint); interleavedBufferPoint.filterMode = FilterMode.Point; PostMaterial.SetTexture("_MainTexBlurred", interleavedBuffer); PostMaterial.SetTexture("_MainTexBlurredPoint", interleavedBufferPoint); Graphics.Blit(source, destination, PostMaterial, 3); RenderTexture.ReleaseTemporary(interleavedBufferPoint); RenderTexture.ReleaseTemporary(quarterDepthTexture); } else { for (int i = 0; i < blurIterations; i++) { Graphics.Blit(interleavedBuffer, pingPong, PostMaterial, 1); interleavedBuffer.DiscardContents(); Graphics.Blit(pingPong, interleavedBuffer, PostMaterial, 2); pingPong.DiscardContents(); } PostMaterial.SetTexture("_MainTexBlurred", interleavedBuffer); Graphics.Blit(source, destination, PostMaterial, 5); RenderTexture.ReleaseTemporary(pingPong); RenderTexture.ReleaseTemporary(bufferA); } }