Skip to content

Instantly share code, notes, and snippets.

@anlumo
Created April 8, 2017 01:32
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anlumo/18d944520a692ce1d83551895fbdf598 to your computer and use it in GitHub Desktop.
Save anlumo/18d944520a692ce1d83551895fbdf598 to your computer and use it in GitHub Desktop.
Implicit surface shader for Unity
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