Skip to content

Instantly share code, notes, and snippets.

@hakanai
Created May 28, 2020 07:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hakanai/d51fc9155ea5e591af595bce3e780cf8 to your computer and use it in GitHub Desktop.
Save hakanai/d51fc9155ea5e591af595bce3e780cf8 to your computer and use it in GitHub Desktop.
Shader code reuse prototype
#include "../Common/ELRaycastBase.cginc"
#include "../Common/ELRaycastFunctions.cginc"
////////////////////////////////////////////////////////////////////////////////
// Input / Output Data Structures
struct FragmentInput
{
// Stuff from ELRaycastBaseFragmentInput
float4 pos : SV_POSITION;
float4 color : COLOR;
float4 grabPos : TEXCOORD0;
float4 objectPos : TEXCOORD1;
float3 objectNormal : NORMAL;
float3 objectRayStart : TEXCOORD2;
float3 objectRayDir : TEXCOORD3;
// Our extra stuff
float2 texcoord : TEXCOORD4;
float2 texcoordMetallic : TEXCOORD5;
float2 texcoordNormal : TEXCOORD6;
float2 texcoordEmission : TEXCOORD7;
};
// Commenting out what other includes have provided for us - documented here for completeness.
// There may in fact be more which I have simply not named consistently.
// If you are reading this and know that this is the case, let me know and I'll rename my stuff.
//uniform sampler2D _MainTex;
//uniform float4 _MainTex_ST;
//uniform float4 _Color;
uniform sampler2D _MetallicTex;
uniform float4 _MetallicTex_ST;
uniform sampler2D _NormalMap;
uniform float4 _NormalMap_ST;
//uniform float _Metallic;
uniform float _Smoothness;
//uniform sampler2D _EmissionMap;
uniform float4 _EmissionMap_ST;
//uniform float3 _EmissionColor;
uniform float3 _BallAlbedo;
uniform float3 _BallEmission;
uniform float _BallMetallic;
uniform float _BallSmoothness;
////////////////////////////////////////////////////////////////////////////////
// Vertex Shader
FragmentInput Vertex(ELRaycastBaseVertexInput input)
{
FragmentInput output;
UNITY_INITIALIZE_OUTPUT(FragmentInput, output);
((ELRaycastBaseFragmentInput) output) = ELRaycastBaseVertex(input);
output.texcoord = TRANSFORM_TEX(input.texcoord, _MainTex);
output.texcoordMetallic = TRANSFORM_TEX(input.texcoord, _MetallicTex);
output.texcoordNormal = TRANSFORM_TEX(input.texcoord, _NormalMap);
output.texcoordEmission = TRANSFORM_TEX(input.texcoord, _EmissionMap);
return output;
}
////////////////////////////////////////////////////////////////////////////////
// Fragment Shader
FragmentInput myInput;
uint face;
/**
* Stashes custom stuff into global variables so that our overridden
* functions can get at them without having to find even trickier ways
* to pass them through multiple method calls.
*/
void StashGlobals(FragmentInput input)
{
myInput = input;
// Determine the face of the die which was hit by looking at the vertex colour.
// I coloured the model systematically so that this could be written programmatically.
// R=1, G=2, B=4, and add the values together.
// e.g., cyan is green + blue, so it would be face 6.
face = dot(input.color > 0.5 ? 1 : 0, uint3(1, 2, 4));
}
// Implementing function defined in `ELRaycastBase.cginc`
bool ELRaycast(ELRay ray, out float3 objectPos, out float3 objectNormal, out float material)
{
if (face == 7)
{
// Hits the frame immediately
objectPos = myInput.objectPos;
objectNormal = myInput.objectNormal;
material = 0.0;
return true;
}
static const float sphereRadius = 0.00125;
static const float k = 0.00275;
static const float sphereRadius2 = sphereRadius * sphereRadius;
static const float3 spherePositions[21] = {
// 1
float3(0.0, 0.0, 0.0),
// 2
float3(0.0, k, k), float3(0.0, -k, -k),
// 3
float3(0.0, 0.0, 0.0), float3(k, 0.0, -k), float3(-k, 0.0, k),
// 4
float3(k, 0.0, k), float3(k, 0.0, -k), float3(-k, 0.0, k), float3(-k, 0.0, -k),
// 5
float3(0.0, 0.0, 0.0), float3(0.0, k, k), float3(0.0, k, -k), float3(0.0, -k, k), float3(0.0, -k, -k),
// 6
float3(k, k, 0.0), float3(k, -k, 0.0), float3(0.0, k, 0.0), float3(0.0, -k, 0.0), float3(-k, k, 0.0), float3(-k, -k, 0.0),
};
// Index of first sphere in `spherePositions`
static const uint spherePositionOffsets[7] = {0, 0, 1, 3, 6, 10, 15};
uint offset = spherePositionOffsets[face];
float tBest = 100.0;
bool hit = false;
for (uint i = 0; i < face; i++)
{
float3 sphereCentre = spherePositions[offset + i];
if (ELSphereRayIntersect(sphereCentre, sphereRadius2, ray))
{
hit = true;
if (ray.t < tBest)
{
objectPos = ray.pos;
// XXX: Could try delaying this until the end of the loop?
objectNormal = normalize(objectPos - sphereCentre);
material = 1.0;
tBest = ray.t;
}
}
}
return hit;
}
// Implementing function defined in `ELRaycastBase.cginc`
void ELDecodeMaterial(ELRaycastBaseFragmentInput input, float material, inout SurfaceOutputStandard output)
{
if (material > 0.5)
{
// XXX: I want to texture this better too some day, but smooth balls are nice too. uwu
output.Albedo = _BallAlbedo;
output.Emission = _BallEmission;
output.Metallic = _BallMetallic;
output.Smoothness = _BallSmoothness;
output.Alpha = 1.0;
}
else
{
float4 albedo = tex2D(_MainTex, myInput.texcoord) * _Color;
output.Albedo = albedo.rgb;
output.Alpha = albedo.a;
float4 metal = tex2D(_MetallicTex, myInput.texcoordMetallic);
output.Metallic = metal.r * _Metallic;
output.Smoothness = metal.a * _Smoothness;
output.Normal = UnpackNormal(tex2D(_NormalMap, myInput.texcoordNormal));
output.Emission = tex2D(_EmissionMap, myInput.texcoordEmission) * _EmissionColor;
}
}
/**
* Fragment shader for forward / forward add.
*
* @param input the fragment input structure.
* @return the fragment output structure.
*/
ELRaycastBaseFragmentOutput Fragment(FragmentInput input)
{
StashGlobals(input);
return ELRaycastFragment((ELRaycastBaseFragmentInput) input);
}
/**
* Fragment shader for shadow caster.
*
* @param input the fragment input structure.
* @return the shadow caster fragment result.
*/
float4 ShadowCasterFragment(FragmentInput input) : SV_Target
{
StashGlobals(input);
return ELRaycastShadowCasterFragment((ELRaycastBaseFragmentInput) input);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment