335 lines
12 KiB
HLSL
335 lines
12 KiB
HLSL
// Used Unitys "Standard geometry shader example" as a base to get unitys standard lighting and stuff w/ a custom geometry stage since surface shaders dont allow this
|
|
//and when writing from the ground up lighting has to be done by hand
|
|
// https://github.com/keijiro/StandardGeometryShader
|
|
|
|
#include "UnityCG.cginc"
|
|
#include "UnityGBuffer.cginc"
|
|
#include "UnityStandardUtils.cginc"
|
|
|
|
// Cube map shadow caster; Used to render point light shadows on platforms
|
|
// that lacks depth cube map support.
|
|
#if defined(SHADOWS_CUBE) && !defined(SHADOWS_CUBE_IN_DEPTH_TEX)
|
|
#define PASS_CUBE_SHADOWCASTER
|
|
#endif
|
|
|
|
// Shader uniforms
|
|
half4 _Color;
|
|
sampler2D _MainTex;
|
|
float4 _MainTex_ST;
|
|
|
|
half _Glossiness;
|
|
half _Metallic;
|
|
|
|
sampler2D _BumpMap;
|
|
float _BumpScale;
|
|
|
|
sampler2D _OcclusionMap;
|
|
float _OcclusionStrength;
|
|
|
|
float _LocalTime;
|
|
|
|
// Vertex input attributes
|
|
struct Attributes {
|
|
float4 position : POSITION;
|
|
float3 normal : NORMAL;
|
|
float4 tangent : TANGENT;
|
|
float2 texcoord : TEXCOORD;
|
|
};
|
|
|
|
// Fragment varyings
|
|
struct Varyings {
|
|
float4 position : SV_POSITION;
|
|
|
|
#if defined(PASS_CUBE_SHADOWCASTER)
|
|
// Cube map shadow caster pass
|
|
float3 shadow : TEXCOORD0;
|
|
|
|
#elif defined(UNITY_PASS_SHADOWCASTER)
|
|
// Default shadow caster pass
|
|
|
|
#else
|
|
// GBuffer construction pass
|
|
float3 normal : NORMAL;
|
|
float2 texcoord : TEXCOORD0;
|
|
float4 tspace0 : TEXCOORD1;
|
|
float4 tspace1 : TEXCOORD2;
|
|
float4 tspace2 : TEXCOORD3;
|
|
half3 ambient : TEXCOORD4;
|
|
|
|
#endif
|
|
};
|
|
|
|
//
|
|
// Vertex stage
|
|
//
|
|
|
|
Attributes Vertex(Attributes input) {
|
|
// Only do object space to world space transform.
|
|
input.position = mul(unity_ObjectToWorld, input.position);
|
|
input.normal = UnityObjectToWorldNormal(input.normal);
|
|
input.tangent.xyz = UnityObjectToWorldDir(input.tangent.xyz);
|
|
input.texcoord = TRANSFORM_TEX(input.texcoord, _MainTex);
|
|
return input;
|
|
}
|
|
|
|
//
|
|
// Geometry stage
|
|
//
|
|
|
|
Varyings VertexOutput(float3 wpos, half3 wnrm, half4 wtan, float2 uv) {
|
|
Varyings o;
|
|
#if defined(PASS_CUBE_SHADOWCASTER)
|
|
// Cube map shadow caster pass: Transfer the shadow vector.
|
|
o.position = UnityWorldToClipPos(float4(wpos, 1));
|
|
o.shadow = wpos - _LightPositionRange.xyz;
|
|
#elif defined(UNITY_PASS_SHADOWCASTER)
|
|
// Default shadow caster pass: Apply the shadow bias.
|
|
float scos = dot(wnrm, normalize(UnityWorldSpaceLightDir(wpos)));
|
|
wpos -= wnrm * unity_LightShadowBias.z * sqrt(1 - scos * scos);
|
|
o.position = UnityApplyLinearShadowBias(UnityWorldToClipPos(float4(wpos, 1)));
|
|
#else
|
|
// GBuffer construction pass
|
|
half3 bi = cross(wnrm, wtan) * wtan.w * unity_WorldTransformParams.w;
|
|
o.position = UnityWorldToClipPos(float4(wpos, 1));
|
|
o.normal = wnrm;
|
|
o.texcoord = uv;
|
|
o.tspace0 = float4(wtan.x, bi.x, wnrm.x, wpos.x);
|
|
o.tspace1 = float4(wtan.y, bi.y, wnrm.y, wpos.y);
|
|
o.tspace2 = float4(wtan.z, bi.z, wnrm.z, wpos.z);
|
|
o.ambient = ShadeSHPerVertex(wnrm, 0);
|
|
#endif
|
|
return o;
|
|
}
|
|
|
|
float3 ConstructNormal(float3 v1, float3 v2, float3 v3) {
|
|
return normalize(cross(v2 - v1, v3 - v1));
|
|
}
|
|
|
|
float rand(float3 co){
|
|
return frac(sin(dot(co.xyz, float3(12.9898, 78.233, 53.539))) * 43758.5453);
|
|
}
|
|
float3x3 AngleAxis3x3(float angle, float3 axis){
|
|
float c, s;
|
|
sincos(angle, s, c);
|
|
float t = 1 - c;
|
|
float x = axis.x;
|
|
float y = axis.y;
|
|
float z = axis.z;
|
|
return float3x3(
|
|
t * x * x + c, t * x * y - s * z, t * x * z + s * y,
|
|
t * x * y + s * z, t * y * y + c, t * y * z - s * x,
|
|
t * x * z - s * y, t * y * z + s * x, t * z * z + c
|
|
);
|
|
}
|
|
|
|
float _BladeHeight, _BladeHeightRandom, _BladeWidth, _BladeWidthRandom, _BendRotationRandom;
|
|
int _Test;
|
|
|
|
[instance(5)]
|
|
[maxvertexcount(42)]
|
|
void Geometry( triangle Attributes input[3], uint pid : SV_PrimitiveID, inout TriangleStream<Varyings> outStream, uint InstanceID : SV_GSInstanceID) {
|
|
//Vertex inputs;
|
|
|
|
//
|
|
//float2 uv0 = input[0].texcoord;
|
|
//float2 uv1 = input[1].texcoord;
|
|
//float2 uv2 = input[2].texcoord;
|
|
|
|
float3 pos = input[0].position;
|
|
float3 vNormal = input[0].normal;
|
|
float4 vTangent = input[0].tangent;
|
|
float3 vBinormal = cross (vNormal,vTangent)*vTangent.w;
|
|
|
|
float height = (rand(pos.zyx) * 2 - 1) * _BladeHeightRandom + _BladeHeight;
|
|
float width = (rand(pos.xzy) * 2 - 1) * _BladeWidthRandom + _BladeWidth;
|
|
|
|
float3x3 tangentToLocal = float3x3(
|
|
vTangent.x, vBinormal.x, vNormal.x,
|
|
vTangent.y, vBinormal.y, vNormal.y,
|
|
vTangent.z, vBinormal.z, vNormal.z
|
|
);
|
|
|
|
|
|
|
|
//TODO add geometry instancing
|
|
//TODO create nodes based on world pos
|
|
//TODO find out if need to remember geometry instancing index to create mor tris
|
|
//TODO keep track of how many verts used
|
|
|
|
//Add node
|
|
//float3 wn = ConstructNormal(wp3, wp4, wp5);
|
|
//outStream.Append(VertexOutput(pos + mul(transformationMatrix, float3( width, 0, 0 )),half3(0,1,0),float4(1,1,0,0), float2(1.25,0) ));
|
|
//outStream.Append(VertexOutput(pos + mul(transformationMatrix, float3(-width, 0, 0 )),half3(0,1,0),float4(1,1,0,0), float2(-0.25,0) ));
|
|
//outStream.Append(VertexOutput(pos + mul(transformationMatrix, float3( 0 , 0, height)),half3(0,1,0),float4(1,1,0,0), float2(0.5,1.5) ));
|
|
//outStream.RestartStrip();
|
|
//outStream.Append(VertexOutput(pos + mul(transformationMatrix, float3(0, width, 0 )),half3(0,1,0),float4(1,1,0,0), float2(1.25,0) ));
|
|
//outStream.Append(VertexOutput(pos + mul(transformationMatrix, float3(0, -width, 0 )),half3(0,1,0),float4(1,1,0,0), float2(-0.25,0) ));
|
|
//outStream.Append(VertexOutput(pos + mul(transformationMatrix, float3(0, 0 , height)),half3(0,1,0),float4(1,1,0,0), float2(0.5,1.5) ));
|
|
//outStream.RestartStrip();
|
|
|
|
//Do triangle
|
|
float3 wp0 = input[0].position.xyz;
|
|
float3 wp1 = input[1].position.xyz;
|
|
float3 wp2 = input[2].position.xyz;
|
|
//1. Order points
|
|
float3 p1 = max(wp0,max(wp1,wp2));
|
|
float3 p2;
|
|
float3 p3 = min(wp0,min(wp1,wp2));
|
|
if (all(p1 >= wp0) && all(p3 <= wp0)) {p2 = wp0;}
|
|
else if(all(p1 >= wp1) && all(p3 <= wp1)) {p2 = wp1;}
|
|
else if(all(p1 >= wp2) && all(p3 <= wp2)) {p2 = wp2;}
|
|
//2. Get directions
|
|
float3 vec1 = p3-p1;
|
|
float3 vec2 = p2-p1;
|
|
float3 vec3 = p3-p2;
|
|
float dir1Len = length(vec1);
|
|
float dir2Len = length(vec2);
|
|
float dir3Len = length(vec3);
|
|
float3 dir1 = vec1 / dir1Len;
|
|
float3 dir2 = vec2 / dir2Len;
|
|
float3 dir3 = vec3 / dir3Len;
|
|
//3. Define values
|
|
float unit = 0.5;
|
|
float3 step1 = dir1 * unit;
|
|
float3 step2 = dir2 * unit * abs(vec2.x/vec1.x);
|
|
float3 step3 = dir3 * unit;
|
|
float3 current1 = p1;
|
|
float3 current2 = p1;
|
|
//4. loop
|
|
int unitsToX = abs(floor(vec1.x/unit));
|
|
for (int i = 0; i < unitsToX; ++i) {
|
|
current1 += step1;
|
|
current2 += step2;
|
|
int unitsToZ = abs(floor((current1.z-current2.z)/unit));
|
|
//1. create start and ends
|
|
float3 current = floor(current1);
|
|
for (int j = 0; j < unitsToZ; ++j) {//loop and create nodes
|
|
|
|
float3x3 facingRotationMatrix = AngleAxis3x3(rand(pos) * UNITY_TWO_PI, float3(0, 0, 1));
|
|
float3x3 bendRotationMatrix = AngleAxis3x3(rand(pos.zzx) * _BendRotationRandom * UNITY_PI * 0.5, float3(-1, 0, 0));
|
|
float3x3 transformationMatrix = mul(mul(tangentToLocal, facingRotationMatrix),bendRotationMatrix);
|
|
|
|
float k = i+j+1;
|
|
//-Creat node- START
|
|
outStream.Append(VertexOutput(current + mul(transformationMatrix, float3( width, 0, 0 )),half3(0,1,0),float4(1,1,0,0), float2(1.25,0) ));
|
|
outStream.Append(VertexOutput(current + mul(transformationMatrix, float3(-width, 0, 0 )),half3(0,1,0),float4(1,1,0,0), float2(-0.25,0) ));
|
|
outStream.Append(VertexOutput(current + mul(transformationMatrix, float3( 0 , 0, height*k)),half3(0,1,0),float4(1,1,0,0), float2(0.5,1.5) ));
|
|
outStream.RestartStrip();
|
|
outStream.Append(VertexOutput(current + mul(transformationMatrix, float3(0, width, 0 )),half3(0,1,0),float4(1,1,0,0), float2(1.25,0) ));
|
|
outStream.Append(VertexOutput(current + mul(transformationMatrix, float3(0, -width, 0 )),half3(0,1,0),float4(1,1,0,0), float2(-0.25,0) ));
|
|
outStream.Append(VertexOutput(current + mul(transformationMatrix, float3(0, 0 , height*k)),half3(0,1,0),float4(1,1,0,0), float2(0.5,1.5) ));
|
|
outStream.RestartStrip();
|
|
//-Create node- END
|
|
|
|
current.z += unit;
|
|
}
|
|
}
|
|
|
|
|
|
// Extrusion amount
|
|
//float ext = saturate(0.4 - cos(_LocalTime * UNITY_PI * 2) * 0.41);
|
|
//ext *= 1 + 0.3 * sin(pid * 832.37843 + _LocalTime * 88.76);
|
|
//
|
|
//// Extrusion points
|
|
//float3 offs = ConstructNormal(wp0, wp1, wp2) * ext;
|
|
//float3 wp3 = wp0 + offs;
|
|
//float3 wp4 = wp1 + offs;
|
|
//float3 wp5 = wp2 + offs;
|
|
//
|
|
//// Cap triangle
|
|
//float3 wn = ConstructNormal(wp3, wp4, wp5);
|
|
//float np = saturate(ext * 10);
|
|
//float3 wn0 = lerp(input[0].normal, wn, np);
|
|
//float3 wn1 = lerp(input[1].normal, wn, np);
|
|
//float3 wn2 = lerp(input[2].normal, wn, np);
|
|
//outStream.Append(VertexOutput(wp3, wn0, input[0].tangent, uv0));
|
|
//outStream.Append(VertexOutput(wp4, wn1, input[1].tangent, uv1));
|
|
//outStream.Append(VertexOutput(wp5, wn2, input[2].tangent, uv2));
|
|
//outStream.RestartStrip();
|
|
//
|
|
//// Side faces
|
|
//float4 wt = float4(normalize(wp3 - wp0), 1); // world space tangent
|
|
//wn = ConstructNormal(wp3, wp0, wp4);
|
|
//outStream.Append(VertexOutput(wp3, wn, wt, uv0));
|
|
//outStream.Append(VertexOutput(wp0, wn, wt, uv0));
|
|
//outStream.Append(VertexOutput(wp4, wn, wt, uv1));
|
|
//outStream.Append(VertexOutput(wp1, wn, wt, uv1));
|
|
//outStream.RestartStrip();
|
|
//
|
|
//wn = ConstructNormal(wp4, wp1, wp5);
|
|
//outStream.Append(VertexOutput(wp4, wn, wt, uv1));
|
|
//outStream.Append(VertexOutput(wp1, wn, wt, uv1));
|
|
//outStream.Append(VertexOutput(wp5, wn, wt, uv2));
|
|
//outStream.Append(VertexOutput(wp2, wn, wt, uv2));
|
|
//outStream.RestartStrip();
|
|
//
|
|
//wn = ConstructNormal(wp5, wp2, wp3);
|
|
//outStream.Append(VertexOutput(wp5, wn, wt, uv2));
|
|
//outStream.Append(VertexOutput(wp2, wn, wt, uv2));
|
|
//outStream.Append(VertexOutput(wp3, wn, wt, uv0));
|
|
//outStream.Append(VertexOutput(wp0, wn, wt, uv0));
|
|
//outStream.RestartStrip();
|
|
}
|
|
|
|
//
|
|
// Fragment phase
|
|
//
|
|
|
|
#if defined(PASS_CUBE_SHADOWCASTER)
|
|
|
|
// Cube map shadow caster pass
|
|
half4 Fragment(Varyings input) : SV_Target {
|
|
float depth = length(input.shadow) + unity_LightShadowBias.x;
|
|
return UnityEncodeCubeShadowDepth(depth * _LightPositionRange.w);
|
|
}
|
|
|
|
#elif defined(UNITY_PASS_SHADOWCASTER)
|
|
|
|
// Default shadow caster pass
|
|
half4 Fragment() : SV_Target { return 0; }
|
|
|
|
#else
|
|
|
|
float _AlphaCutoff;
|
|
|
|
// GBuffer construction pass
|
|
void Fragment( Varyings input, out half4 outGBuffer0 : SV_Target0, out half4 outGBuffer1 : SV_Target1, out half4 outGBuffer2 : SV_Target2, out half4 outEmission : SV_Target3) {
|
|
// Sample textures
|
|
float4 sample = tex2D(_MainTex, input.texcoord);
|
|
if(sample.a <= _AlphaCutoff) clip(-1);
|
|
half3 albedo = sample.rgb * _Color.rgb;
|
|
|
|
half4 normal = tex2D(_BumpMap, input.texcoord);
|
|
normal.xyz = UnpackScaleNormal(normal, _BumpScale);
|
|
|
|
half occ = tex2D(_OcclusionMap, input.texcoord).g;
|
|
occ = LerpOneTo(occ, _OcclusionStrength);
|
|
|
|
// PBS workflow conversion (metallic -> specular)
|
|
half3 c_diff, c_spec;
|
|
half refl10;
|
|
c_diff = DiffuseAndSpecularFromMetallic(
|
|
albedo, _Metallic, // input
|
|
c_spec, refl10 // output
|
|
);
|
|
|
|
// Tangent space conversion (tangent space normal -> world space normal)
|
|
float3 wn = normalize(float3( dot(input.tspace0.xyz, normal), dot(input.tspace1.xyz, normal), dot(input.tspace2.xyz, normal) ));
|
|
|
|
// Update the GBuffer.
|
|
UnityStandardData data;
|
|
data.diffuseColor = c_diff;
|
|
data.occlusion = occ;
|
|
data.specularColor = c_spec;
|
|
data.smoothness = _Glossiness;
|
|
data.normalWorld = wn;
|
|
UnityStandardDataToGbuffer(data, outGBuffer0, outGBuffer1, outGBuffer2);
|
|
|
|
// Calculate ambient lighting and output to the emission buffer.
|
|
float3 wp = float3(input.tspace0.w, input.tspace1.w, input.tspace2.w);
|
|
half3 sh = ShadeSHPerPixel(data.normalWorld, input.ambient, wp);
|
|
outEmission = half4(sh * c_diff, 1) * occ;
|
|
}
|
|
|
|
#endif
|