Skip to content

Instantly share code, notes, and snippets.

@rondreas
Last active September 13, 2018 14:41
Show Gist options
  • Save rondreas/412acca38b4ce3d9a25c3a57bac5dd87 to your computer and use it in GitHub Desktop.
Save rondreas/412acca38b4ce3d9a25c3a57bac5dd87 to your computer and use it in GitHub Desktop.
Attempting to get a grip on shaders after being inspired by: http://blog.camposanto.com/post/171934927979/hi-im-matt-wilde-an-old-man-from-the-north-of
using UnityEngine;
[ExecuteInEditMode]
public class SDFSphere : MonoBehaviour {
private void Update()
{
// Set a global value that we can use in our shader.
Shader.SetGlobalVector("_sdfSphere_position", this.transform.position);
}
}
using UnityEngine;
[ExecuteInEditMode]
public class SetVectorArray : MonoBehaviour {
public Transform[] spheres; // Get a public available array user can throw transforms into
private Vector4[] positions;
// Initializing in Awake instead of Start to also allow init in editor.
private void Awake()
{
positions = new Vector4[10];
}
void Update () {
SetPositions();
// Set the Global length of our Array, the Min is used to clamp the value down to the maximum allowed of 10 in our shader.
Shader.SetGlobalInt("_ArrayLength", spheres.Length);
Shader.SetGlobalVectorArray("_spheres", positions);
}
private void SetPositions ()
{
for (int i = 0; i < spheres.Length; i++)
{
if (spheres[i] == null) {
positions[i] = Vector4.positiveInfinity;
}
else
{
positions[i] = (Vector4)spheres[i].position;
}
}
}
private void OnValidate()
{
// Validate list isn't larger than 10 transforms
if (spheres.Length > 10)
{
// If that's the case - create a copy that only has 10 items, and set that back to the previous one.
var arr = new Transform[10];
for (int i = 0; i < 10; i++)
{
arr[i] = spheres[i];
}
spheres = arr;
}
}
private void SetRadii()
{
// TODO: Check for radius for each existing sphere in array. And set the w dimension for the vector to the radius
}
}
Shader "Custom/SignedDistanceField" {
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
sampler2D _Texture;
int _ArrayLength; // Also set as a global shader variable.
// We will store the world space position of up to 10 spheres, and their radius in the forth slot seeing unity will by
// default set it to zero after converting the position vec3 to a vec4 required in Shader.SetGlobalVectorArray.
float4 _spheres[10]; // Initalized as an array of size 10 seeing as this must be defined statically.
struct Input {
float2 uv_Texture;
float3 worldPos;
};
// Signed Distance Field Functions for most shapes
// http://iquilezles.org/www/articles/distfunctions/distfunctions.htm
float sdfSphere(float3 position, float radius) {
return length(position) - radius;
}
// polynomial smooth min (k = 0.1), higher k leads to a smoother blend.. I think.
// http://iquilezles.org/www/articles/smin/smin.htm
float sminCubic(float a, float b, float k)
{
float h = max(k - abs(a - b), 0.0);
return min(a, b) - h * h*h / (6.0*k*k);
}
void surf (Input IN, inout SurfaceOutputStandard o) {
float distance = 0;
// Probably not the most optimized way to handle the different scenarios of number of items.
switch (_ArrayLength) {
case 0: {
distance = 1;
} break;
case 1: {
distance = sdfSphere(float3(IN.worldPos - _spheres[0].xyz), 0.5f);
} break;
default: {
// We will first need to solve the first distance so we got something to work from.
distance = sdfSphere(float3(IN.worldPos - _spheres[0].xyz), 0.5f);
// Let's iterate through each sphere and combine their distance field relative to currect pixel I assume
for (int i = 1; i < _ArrayLength; i++) {
float d2 = sdfSphere(float3(IN.worldPos - _spheres[i].xyz), 0.5f);
// Regular Union of primitive distances.
// distance = min(distance, d2);
distance = sminCubic(distance, d2, 0.3);
}
} break;
}
// Moved into outputting with emissive instead of albedo, allowed a sharper and more 'intuitive' display
o.Emission = fixed3(distance, distance, distance);
o.Alpha = 1;
}
ENDCG
}
FallBack "Diffuse"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment