Created
July 6, 2020 00:07
-
-
Save bgolus/df9fd6dfb11312e68592afe373b153f8 to your computer and use it in GitHub Desktop.
A "single triangle" cube shader. Really a shader that orients a flat mesh towards the camera and uses a box ray intersection to draw a cube in the interior.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Shader "Unlit/CameraFacingBoxRaycast" | |
{ | |
Properties | |
{ | |
_Cube ("Texture", Cube) = "" {} | |
_MeshScale ("Mesh Scale", Float) = 1.0 | |
[Toggle] _DisableCameraFacing ("Disable Camera Facing", Float) = 0.0 | |
} | |
SubShader | |
{ | |
Tags { "RenderType"="Opaque" } | |
LOD 100 | |
Pass | |
{ | |
Cull Off | |
CGPROGRAM | |
#pragma vertex vert | |
#pragma fragment frag | |
#include "UnityCG.cginc" | |
struct appdata | |
{ | |
float4 vertex : POSITION; | |
}; | |
struct v2f | |
{ | |
float4 pos : SV_POSITION; | |
float3 ray : TEXCOORD0; | |
}; | |
samplerCUBE _Cube; | |
// scale up the mesh if it's too small to see the entire box | |
// for example, the default Unity quad is too small and needs a scale of ~1.8 | |
float _MeshScale; | |
// see what the raycasted box looks like without the mesh being oriented towards the camera | |
bool _DisableCameraFacing; | |
v2f vert (appdata v) | |
{ | |
v2f o; | |
// calculate a camera facing rotation matrix | |
float3 worldSpaceObjectPos = unity_ObjectToWorld._m03_m13_m23; | |
float3 viewOffset = _WorldSpaceCameraPos.xyz - worldSpaceObjectPos; | |
float3 forward = normalize(viewOffset); | |
float3 right = normalize(cross(forward, float3(0,1,0))); | |
float3 up = cross(right, forward); | |
float3x3 rotMat = float3x3(right, up, forward); | |
// get the max object scale to ensure camera facing mesh is scaled large enough to cover | |
float3 scale = float3( | |
length(unity_ObjectToWorld._m00_m10_m20), | |
length(unity_ObjectToWorld._m01_m11_m21), | |
length(unity_ObjectToWorld._m02_m12_m22) | |
); | |
float maxScale = max(abs(scale.x), max(abs(scale.y), abs(scale.z))); | |
// calculate world space position for mesh | |
float3 worldPos = mul(v.vertex.xyz * maxScale * _MeshScale + float3(0,0,maxScale * sqrt(0.5 * 0.5 * 3.0)), rotMat) + worldSpaceObjectPos; | |
// calculate and output object space view ray for interpolation | |
o.ray = mul(unity_WorldToObject, float4(worldPos - _WorldSpaceCameraPos.xyz, 0.0)); | |
o.pos = UnityWorldToClipPos(worldPos); | |
if (_DisableCameraFacing) | |
o.pos = UnityObjectToClipPos(v.vertex); | |
return o; | |
} | |
// from iq's excellent site | |
// https://www.iquilezles.org/www/articles/boxfunctions/boxfunctions.htm | |
float2 boxIntersection( in float3 ro, in float3 rd, in float3 rad, out float3 oN ) | |
{ | |
float3 m = 1.0/rd; | |
float3 n = m*ro; | |
float3 k = abs(m)*rad; | |
float3 t1 = -n - k; | |
float3 t2 = -n + k; | |
float tN = max( max( t1.x, t1.y ), t1.z ); | |
float tF = min( min( t2.x, t2.y ), t2.z ); | |
if( tN>tF || tF<0.0) return float2(-1.0, -1.0); // no intersection | |
oN = -sign(rd)*step(t1.yzx,t1.xyz)*step(t1.zxy,t1.xyz); | |
return float2( tN, tF ); | |
} | |
fixed4 frag (v2f i) : SV_Target | |
{ | |
// ray origin | |
float3 objectSpaceCameraPos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos.xyz, 1.0)).xyz; | |
// ray box intersection | |
float3 faceNormal; // unused | |
float2 rayHits = boxIntersection(objectSpaceCameraPos, i.ray, float3(.5,.5,.5), faceNormal); | |
// above function returns float2(-1,-1) if there's no intersection | |
clip(rayHits.x); | |
// calculate object space position from ray, front hit ray length, and ray origin | |
float3 boxPos = i.ray * rayHits.x + objectSpaceCameraPos; | |
// sample cube map using object space position | |
fixed4 col = texCUBE(_Cube, boxPos); | |
return col; | |
} | |
ENDCG | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment