Search Unity

Question [Custom Pass] Any way to render object further than far clip plane of the camera?

Discussion in 'High Definition Render Pipeline' started by iamarugin, Mar 3, 2020.

  1. iamarugin

    iamarugin

    Joined:
    Dec 17, 2014
    Posts:
    883
    So I have a space game with Solar System in real scale in it. I need to render very far distant objects, like other planets of Solar System. For example, here I render the Moon using Draw Renderers Custom Pass with Before Rendering injection point:



    This works great because the Moon is relatively close to the Earth (300 000 km). But other planets is far far away. I tried to use different scale for them, like 1/60000, but then I have a problem that the Moon will render in front of Earth. I could not use second camera, because it is very expensive. So I need a way to render them in Custom Pass, even if they are further than far clip plane of the camera. Is this possible with Custom Pass? Could you please point me the direction, how can I solve this?
     
  2. Laex410

    Laex410

    Joined:
    Mar 18, 2015
    Posts:
    51
    I think it is not possible, the frustum culling should always occur, even when using a custom pass.

    One solution for your problem might be to render distant objects into the sky cubemap and display them that way.
     
  3. antoinel_unity

    antoinel_unity

    Unity Technologies

    Joined:
    Jan 7, 2019
    Posts:
    265
    Hey,

    Right now I don't think it's possible without hacking the camera matrices manually to change the camera position when rendering the custom pass (Which is what i do here: https://github.com/alelievr/HDRP-Custom-Passes#depth-capture but it only works in after post process right now).
    We're working on a more complete custom pass API which will allow you to render objects from any point of view in your scene during the rendering of your camera, I think this can solve your issue even though it may not be optimal because rendering thousands of these object will be costly.
     
  4. iamarugin

    iamarugin

    Joined:
    Dec 17, 2014
    Posts:
    883
    Thanks! This would be great solution. Also there will be less than 100 such objects, each of them is a simple sphere with the material.
     
  5. iamarugin

    iamarugin

    Joined:
    Dec 17, 2014
    Posts:
    883
    Hey @antoinel_unity I recently updated to Unity 2020.2 and hdrp 10.
    I saw new utility functions like CustomPassUtils.RenderFromCamera and saw FPSForeground sample. But I still quite not understand, how to render anything beyond the far clip plane of the first camera?
    My results so far looks like this:
    Here is the first camera (clip planes 0.1 - 15)
    upload_2021-2-11_21-4-12.png

    Here is my result with custom pass whuch is using camera with clip planes 15-55:
    upload_2021-2-11_21-4-44.png

    Here is how I want it to be:
    upload_2021-2-11_21-6-0.png

    Here is current code and it is wrong, but I don't understand where to start from:

    Code (CSharp):
    1. class DistantGeometryPass : CustomPass {
    2.     [SerializeField] Camera viewCam = null;
    3.     [SerializeField] LayerMask layerMask = 1;
    4.     [SerializeField] bool overrideDepthState = false;
    5.     [SerializeField] CompareFunction depthCompareFunction = CompareFunction.LessEqual;
    6.     [SerializeField] bool depthOnly = false;
    7.     protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd) {
    8.         // Setup code here
    9.     }
    10.  
    11.     protected override void Execute(CustomPassContext ctx) {
    12.         // Disable it for scene view because it's horrible
    13.         if (ctx.hdCamera.camera.cameraType == CameraType.SceneView)
    14.             return;
    15.  
    16.         var depthTestOverride = new RenderStateBlock(RenderStateMask.Depth) {
    17.             depthState = new DepthState(overrideDepthState, depthCompareFunction),
    18.         };
    19.         CustomPassUtils.RenderFromCamera(ctx, viewCam, ctx.cameraColorBuffer, ctx.cameraDepthBuffer, ClearFlag.None, layerMask, overrideRenderState: depthTestOverride);
    20.     }
    21.  
    22.     protected override void Cleanup() {
    23.         // Cleanup code
    24.     }
    25. }
     
  6. iamarugin

    iamarugin

    Joined:
    Dec 17, 2014
    Posts:
    883
    So, I've found this thread: https://forum.unity.com/threads/custompass-renderdepthfromcamera.1025812/
    And modified code like this:

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Rendering.HighDefinition;
    3. using UnityEngine.Rendering;
    4. using System.Reflection;
    5.  
    6. class DistantGeometryPass : CustomPass {
    7.     [SerializeField] Camera viewCam = null;
    8.     [SerializeField] LayerMask layerMask = 1;
    9.     [SerializeField] bool overrideDepthState = false;
    10.     [SerializeField] CompareFunction depthCompareFunction = CompareFunction.LessEqual;
    11.     [SerializeField] bool depthOnly = false;
    12.  
    13.     FieldInfo cullingResultField;
    14.  
    15.     protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd) {
    16.         cullingResultField = typeof(CustomPassContext).GetField(nameof(CustomPassContext.cullingResults));
    17.     }
    18.  
    19.     protected override void Execute(CustomPassContext ctx) {
    20.         // Disable it for scene view because it's horrible
    21.         if (ctx.hdCamera.camera.cameraType == CameraType.SceneView)
    22.             return;
    23.  
    24.         viewCam.TryGetCullingParameters(out var cullingParams);
    25.  
    26.         // Assign the custom culling result to the context
    27.         // so it'll be used for the following operations
    28.         cullingResultField.SetValueDirect(__makeref(ctx), ctx.renderContext.Cull(ref cullingParams));
    29.  
    30.         var depthTestOverride = new RenderStateBlock(RenderStateMask.Depth) {
    31.             depthState = new DepthState(overrideDepthState, depthCompareFunction),
    32.         };
    33.         CustomPassUtils.RenderFromCamera(ctx, viewCam, ctx.cameraColorBuffer, ctx.cameraDepthBuffer, ClearFlag.None, layerMask, overrideRenderState: depthTestOverride);
    34.     }
    35.  
    36.     protected override void Cleanup() {
    37.         // Cleanup code
    38.     }
    39. }
    The result looks like this:
    upload_2021-2-12_14-5-6.png

    Which is better, but still not the refernce.
     
  7. BOXOPHOBIC

    BOXOPHOBIC

    Joined:
    Jul 17, 2015
    Posts:
    509
    Maybe this could help: https://docs.unity3d.com/ScriptReference/Camera-layerCullDistances.html

    Cheers
     
  8. iamarugin

    iamarugin

    Joined:
    Dec 17, 2014
    Posts:
    883
    Thanks for advice. Unfortunately, it will not solve original problem with planets, because there are huge distances between them. And there will be depth buffer precision issues and other stuff like missing cascade shadows, if the camera has big far clip plane value and a small near clip plane at the same time.
     
  9. iamarugin

    iamarugin

    Joined:
    Dec 17, 2014
    Posts:
    883
    Ok, I think I solved it. Firstly, I render objects from other camera into custom color/depth using above pass. Then copy data from custom color buffer to camera buffer using second pass and LEqual ZTest. At the same time I am writing to camera depth buffer values just above far clip plane on that pixels.
    It will obviously work only for Before Rendering and After Opaque injection points.
    I don't know if it is the best solution, but at least it is working.

    Result:
    upload_2021-2-15_1-52-13.png

    Custom Pass Setup:

    upload_2021-2-15_1-52-40.png

    (As you can see there is no shadows on the second half of the image, but it is fine for me, becausue I am rendering very distant objects).
     
    Last edited: Feb 14, 2021
    tcn5150 likes this.
  10. tcn5150

    tcn5150

    Joined:
    Dec 1, 2012
    Posts:
    26
    This looks like a good solution to a similar situation I'm trying to address. I understand how the first pass copies the secondary camera's color/depth buffers to the respective custom buffers. But I'm a bit new to SRP/HDRP, and am stuck trying to figure out how to replicate the function of the second pass.

    I can't find any really useful examples of combining the custom color/depth buffers with an existing camera's buffers. Does anyone know any basic tutorials or docs that explain this?
     
  11. robot-ink

    robot-ink

    Joined:
    Jul 1, 2011
    Posts:
    18

    in your custom pass inspector, set buffer to custom

    then in the C# of that custom pass, set the target to cameraColorBuffer like this:

    Code (CSharp):
    1.  CoreUtils.SetRenderTarget(ctx.cmd, ctx.cameraColorBuffer);
    2.         CoreUtils.DrawFullScreen(ctx.cmd, customPassMaterial, ctx.propertyBlock, 0);
    then in your customPassMaterial, load the custom buffer in the shader:

    Code (CSharp):
    1. float4 bufferColor = LoadCustomColor(pcs);
    2. return bufferColor;
     
    tcn5150 likes this.
  12. tcn5150

    tcn5150

    Joined:
    Dec 1, 2012
    Posts:
    26