Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Skybox with local cubemap correction

Discussion in 'Shaders' started by simcovr, Jul 26, 2016.

  1. simcovr

    simcovr

    Joined:
    Jul 3, 2012
    Posts:
    43
    Hi!

    I'm looking a solution about a skybox shader that implement the perspective correction as reflection probes does for reflections.

    There is some topic about implementing this for reflections, (like this one http://www.gamasutra.com/blogs/Robe...lections_Based_on_Local_Cubemaps_in_Unity.php ) but I didn't find anything about using a skybox as background.

    What I'm looking for is something similar to what the CSR Racing2 guys did for their showroom
     
  2. Lost-in-the-Garden

    Lost-in-the-Garden

    Joined:
    Nov 18, 2015
    Posts:
    176
    The idea of a standard skybox is that it is infinitely far away and thus does not need perspective correction. Can you post an image of what you are trying to achieve instead?
     
  3. simcovr

    simcovr

    Joined:
    Jul 3, 2012
    Posts:
    43
    I know that a skybox is meant to be used with a "sky", but sometime you need to render an interior space or something that is near the camera than the infinity :p

    However, yesterday I found myself this solution:

    Code (csharp):
    1.  
    2. Shader "Skybox/Cubemap Parallax" {
    3. Properties {
    4.     _Tint ("Tint Color", Color) = (.5, .5, .5, .5)
    5.     [Gamma] _Exposure ("Exposure", Range(0, 8)) = 1.0
    6.     _Rotation ("Rotation", Range(0, 360)) = 0
    7.     [NoScaleOffset] _Tex ("Cubemap   (HDR)", Cube) = "grey" {}
    8.     _Pos ("Position", Vector) = (0,0,0,0)
    9.     _BBoxMin ("BoxSizeMin",Vector) = (1,1,1)
    10.     _BBoxMax ("BoxSizeMax",Vector) = (1,1,1)
    11. }
    12.  
    13. SubShader {
    14.     Tags { "Queue"="Background" "RenderType"="Background" "PreviewType"="Skybox" }
    15.     Cull Off ZWrite Off
    16.  
    17.     Pass {
    18.        
    19.         CGPROGRAM
    20.         #pragma vertex vert
    21.         #pragma fragment frag
    22.  
    23.         #include "UnityCG.cginc"
    24.  
    25.         samplerCUBE _Tex;
    26.         half4 _Tex_HDR;
    27.         half4 _Tint;
    28.         half _Exposure;
    29.         float _Rotation;
    30.         fixed3 _Pos;
    31.         fixed3 _BBoxMin;
    32.         fixed3 _BBoxMax;
    33.  
    34.         float3 LocalCorrect(float3 origVec, float3 bboxMin, float3 bboxMax,
    35.             float3 vertexPos, float3 cubemapPos)
    36.         {
    37.            // Find the ray intersection with box plane
    38.            float3 invOrigVec = float3(1.0,1.0,1.0)/origVec;
    39.            float3 intersecAtMaxPlane = (bboxMax - vertexPos) * invOrigVec;
    40.            float3 intersecAtMinPlane = (bboxMin - vertexPos) * invOrigVec;
    41.            // Get the largest intersection values
    42.            // (we are not intersted in negative values)
    43.            float3 largestIntersec = max(intersecAtMaxPlane, intersecAtMinPlane);
    44.            // Get the closest of all solutions
    45.            float Distance = min(min(largestIntersec.x, largestIntersec.y),
    46.                                 largestIntersec.z);
    47.            // Get the intersection position
    48.            float3 IntersectPositionWS = vertexPos + origVec * Distance;
    49.            // Get corrected vector
    50.            float3 localCorrectedVec = IntersectPositionWS - cubemapPos;
    51.            return localCorrectedVec;
    52.         }
    53.  
    54.         float4 RotateAroundYInDegrees (float4 vertex, float degrees)
    55.         {
    56.             float alpha = degrees * UNITY_PI / 180.0;
    57.             float sina, cosa;
    58.             sincos(alpha, sina, cosa);
    59.             float2x2 m = float2x2(cosa, -sina, sina, cosa);
    60.             return float4(mul(m, vertex.xz), vertex.yw).xzyw;
    61.         }
    62.        
    63.         struct appdata_t {
    64.             float4 vertex : POSITION;
    65.         };
    66.  
    67.         struct v2f {
    68.             float4 vertex : SV_POSITION;
    69.             float3 texcoord : TEXCOORD0;
    70.         };
    71.  
    72.         v2f vert (appdata_t v)
    73.         {
    74.             v2f o;
    75.             o.vertex = mul(UNITY_MATRIX_MVP, RotateAroundYInDegrees(v.vertex, _Rotation));
    76.             o.texcoord = v.vertex.xyz;
    77.             return o;
    78.         }
    79.  
    80.         fixed4 frag (v2f i) : SV_Target
    81.         {
    82.             float3 r = LocalCorrect(i.texcoord,_BBoxMin,_BBoxMax,_Pos,float3(0,0,0));
    83.             half4 tex = texCUBE (_Tex, r);
    84.  
    85.             half3 c = DecodeHDR (tex, _Tex_HDR);
    86.             c = c * _Tint.rgb * unity_ColorSpaceDouble.rgb;
    87.             c *= _Exposure;
    88.             return half4(c, 1);
    89.         }
    90.         ENDCG
    91.     }
    92. }    
    93.  
    94.  
    95. Fallback Off
    96.  
    97. }
    98.  
    and the C# part:
    Code (csharp):
    1.  
    2.  
    3. using UnityEngine;
    4. using System.Collections;
    5.  
    6. [ExecuteInEditMode]
    7. public class RelativePosition : MonoBehaviour {
    8.  
    9.  
    10.     public Transform cam;
    11.     Vector3 pos;
    12.     public Material skyboxMaterial;
    13.     public BoxCollider bCol;
    14.     Vector3 BBMin;
    15.     Vector3 BBMax;
    16.  
    17.     // Use this for initialization
    18.     void Start () {
    19.         if (cam == null) cam = Camera.main.transform;
    20.         skyboxMaterial.SetVector("_BBoxMin",-transform.localScale*0.5f);
    21.         skyboxMaterial.SetVector("_BBoxMax",transform.localScale*0.5f);
    22.     }
    23.    
    24.     // Update is called once per frame
    25.     void Update () {
    26.         GetBB();
    27.     }
    28.  
    29.     void GetBB()
    30.     {
    31.         pos = cam.position - bCol.center + transform.position;
    32.         BBMin = bCol.center - bCol.size*0.5f;
    33.         BBMax = bCol.center + bCol.size*0.5f;
    34.         skyboxMaterial.SetVector("_BBoxMin",BBMin);
    35.         skyboxMaterial.SetVector("_BBoxMax",BBMax);
    36.         skyboxMaterial.SetVector("_Pos",pos);
    37.     }
    38.  
    39.     void OnDrawGizmos()
    40.     {
    41.         Gizmos.color = new Color(1,1,0,0.25f);
    42.         Gizmos.DrawCube(bCol.center+ transform.position,bCol.size);
    43.         Gizmos.color = Color.yellow;
    44.         Gizmos.DrawWireCube(bCol.center+ transform.position,bCol.size);
    45.     }
    46. }
    47.  
    You need a gameobject with a BoxCollider in order to work.

    With this technique you can use prerendered backgrounds and match your scene camera position.

    Feel free to improve and share results