Skip to content

Instantly share code, notes, and snippets.

@brianasu
Last active August 31, 2022 13:07
Show Gist options
  • Save brianasu/141ecb4576891110df4bd0af503b3a3e to your computer and use it in GitHub Desktop.
Save brianasu/141ecb4576891110df4bd0af503b3a3e to your computer and use it in GitHub Desktop.
Hex tiling
Shader "Custom/hex tiling surface"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
_RotStrength ("Rot Strength", FLOAT) = 0
_FalloffContrast ("Falloff Contrast", FLOAT) = 0.6
_Exp ("Falloff Exp", FLOAT) = 7
_R ("Gain", Range(0, 1)) = 0.5
[KeywordEnum(Hex, Tiled, Debug)] _Mode ("Mode", FLOAT) = 0
}
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
#pragma shader_feature _MODE_HEX _MODE_TILED _MODE_DEBUG
sampler2D _MainTex;
struct Input
{
float2 uv_MainTex;
};
half _Glossiness;
half _Metallic;
fixed4 _Color;
// Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
// See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
// #pragma instancing_options assumeuniformscaling
UNITY_INSTANCING_BUFFER_START(Props)
// put more per-instance properties here
UNITY_INSTANCING_BUFFER_END(Props)
#define M_PI 3.14159265359
float _FalloffContrast = 0.6;
float _Exp = 7;
float _RotStrength = 0;
float _R = 0.5;
float _HexSize = 1;
float2 hash( float2 p)
{
float2 r = mul(float2x2(127.1, 311.7, 269.5, 183.3), p);
return frac( sin( r )*43758.5453 );
}
void TriangleGrid(out float w1, out float w2, out float w3,
out int2 vertex1, out int2 vertex2, out int2 vertex3,
float2 st)
{
// Scaling of the input
st *= 2 * sqrt(3);
// Skew input space into simplex triangle grid
const float2x2 gridToSkewedGrid = float2x2(1.0, -0.57735027, 0.0, 1.15470054);
float2 skewedCoord = mul(gridToSkewedGrid, st);
int2 baseId = int2( floor ( skewedCoord ));
float3 temp = float3( frac( skewedCoord ), 0);
temp.z = 1.0 - temp.x - temp.y;
float s = step(0.0, -temp.z);
float s2 = 2*s-1;
w1 = -temp.z * s2;
w2 = s - temp.y * s2;
w3 = s - temp.x * s2;
vertex1 = baseId + int2(s, s);
vertex2 = baseId + int2(s, 1-s);
vertex3 = baseId + int2(1-s, s);
}
float2 MakeCenST(int2 Vertex)
{
float2x2 invSkewMat = float2x2(1.0, 0.5, 0.0, 1.0/1.15470054);
return mul(invSkewMat, Vertex) / (2 * sqrt(3));
}
float2x2 LoadRot2x2(int2 idx, float rotStrength)
{
float angle = abs(idx.x*idx.y) + abs(idx.x+idx.y) + M_PI;
// remap to +/-pi
angle = fmod(angle, 2*M_PI);
if(angle<0) angle += 2*M_PI;
if(angle>M_PI) angle -= 2*M_PI;
angle *= rotStrength;
float cs = cos(angle), si = sin(angle);
return float2x2(cs, -si, si, cs);
}
float3 ProduceHexWeights(float3 W, int2 vertex1, int2 vertex2, int2 vertex3)
{
float3 res = 0.0;
int v1 = (vertex1.x-vertex1.y)%3;
if(v1<0) v1+=3;
int vh = v1<2 ? (v1+1) : 0;
int vl = v1>0 ? (v1-1) : 2;
int v2 = vertex1.x<vertex3.x ? vl : vh;
int v3 = vertex1.x<vertex3.x ? vh : vl;
res.x = v3==0 ? W.z : (v2==0 ? W.y : W.x);
res.y = v3==1 ? W.z : (v2==1 ? W.y : W.x);
res.z = v3==2 ? W.z : (v2==2 ? W.y : W.x);
return res;
}
float3 Gain3(float3 x, float r)
{
// increase contrast when r>0.5 and
// reduce contrast if less
float k = log(1-r) / log(0.5);
float3 s = 2 * step(0.5, x);
float3 m = 2 * (1 - s);
float3 res = 0.5 * s + 0.25 * m * pow(max(0.0, s + x*m), k);
return res.xyz / (res.x + res.y + res.z);
}
// Input:\ r increase contrast when r>0.5
// Output:\ color is the blended result
// Output:\ weights shows the weight of each hex tile
void hex2colTex(out float4 color, out float3 weights, sampler2D samp, float2 st, float rotStrength, float r)
{
float2 dSTdx = ddx(st), dSTdy = ddy(st);
// Get triangle info
float w1, w2, w3;
int2 vertex1, vertex2, vertex3;
TriangleGrid(w1, w2, w3, vertex1, vertex2, vertex3, st);
float2x2 rot1 = LoadRot2x2(vertex1, rotStrength);
float2x2 rot2 = LoadRot2x2(vertex2, rotStrength);
float2x2 rot3 = LoadRot2x2(vertex3, rotStrength);
// offset random rotation
// float2x2 rot1 = LoadRot2x2(vertex1, rotStrength + hash(vertex1));
// float2x2 rot2 = LoadRot2x2(vertex2, rotStrength + hash(vertex2));
// float2x2 rot3 = LoadRot2x2(vertex3, rotStrength + hash(vertex3));
float2 cen1 = MakeCenST(vertex1);
float2 cen2 = MakeCenST(vertex2);
float2 cen3 = MakeCenST(vertex3);
// offset UV position
float2 st1 = mul(st - cen1, rot1) + cen1 + hash(vertex1);
float2 st2 = mul(st - cen2, rot2) + cen2 + hash(vertex2);
float2 st3 = mul(st - cen3, rot3) + cen3 + hash(vertex3);
// float2 st1 = mul(st - cen1, rot1) + cen1;
// float2 st2 = mul(st - cen2, rot2) + cen2;
// float2 st3 = mul(st - cen3, rot3) + cen3;
// Fetch input
float4 c1 = tex2Dgrad(samp, st1, mul(dSTdx, rot1), mul(dSTdy, rot1));
float4 c2 = tex2Dgrad(samp, st2, mul(dSTdx, rot2), mul(dSTdy, rot2));
float4 c3 = tex2Dgrad(samp, st3, mul(dSTdx, rot3), mul(dSTdy, rot3));
// float4 c1 = tex2D(samp, st1);
// float4 c2 = tex2D(samp, st2);
// float4 c3 = tex2D(samp, st3);
// use luminance as weight
float3 Dw = float3(Luminance(c1.xyz), Luminance(c2.xyz), Luminance(c3.xyz));
Dw = lerp(1.0, Dw, _FalloffContrast); // 0.6
// Dw = 1; // don't weigh blend by lum. probably do height based blending here
float3 W = Dw * pow(float3(w1, w2, w3), _Exp); // 7
W /= (W.x + W.y + W.z);
if(r!=0.5)
W = Gain3(W, r);
color = W.x * c1 + W.y * c2 + W.z * c3;
weights = ProduceHexWeights(W.xyz, vertex1, vertex2, vertex3);
}
void surf (Input IN, inout SurfaceOutputStandard o)
{
// Albedo comes from a texture tinted by color
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
#if _MODE_HEX
float4 color;
float3 weights;
hex2colTex(color, weights, _MainTex, IN.uv_MainTex, _RotStrength, _R);
o.Albedo = color.rgb * _Color;
#endif
#if _MODE_DEBUG
float4 color;
float3 weights;
hex2colTex(color, weights, _MainTex, IN.uv_MainTex, _RotStrength, _R);
o.Albedo = weights;
#endif
// Metallic and smoothness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment