bool Culling(ScriptableRenderContext context, Decal decal, ref RenderingData renderingData, out CullingResults cullingResults) { // Setup var camera = renderingData.cameraData.camera; var localScale = decal.transform.lossyScale; cullingResults = new CullingResults(); // Never draw in Preview if (camera.cameraType == CameraType.Preview) { return(false); } // Test for Decal behind Camera var maxRadius = Mathf.Max(Mathf.Max(localScale.x * 0.5f, localScale.y * 0.5f), localScale.z) + kErrorMargin; var positionVS = camera.WorldToViewportPoint(decal.transform.position); if (positionVS.z < -maxRadius) { return(false); } // Get Decal bounds var boundsScale = new Vector3(maxRadius, maxRadius, maxRadius); var bounds = new Bounds(decal.transform.position, boundsScale); // Test against frustum planes var planes = GeometryUtility.CalculateFrustumPlanes(camera); if (!GeometryUtility.TestPlanesAABB(planes, bounds)) { return(false); } // Get CullingParameters var cullingParameters = new ScriptableCullingParameters(); if (!camera.TryGetCullingParameters(out cullingParameters)) { return(false); } // Set culling planes cullingParameters.cullingPlaneCount = 6; for (int i = 0; i < 6; ++i) { cullingParameters.SetCullingPlane(i, decal.clipPlanes[i]); } // Culling Results cullingResults = context.Cull(ref cullingParameters); return(true); }
private bool StartCullingIfVisible(ScriptableRenderContext context, Camera cam) { if (m_frustumVertices == null) { return(false); } ScriptableCullingParameters cullingParameters = new ScriptableCullingParameters(); if (!cam.TryGetCullingParameters(IsStereoEnabled(cam), out cullingParameters)) { return(false); } if (m_temporaryData == null) { m_temporaryData = new TemporaryData(); } uint flags = 0xff; ulong flags64 = 0; for (int i = 0; i < 8; ++i) { Vector3 v = m_temporaryData.m_vertices[i] = transform.TransformPoint(m_frustumVertices[i]); uint f = 0; for (int j = 0; j < cullingParameters.cullingPlaneCount; ++j) { Plane plane = cullingParameters.GetCullingPlane(j); if (plane.GetDistanceToPoint(v) < 0) { f |= (1U << j); } } flags &= f; flags64 |= (((ulong)f) << (8 * i)); } if (flags != 0) { // projector is not visible from the camera return(false); } if (!m_requiresCullingResult) { return(true); } uint cameraPlanes = 0; int planeCount = 0; // -x flags = (uint)((flags64 >> 0) & (flags64 >> 8) & (flags64 >> 32) & (flags64 >> 40)) & 0xFF; if (flags == 0) { m_temporaryData.m_clipPlanes[planeCount++] = new Plane(m_temporaryData.m_vertices[0], m_temporaryData.m_vertices[1], m_temporaryData.m_vertices[4]); } else { cameraPlanes |= flags; } // +x flags = (uint)((flags64 >> 16) & (flags64 >> 24) & (flags64 >> 48) & (flags64 >> 56)) & 0xFF; if (flags == 0) { m_temporaryData.m_clipPlanes[planeCount++] = new Plane(m_temporaryData.m_vertices[3], m_temporaryData.m_vertices[2], m_temporaryData.m_vertices[7]); } else { cameraPlanes |= flags; } // -y flags = (uint)((flags64 >> 0) & (flags64 >> 16) & (flags64 >> 32) & (flags64 >> 48)) & 0xFF; if (flags == 0) { m_temporaryData.m_clipPlanes[planeCount++] = new Plane(m_temporaryData.m_vertices[2], m_temporaryData.m_vertices[0], m_temporaryData.m_vertices[6]); } else { cameraPlanes |= flags; } // +y flags = (uint)((flags64 >> 8) & (flags64 >> 24) & (flags64 >> 40) & (flags64 >> 56)) & 0xFF; if (flags == 0) { m_temporaryData.m_clipPlanes[planeCount++] = new Plane(m_temporaryData.m_vertices[1], m_temporaryData.m_vertices[3], m_temporaryData.m_vertices[5]); } else { cameraPlanes |= flags; } // near flags = (uint)((flags64 >> 0) & (flags64 >> 8) & (flags64 >> 16) & (flags64 >> 24)) & 0xFF; if (flags == 0) { m_temporaryData.m_clipPlanes[planeCount++] = new Plane(m_temporaryData.m_vertices[0], m_temporaryData.m_vertices[2], m_temporaryData.m_vertices[1]); } else { cameraPlanes |= flags; } // far flags = (uint)((flags64 >> 32) & (flags64 >> 40) & (flags64 >> 48) & (flags64 >> 56)) & 0xFF; if (flags == 0) { m_temporaryData.m_clipPlanes[planeCount++] = new Plane(m_temporaryData.m_vertices[4], m_temporaryData.m_vertices[5], m_temporaryData.m_vertices[6]); } else { cameraPlanes |= flags; } int maxPlaneCount = ScriptableCullingParameters.maximumCullingPlaneCount; for (int i = 0; i < cullingParameters.cullingPlaneCount && planeCount < maxPlaneCount; ++i) { if ((cameraPlanes & (1U << i)) != 0) { m_temporaryData.m_clipPlanes[planeCount++] = cullingParameters.GetCullingPlane(i); } } cullingParameters.cullingPlaneCount = planeCount; for (int i = 0; i < planeCount; ++i) { cullingParameters.SetCullingPlane(i, m_temporaryData.m_clipPlanes[i]); } #if DEBUG // To avoid the error: Assertion failed on expression: 'params.cullingPlaneCount == kPlaneFrustumNum' cullingParameters.cullingPlaneCount = 6; #endif cullingParameters.cullingOptions &= ~(CullingOptions.NeedsReflectionProbes | CullingOptions.ShadowCasters); CullingResults cullingResults = context.Cull(ref cullingParameters); m_cullingResults.Add(cam, cullingResults); return(true); }
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) { var camera = renderingData.cameraData.camera; SortingCriteria sortFlags; if (filterSettings.renderQueueRange == RenderQueueRange.opaque) { sortFlags = renderingData.cameraData.defaultOpaqueSortFlags; } else { sortFlags = SortingCriteria.CommonTransparent; } var drawSettings = CreateDrawingSettings(shaderTagIds, ref renderingData, sortFlags); CommandBuffer cmd = CommandBufferPool.Get("ClipSphere"); cmd.EnableShaderKeyword("CLIP_SPHERE_ON"); cmd.SetGlobalFloat("_ClipObjEdgeThickness", 0.01f); context.ExecuteCommandBuffer(cmd); cmd.Clear(); var baseCameraMatrix = camera.worldToCameraMatrix; foreach (var proxy in ProxyNode.Instances) { if (!proxy.isActiveAndEnabled) { continue; } if (proxy.State == ProxyNode.ProxyState.Minimized) { continue; } foreach (var mark in proxy.Marks) { if (mark == null || !mark.isActiveAndEnabled) { continue; } cmd.SetGlobalColor("_ClipObjEdgeColor", proxy.Color); cmd.SetGlobalVector("_ClipObjPosition", mark.transform.position); cmd.SetGlobalVector("_ClipObjScale", 0.5f * proxy.ProxyScaleFactor * mark.transform.localScale); var clipTransform = GetWarpTransform(proxy.transform, mark.transform); cmd.SetGlobalMatrix("_ClipTransform", clipTransform); cmd.SetGlobalMatrix("_ClipTransformInv", clipTransform.inverse); context.ExecuteCommandBuffer(cmd); OnProxyPass?.Invoke(this, GetProxyCameraPosition(proxy.transform, mark.transform)); // Stupid hack, because the other versions crashed or didn't work var scp = new ScriptableCullingParameters(); camera.TryGetCullingParameters(true, out scp); scp.cullingPlaneCount = 6; scp.SetCullingPlane(0, new Plane(new Vector3(1, 0, 0), mark.transform.position - new Vector3(1, 0, 0) * mark.transform.localScale.x)); scp.SetCullingPlane(1, new Plane(new Vector3(-1, 0, 0), mark.transform.position + new Vector3(1, 0, 0) * mark.transform.localScale.x)); scp.SetCullingPlane(2, new Plane(new Vector3(0, 1, 0), mark.transform.position - new Vector3(0, 1, 0) * mark.transform.localScale.y)); scp.SetCullingPlane(3, new Plane(new Vector3(0, -1, 0), mark.transform.position + new Vector3(0, 1, 0) * mark.transform.localScale.y)); scp.SetCullingPlane(4, new Plane(new Vector3(0, 0, 1), mark.transform.position - new Vector3(0, 0, 1) * mark.transform.localScale.z)); scp.SetCullingPlane(5, new Plane(new Vector3(0, 0, -1), mark.transform.position + new Vector3(0, 0, 1) * mark.transform.localScale.z)); var cullResults = context.Cull(ref scp); context.DrawRenderers(cullResults, ref drawSettings, ref filterSettings, ref renderStateBlock); } } cmd.SetGlobalMatrix("_ClipTransform", Matrix4x4.identity); cmd.DisableShaderKeyword("CLIP_SPHERE_ON"); context.ExecuteCommandBuffer(cmd); CommandBufferPool.Release(cmd); }
private bool StartCullingIfVisible(ScriptableRenderContext context, Camera cam) { if (m_frustumVertices == null) { return(false); } ScriptableCullingParameters cullingParameters = new ScriptableCullingParameters(); if (!cam.TryGetCullingParameters(IsStereoEnabled(cam), out cullingParameters)) { return(false); } if (m_temporaryData == null) { m_temporaryData = new TemporaryData(); } uint flags = 0xff; ulong flags64 = 0; for (int i = 0; i < 8; ++i) { Vector3 v = m_temporaryData.m_vertices[i] = transform.TransformPoint(m_frustumVertices[i]); uint f = 0; for (int j = 0; j < cullingParameters.cullingPlaneCount; ++j) { Plane plane = cullingParameters.GetCullingPlane(j); if (plane.GetDistanceToPoint(v) < 0) { f |= (1U << j); } } flags &= f; flags64 |= (((ulong)f) << (8 * i)); } if (flags != 0) { // projector is not visible from the camera return(false); } if (!m_requiresCullingResult) { return(true); } uint cameraPlanes = 0; int planeCount = 0; // -x flags = (uint)((flags64 >> 0) & (flags64 >> 8) & (flags64 >> 32) & (flags64 >> 40)) & 0xFF; if (flags == 0) { m_temporaryData.m_clipPlanes[planeCount++] = new Plane(m_temporaryData.m_vertices[0], m_temporaryData.m_vertices[1], m_temporaryData.m_vertices[4]); } else { cameraPlanes |= flags; } // +x flags = (uint)((flags64 >> 16) & (flags64 >> 24) & (flags64 >> 48) & (flags64 >> 56)) & 0xFF; if (flags == 0) { m_temporaryData.m_clipPlanes[planeCount++] = new Plane(m_temporaryData.m_vertices[3], m_temporaryData.m_vertices[2], m_temporaryData.m_vertices[7]); } else { cameraPlanes |= flags; } // -y flags = (uint)((flags64 >> 0) & (flags64 >> 16) & (flags64 >> 32) & (flags64 >> 48)) & 0xFF; if (flags == 0) { m_temporaryData.m_clipPlanes[planeCount++] = new Plane(m_temporaryData.m_vertices[2], m_temporaryData.m_vertices[0], m_temporaryData.m_vertices[6]); } else { cameraPlanes |= flags; } // +y flags = (uint)((flags64 >> 8) & (flags64 >> 24) & (flags64 >> 40) & (flags64 >> 56)) & 0xFF; if (flags == 0) { m_temporaryData.m_clipPlanes[planeCount++] = new Plane(m_temporaryData.m_vertices[1], m_temporaryData.m_vertices[3], m_temporaryData.m_vertices[5]); } else { cameraPlanes |= flags; } // near flags = (uint)((flags64 >> 0) & (flags64 >> 8) & (flags64 >> 16) & (flags64 >> 24)) & 0xFF; if (flags == 0) { m_temporaryData.m_clipPlanes[planeCount++] = new Plane(m_temporaryData.m_vertices[0], m_temporaryData.m_vertices[2], m_temporaryData.m_vertices[1]); } else { cameraPlanes |= flags; } // far flags = (uint)((flags64 >> 32) & (flags64 >> 40) & (flags64 >> 48) & (flags64 >> 56)) & 0xFF; if (flags == 0) { m_temporaryData.m_clipPlanes[planeCount++] = new Plane(m_temporaryData.m_vertices[4], m_temporaryData.m_vertices[5], m_temporaryData.m_vertices[6]); } else { cameraPlanes |= flags; } int maxPlaneCount = ScriptableCullingParameters.maximumCullingPlaneCount; Debug.Assert(cullingParameters.cullingPlaneCount == 6); const int farPlaneIndex = 5; uint addedCameraPlanes = 0; for (int i = 0; i < cullingParameters.cullingPlaneCount && planeCount < maxPlaneCount; ++i) { if ((cameraPlanes & (1U << i)) != 0) { addedCameraPlanes |= 1U << i; m_temporaryData.m_clipPlanes[planeCount++] = cullingParameters.GetCullingPlane(i); } } if (farPlaneIndex < planeCount) { // keep the camera far clip plane unchanged so that Layer Culling Distances can be handled correctly. if ((addedCameraPlanes & (1U << farPlaneIndex)) != 0) { // already have the camera far clip plane in m_temporaryData.m_clipPlanes[planeCount - 1] int currentFarPlaneIndex = planeCount - 1; // we need the following lines between #else and #endif if farPlaneIndex != 5 #if true Debug.Assert(farPlaneIndex == cullingParameters.cullingPlaneCount - 1); #else uint cameraPlaneFlags = addedCameraPlanes >> (farPlaneIndex + 1); while (cameraPlaneFlags != 0) { if ((cameraPlaneFlags & 1U) == 1U) { --currentFarPlaneIndex; } } #endif if (currentFarPlaneIndex != farPlaneIndex) { Plane farPlane = m_temporaryData.m_clipPlanes[currentFarPlaneIndex]; m_temporaryData.m_clipPlanes[currentFarPlaneIndex] = m_temporaryData.m_clipPlanes[farPlaneIndex]; m_temporaryData.m_clipPlanes[farPlaneIndex] = farPlane; } } else { // check if we really need to care abount Layer Culling Distances bool useLayerCullingDistances = false; Vector3 cameraForward = cam.transform.forward; float defaultCullingDistance = cam.farClipPlane + Vector3.Dot(cameraForward, cam.transform.position); defaultCullingDistance *= 0.9999f; float maxCullingDistance = Vector3.Dot(m_temporaryData.m_vertices[0], cameraForward); for (int i = 1; i < 8; ++i) { maxCullingDistance = Mathf.Max(maxCullingDistance, Vector3.Dot(m_temporaryData.m_vertices[i], cameraForward)); } maxCullingDistance = Mathf.Min(maxCullingDistance, defaultCullingDistance); int layerMask = cam.cullingMask & ~projector.ignoreLayers; for (int i = 0, endi = ScriptableCullingParameters.layerCount; i < endi && layerMask != 0; ++i, layerMask >>= 1) { if ((layerMask & 1) != 0) { float layerCullingDistance = cullingParameters.GetLayerCullingDistance(i); if (layerCullingDistance < maxCullingDistance) { useLayerCullingDistances = true; break; } } } if (useLayerCullingDistances) { // we need to care about Layer Culling Distances. so keep far plane unchanged // otherwise, projector might be drawn on invisible objects. if (planeCount < ScriptableCullingParameters.maximumCullingPlaneCount) { m_temporaryData.m_clipPlanes[planeCount++] = m_temporaryData.m_clipPlanes[farPlaneIndex]; } else { m_temporaryData.m_clipPlanes[planeCount - 1] = m_temporaryData.m_clipPlanes[farPlaneIndex]; } m_temporaryData.m_clipPlanes[farPlaneIndex] = cullingParameters.GetCullingPlane(farPlaneIndex); } else { // we don't need to care abount Layer Culling Distances, but need to SetCullingDistance // so that culling can work correctly. Vector3 farPlaneNormal = m_temporaryData.m_clipPlanes[farPlaneIndex].normal; float maxDistance = Vector3.Dot(farPlaneNormal, m_temporaryData.m_vertices[0]); for (int i = 1; i < 8; ++i) { maxDistance = Mathf.Min(maxDistance, Vector3.Dot(m_temporaryData.m_vertices[i], farPlaneNormal)); } maxDistance = -maxDistance; for (int i = 0, endi = ScriptableCullingParameters.layerCount; i < endi; ++i) { cullingParameters.SetLayerCullingDistance(i, maxDistance); } } } } #if DEBUG // make sure that farPlaneIndex is correct. Plane farClipPlane = cullingParameters.GetCullingPlane(farPlaneIndex); float farClipDistance = farClipPlane.GetDistanceToPoint(cam.transform.position); float error = Mathf.Abs(farClipDistance - cam.farClipPlane); float dirError = Vector3.Dot(farClipPlane.normal, cam.transform.forward) + 1.0f; for (int i = 0; i < 6; ++i) { if (i != farPlaneIndex) { Plane plane = cullingParameters.GetCullingPlane(i); Debug.Assert(error < Mathf.Abs(cam.farClipPlane - plane.GetDistanceToPoint(cam.transform.position))); Debug.Assert(dirError < Vector3.Dot(plane.normal, cam.transform.forward) + 1.0f); } } // To avoid the error: Assertion failed on expression: 'params.cullingPlaneCount == kPlaneFrustumNum' while (planeCount < 6) { m_temporaryData.m_clipPlanes[planeCount] = cullingParameters.GetCullingPlane(planeCount); ++planeCount; } planeCount = 6; #endif cullingParameters.cullingPlaneCount = planeCount; for (int i = 0; i < planeCount; ++i) { cullingParameters.SetCullingPlane(i, m_temporaryData.m_clipPlanes[i]); } cullingParameters.cullingOptions &= ~(CullingOptions.NeedsReflectionProbes | CullingOptions.ShadowCasters); if (terrainsToBeFilteredWithRenderFlags != null && 0 < terrainsToBeFilteredWithRenderFlags.Length) { if (m_originalTerrainRenderFlags == null || m_originalTerrainRenderFlags.Length < terrainsToBeFilteredWithRenderFlags.Length) { m_originalTerrainRenderFlags = new TerrainRenderFlags[terrainsToBeFilteredWithRenderFlags.Length]; } for (int i = 0; i < terrainsToBeFilteredWithRenderFlags.Length; ++i) { if (terrainsToBeFilteredWithRenderFlags[i] != null) { m_originalTerrainRenderFlags[i] = terrainsToBeFilteredWithRenderFlags[i].editorRenderFlags; terrainsToBeFilteredWithRenderFlags[i].editorRenderFlags &= terrainRenderFlags; } } } CullingResults cullingResults = context.Cull(ref cullingParameters); if (terrainsToBeFilteredWithRenderFlags != null && 0 < terrainsToBeFilteredWithRenderFlags.Length) { for (int i = 0; i < terrainsToBeFilteredWithRenderFlags.Length; ++i) { if (terrainsToBeFilteredWithRenderFlags[i] != null) { terrainsToBeFilteredWithRenderFlags[i].editorRenderFlags = m_originalTerrainRenderFlags[i]; } } } m_cullingResults.Add(cam, cullingResults); return(true); }