I have an cloud sphere that’s very far from the Player. I want to make the camera to render the clouds without increasing the near clipping planes to improve performance and to avoid the player to see to much in the horizon. Just 1000-2000 units. I want to tell camera to render the clouds that are 7000 units far, but to avoid rendering other objects that are more than 2000 far.
P.S: I would like to not use the 2 cameras method(1 camera with 7000 clipping plane that render only the clouds layer and 1 camera with 2000 clipping plane that render everything else)
You could try using a custom procedural skybox shader.
How to write it depends on which version and rendering pipeline you’re using.
Additionally you could attach a SMALL 1 unit sphere directly to the camera, and render it with depth write disabled, in Background queue. It will look as if it was infinitely far away. Just because an object looks like it is far away, that doesn’t mean it is actually there.
Once again, this is for “built-in renderer”
Basically, your clouds do not need to be up to scale, it can be just smoke and mirrors around the camera.
From the docs it sounds like this can be used to reduce culling distance for layers, but not to increase it.
From a pure math perspective you can get the desired result by setting the far clip to just larger than the sky sphere’s distance and reducing the layer clip distances for everything else. However, when you take the depth buffer into account that could give you issues, as you’re reducing the depth precision available to the majority of the stuff you’re rendering. That may or may not matter, depending on what you’re doing.
The first solution that comes to my mind, for conceptual simplicity, is to simply have two cameras with matching settings and transforms, except for the clear flags, clip planes and render order. Render your far camera first with clear flags set to “Skybox”, then your normal camera with your clear flags set to “depth only”. It does seem overkill to have a whole extra camera to render just one thing, though.
The second solution that comes to my mind has already been explained by @neginfinity . Tweak the shader and render order within a single camera so that your skybox is rendered first without z-write, at any scale that makes it visible. Then render the rest of your scene, which will ignore it because it’s not in the z-buffer. I’m no rendering expert but this strikes me as far more efficient.
If you look into how skyboxes are generally rendered in Unity there might be options there. Replace the skybox material with one that gives the behaviour you want, then assign that to your cameras.
Yes, but you just approach it from the other direction. Set your camera to 7000, then use layerCullDistances to reduce all layers to 2000 except for the cloud layer.
I was just thinking about this problem.
I’m using HDRP.
I have got some mountains very far away (3d models), far beyond my camera clipping plane that I would not like to change.
I’m bumping since somebody might know the “official” way to do it.
Depends on what you’re actually doing. You can put them on a cube map and render them with the sky or you can make impostors out of them and render them at the far clipping plane. For example. You can’t render 3D objects beyond your far clipping plane, obviously.
This is life-sized earth and moon. It is done by using camera stacking and progressively smaller scenes set on different layers. So, you’d have a visual layers with objects that are nearby, a visual layer with surroundings scaled down by factor of, say 1000, one more layer with surroundings scaled by factor of 1000000 and so on. This can be stored in the same scene, although managing it all in the same spot is messy.
The cameras woudl first render the largest scene, then smaller scene on top of it, with the “nearby objects” scene being rendered last.
I’ve created a tiny tool, that change every Layer with a default Far value (the maximum is the default far of the camera)
Planning to add it to the asset store, for anyone wanting it for free before I release it, ping me
Just be aware this scenario will give you precision issues if there is a large difference between your depths. Might be worth testing some extreme scenarios so that you can provide accurate details of the precision limits to your buyers.
I have had this problem too with a sky dome and custom shader to make clouds.
I used this code o.pos.z = o.pos.w - 1.0e-6f;, which rendered the clouds in front of all the other geometry in the scene, so then I used "Queue" = "Geometry-1" to render before any scene objects.
Note this is extracted code from a custom sky / cloud shader, so I haven’t tested it.
Shader "Custom/NoSkyClippingShader" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
// your properties here
}
SubShader {
// we want to render the clouds always before the geometry
Tags { "Queue" = "Geometry-1" "RenderType"="Transparent" }
cull front // we only want to render the inside of the dome
zwrite off
Blend SrcAlpha OneMinusSrcAlpha
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f {
fixed4 pos : SV_POSITION;
fixed4 uv0 : TEXCOORD0;
fixed4 uv1 : TEXCOORD1;
};
v2f vert (appdata v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
// set the z pos of every vert of the dome
o.pos.z = o.pos.w - 1.0e-6f;
// rest of your shader code here
}
fixed4 frag (v2f i) : SV_Target { return tex2D(_MainTex, i.uv); }
ENDCG
I made this version with custom editor based on usernameHed’s answer.
Notice that in order for this to behave correctly, you need to set your camera’s far clipping planes to something like 1000. Here, I have set all layers’ clipping distance to 80. If you wish to always render far objects like sky domes, set their distances to 1000 or some higher values. Edit: Added “#if UNITY_EDITOR” and “#endif”.
using System;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace UnityEssentials.CameraPerLayerFarDist
{
/// <summary>
/// * Limits clipping plane distance for each layer
/// </summary>
[ExecuteInEditMode]
public class PerLayerFarDistance : MonoBehaviour
{
[SerializeField]
private Camera _camera;
[SerializeField]
private LayerWithDistance[] _settings = new LayerWithDistance[32];
[Serializable]
public struct LayerWithDistance
{
public LayerMask layer;
public float distance;
}
public void OnValidate()
{
if (_settings.Length != 32)
GetLayers();
}
private void Awake()
{
SetCameraCullingMode();
}
private void SetCameraCullingMode()
{
_camera.layerCullSpherical = false;
_camera.layerCullDistances =
_settings.ToList().Select(x => x.distance).ToArray();;
}
[ContextMenu("GetLayers")]
public void GetLayers()
{
for (int i = 0; i <= 31; i++)
{
_settings[i].layer = 1 << i;
// * Set far clipping plane distance for layer to 80
_settings[i].distance = 80f;
}
}
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(LayerWithDistance))]
public class LayerWithDistanceDrawerUIE: PropertyDrawer
{
public override void OnGUI(Rect position,
SerializedProperty property,
GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
position = EditorGUI.PrefixLabel(position,
GUIUtility
.GetControlID(FocusType.Passive),
label);
var indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
Rect layerRect = new(position.x,
position.y,
120,
position.height);
Rect distanceRect = new(position.x + 125,
position.y, 30,
position.height);
EditorGUI.PropertyField(layerRect,
property
.FindPropertyRelative("layer"),
GUIContent.none);
EditorGUI.PropertyField(distanceRect,
property
.FindPropertyRelative("distance"),
GUIContent.none);
EditorGUI.indentLevel = indent;
EditorGUI.EndProperty();
}
}
#endif
}
}