Last active
August 31, 2022 13:07
-
-
Save brianasu/141ecb4576891110df4bd0af503b3a3e to your computer and use it in GitHub Desktop.
Hex tiling
This file contains 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/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