Last active
September 13, 2018 14:41
-
-
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
This file contains hidden or 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
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); | |
} | |
} |
This file contains hidden or 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
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 | |
} | |
} |
This file contains hidden or 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 "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