Created
April 8, 2017 01:32
-
-
Save anlumo/18d944520a692ce1d83551895fbdf598 to your computer and use it in GitHub Desktop.
Implicit surface shader for Unity
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 "Own/Volumetric" { | |
Properties { | |
_Radius ("Radius", Float) = 1.0 | |
_Center ("Center", Vector) = (0.0, 0.0, 0.0, 0.0) | |
_Color ("Color", Color) = (1.0, 0.0, 0.0, 1.0) | |
_SpecularPower ("Specular Power", Float) = 20.0 | |
_Gloss ("Gloss", Float) = 5.0 | |
} | |
SubShader { | |
Tags { "RenderType"="Opaque" } | |
LOD 100 | |
Pass { | |
CGPROGRAM | |
#pragma vertex vert | |
#pragma fragment frag | |
#include "UnityCG.cginc" | |
#include "Lighting.cginc" | |
struct appdata { | |
float4 vertex : POSITION; | |
}; | |
struct v2f { | |
float4 vertex : SV_POSITION; | |
float3 wPos : TEXCOORD1; // World position | |
}; | |
float _Radius; | |
float4 _Center; | |
float4 _Color; | |
float _SpecularPower; | |
float _Gloss; | |
const float PI = 3.1415926; | |
v2f vert (appdata v) { | |
v2f o; | |
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); | |
o.wPos = mul(unity_ObjectToWorld, v.vertex).xyz; | |
return o; | |
} | |
float rand(float3 co) { | |
return frac(sin(dot(co.xyz, float3(12.9898, 78.233, 45.5432))) * 43758.5453); | |
} | |
float sdf_sphere(float3 p, float3 c, float r) { | |
return distance(p, c) - r; | |
} | |
float sdf_box(float3 p, float3 c, float3 s) { | |
float x = max(p.x - c.x - float3(s.x / 2., 0, 0), | |
c.x - p.x - float3(s.x / 2., 0, 0) | |
); | |
float y = max(p.y - c.y - float3(s.y / 2., 0, 0), | |
c.y - p.y - float3(s.y / 2., 0, 0) | |
); | |
float z = max(p.z - c.z - float3(s.z / 2., 0, 0), | |
c.z - p.z - float3(s.z / 2., 0, 0) | |
); | |
return max(max(x, y), z); | |
} | |
float sdf_smin(float a, float b, float k = 32) | |
{ | |
float res = exp(-k*a) + exp(-k*b); | |
return -log(max(0.0001, res)) / k; | |
} | |
float sdf_blend(float d1, float d2, float a) { | |
return a * d1 + (1 - a) * d2; | |
} | |
float map(float3 p) { | |
return max(sdf_smin( | |
sdf_sphere(p, -float3 (1.5, 0, 0), 2), // left sphere | |
sdf_sphere(p, +float3 (1.5, 0, 0), 2) // right sphere | |
, 8), sdf_blend(sdf_sphere(p, 0, 2), sdf_box(p, 0, 2), 0.5)); | |
} | |
float3 normal(float3 p) { | |
const float eps = 0.001; | |
return normalize(float3 | |
(map(p + float3(eps, 0, 0)) - map(p - float3(eps, 0, 0)), | |
map(p + float3(0, eps, 0)) - map(p - float3(0, eps, 0)), | |
map(p + float3(0, 0, eps)) - map(p - float3(0, 0, eps)) | |
) | |
); | |
} | |
fixed4 simpleLambert(fixed3 normal, float3 viewDirection) { | |
//return fixed4(normal.x, normal.y, normal.z, 1.0); | |
fixed3 lightDir = _WorldSpaceLightPos0.xyz; | |
fixed3 lightCol = _LightColor0.rgb; | |
fixed NdotL = max(dot(normal, lightDir), 0); | |
fixed4 c; | |
// Specular | |
fixed3 h = (lightDir - viewDirection) / 2.; | |
fixed s = pow(dot(normal, h), _SpecularPower) * _Gloss; | |
c.rgb = _Color * lightCol * NdotL + s; | |
c.a = 1; | |
return c; | |
} | |
fixed4 renderSurface(float3 p, float3 viewDirection) { | |
return simpleLambert(normal(p), viewDirection); | |
} | |
#define STEPS 256 | |
#define MIN_DISTANCE 0.001 | |
fixed4 raymarch(float3 position, float3 direction) { | |
for (int i = 0; i < STEPS; i++) { | |
float distance = map(position); | |
if (distance < MIN_DISTANCE) { | |
return renderSurface(position, direction); | |
} | |
position += distance * direction; | |
} | |
discard; | |
return fixed4(1, 1, 1, 1); | |
} | |
fixed4 frag (v2f i) : SV_Target { | |
float3 viewDirection = normalize(i.wPos - _WorldSpaceCameraPos); | |
return raymarch(i.wPos, viewDirection); | |
} | |
ENDCG | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment