From b35f8bd478778af7ca50eff8438f3f59b5d486df Mon Sep 17 00:00:00 2001 From: Timo Eberl Date: Sun, 31 Aug 2025 18:47:57 +0200 Subject: [PATCH] curved normals and some other stuff. lighting is done, but looks bad still --- Assets/Materials/Grass.mat | 7 ++- .../Scripts/MainCameraPositionShaderSetter.cs | 1 + Assets/Shaders/GrassBlade.shader | 9 +-- Assets/Shaders/include/GrassBladePass.hlsl | 63 ++++++++++--------- 4 files changed, 42 insertions(+), 38 deletions(-) diff --git a/Assets/Materials/Grass.mat b/Assets/Materials/Grass.mat index 2be98ad..5660b27 100644 --- a/Assets/Materials/Grass.mat +++ b/Assets/Materials/Grass.mat @@ -28,6 +28,10 @@ Material: m_Texture: {fileID: 2800000, guid: bbec7f79ed7356243ae0604d95144b77, type: 3} m_Scale: {x: 1, y: 1} m_Offset: {x: 0, y: 0} + - _FieldColor: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} - _FrabVarianz: m_Texture: {fileID: 2800000, guid: 9bb4e817f09d0ea4cbab03f772e01910, type: 3} m_Scale: {x: 1, y: 1} @@ -38,9 +42,10 @@ Material: - _BendStrength: 1 - _BladeBow: 0.195 - _BladeWidth: 0.0274 - - _BladeWidthTexStrength: 1 + - _BladeWidthTexStrength: 0.74 - _LOD: 0 - _Metallic: 0 + - _NormalCurvature: 1 - _Roughness: 0 - _SSSStrength: 1 - _Translucency: 1.81 diff --git a/Assets/Scripts/MainCameraPositionShaderSetter.cs b/Assets/Scripts/MainCameraPositionShaderSetter.cs index 62868c3..5aaadce 100644 --- a/Assets/Scripts/MainCameraPositionShaderSetter.cs +++ b/Assets/Scripts/MainCameraPositionShaderSetter.cs @@ -1,3 +1,4 @@ +using System; using UnityEngine; using UnityEditor; diff --git a/Assets/Shaders/GrassBlade.shader b/Assets/Shaders/GrassBlade.shader index 094ea57..20adef0 100644 --- a/Assets/Shaders/GrassBlade.shader +++ b/Assets/Shaders/GrassBlade.shader @@ -5,7 +5,7 @@ _BladeWidth("Blade Width", Range(0.003, .1)) = 0.01 _BendStrength("Bend Strength", Range(0, 1)) = 1 - _FrabVarianz("Farb Varianz", 2D) = "white" {} + _FieldColor("Field Color", 2D) = "white" {} _BladeWidthTex("Blade Width Texture", 2D) = "white" {} _AOStrength("Ambient Occlusion Strength", Range(0,2)) = 1 @@ -13,14 +13,9 @@ _SSSStrength("Subsurface Scattering Strength", Range(0,1)) = 1 _Metallic("Metallic", Range(0,1)) = 0 _Roughness("Roughness", Range(0,1)) = 0.3 - _BladeBow("Blade Bow", Range(0,1)) = 0.3 + _NormalCurvature("Normal Curvature", Range(0,1)) = 0.3 _BladeWidthTexStrength("BladeWidthTexStrength", Range(0,1)) = 0.3 _InnerColor("Inner Color", Color) = (1,1,1,1) - - _Color0("Color LOD 0", Color) = (0.3, 1.0, 0.3, 1.0) - _Color1("Color LOD 1", Color) = (1.0, 0.7, 0.3, 1.0) - _Color2("Color LOD 2", Color) = (1.0, 0.3, 0.1, 1.0) - _Color3("Color LOD 3", Color) = (0.8, 0.0, 0.0, 1.0) } SubShader { LOD 100 diff --git a/Assets/Shaders/include/GrassBladePass.hlsl b/Assets/Shaders/include/GrassBladePass.hlsl index a8dd538..3150167 100644 --- a/Assets/Shaders/include/GrassBladePass.hlsl +++ b/Assets/Shaders/include/GrassBladePass.hlsl @@ -1,9 +1,8 @@ // Material Properties float _BladeWidth, _BendStrength; -float4 _Color0, _Color1, _Color2, _Color3, _InnerColor; -float _SegmentsMinusOne, _FieldSize, _AOStrength, _Translucency, _SSSStrength, _Metallic, _Roughness, - _BladeBow, _MaxBladeHeight, _HighlightStrength, _BladeWidthTexStrength; -sampler2D _FrabVarianz, _BladeWidthTex; +float4 _InnerColor; +float _AOStrength, _Translucency, _SSSStrength, _Metallic, _Roughness, _NormalCurvature, _BladeWidthTexStrength; +sampler2D _FieldColor, _BladeWidthTex; float2 _TransitionRange; @@ -179,8 +178,15 @@ void geom(point v2g IN[1], inout TriangleStream triStream) { } const float3 normal = cross(surfTangent1, surfTangent2); - // TODO fake curvature - // o.localNormal = normalize(lerp(normalWS, UnityObjectToWorldNormal(-normalize(segmentWidthOffset)), _BladeBow)); +#if _LOD_LOD_0 + const float curvature = _NormalCurvature; +#elif _LOD_LOD_1 + const float curvature = lerp(_NormalCurvature, 0.0, interpolator); +#else + const float curvature = 0.0; +#endif + float3 leftCurvedNormal = normalize(normalize(normal) + widthOffset * curvature); + float3 rightCurvedNormal = normalize(normalize(normal) - widthOffset * curvature); previousVertLeft = vertLeft; previousVertRight = vertRight; @@ -190,7 +196,7 @@ void geom(point v2g IN[1], inout TriangleStream triStream) { #ifdef IS_IN_BASE_PASS o.uv = float2(1, segmentHeightNormalized); TRANSFER_SHADOW(o) - o.localNormal = normal; + o.localNormal = rightCurvedNormal; o.worldPos = mul(unity_ObjectToWorld, float4(vertRight,1.0)).xyz; #endif triStream.Append(o); @@ -199,7 +205,7 @@ void geom(point v2g IN[1], inout TriangleStream triStream) { #ifdef IS_IN_BASE_PASS o.uv = float2(0, segmentHeightNormalized); TRANSFER_SHADOW(o) - o.localNormal = normal; + o.localNormal = leftCurvedNormal; o.worldPos = mul(unity_ObjectToWorld, float4(vertLeft,1.0)).xyz; #endif triStream.Append(o); @@ -222,7 +228,7 @@ void geom(point v2g IN[1], inout TriangleStream triStream) { #endif } -float4 frag(g2f i) : SV_Target{ +float4 frag(g2f i, bool isFrontFace : SV_IsFrontFace) : SV_Target { #ifdef IS_IN_BASE_PASS float3 localPos = mul(unity_WorldToObject, float4(i.worldPos, 1)).xyz; float d = distance(localPos, i.debug) * 50; @@ -231,57 +237,54 @@ float4 frag(g2f i) : SV_Target{ // return float4(i.debug,1); float3 worldNormal = UnityObjectToWorldNormal(i.localNormal); - float3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)); // at which side of the blade are we looking? - // NOT ACCURATE, because the normals don't exactly match the geometry - const bool lookingFromAbove = dot(worldViewDir, worldNormal) > 0; - if (!lookingFromAbove) { + // VERY INACCURATE, because the normals don't match the geometry (smoothing, fake curvature) + if (!isFrontFace) { worldNormal = -worldNormal; } float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz); + float3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)); float3 worldRefl = reflect(-worldViewDir, worldNormal); - // same as in previous shader - half4 skyData = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, worldRefl, 0); + float4 skyData = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, worldRefl, 0); float3 skyColor = DecodeHDR(skyData, unity_SpecCube0_HDR); float3 lightReflectDirection = reflect(-lightDirection, worldNormal); float3 viewDirection = normalize(float3(float4(_MainCameraPosition.xyz, 1.0) - i.worldPos.xyz)); - - float atten = 1.0; - float3 translucency = atten * _LightColor0.xyz * max(0.0, dot(worldNormal, -lightDirection)) * _Translucency; + float3 translucency = _LightColor0.xyz * max(0.0, dot(worldNormal, -lightDirection)) * _Translucency; float3 subsurf = max(0.0, dot(lightReflectDirection, -viewDirection)) * _SSSStrength * _InnerColor; - const fixed shadow = SHADOW_ATTENUATION(i); + const float shadow = max(.35, SHADOW_ATTENUATION(i)); float3 lightFinal = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, worldNormal, 2.0); lightFinal += translucency; lightFinal += subsurf; - lightFinal *= max(.35, shadow); - lightFinal *= 1.0; + lightFinal *= shadow; + + // ATTENTION DO NOT TRY TO UNDERSTAND THE CODE BELOW (or you will go crazy) float4 middleCol = min(1, abs(i.uv.x - 0.5) * 1); float4 col = max(0.87, pow(middleCol, .01)); - float4 farbvarianz = tex2Dlod(_FrabVarianz, float4(i.worldPos.xz / 40, 0, 3)); - float4 farbvarianz2 = tex2Dlod(_FrabVarianz, float4(i.worldPos.xz / 10, 0, 3)); - float4 farbvarianz3 = tex2Dlod(_FrabVarianz, float4(i.worldPos.xz / 3, 0, 3)); + float3 c0 = tex2Dlod(_FieldColor, float4(i.worldPos.xz / 40, 0, 3)).xyz; + float3 c1 = tex2Dlod(_FieldColor, float4(i.worldPos.xz / 10, 0, 3)).xyz; + float3 c2 = tex2Dlod(_FieldColor, float4(i.worldPos.xz / 3, 0, 3)).xyz; float4 bladeWidthTex = tex2Dlod(_BladeWidthTex, float4(i.uv.x, 0, 0, 3)); - float4 albedo = lerp(farbvarianz2, farbvarianz3, 0.4); - albedo = lerp(albedo, farbvarianz, _Metallic) * 0.7; + float3 albedo = lerp(c1, c2, 0.4); + albedo = lerp(albedo, c0, _Metallic) * 0.7; albedo *= 1 + _AOStrength; albedo *= lerp(1, bladeWidthTex.x * 2.5, _BladeWidthTexStrength); - fixed3 color = fixed3(skyColor * max(.35, shadow) * .2 + lightFinal * albedo * col); - fixed3 highlightedColor = lerp(color, fixed3(2.5, 0.7, 0.5), 0.5); - fixed3 finalTestColor = albedo.xyz ; + float3 color = float3(skyColor * shadow * .2 + lightFinal * albedo * col); + float3 highlightedColor = lerp(color, float3(2.5, 0.7, 0.5), 0.5); + float3 finalTestColor = albedo.xyz ; lightFinal = min(1.4, max(0.4, lightFinal)); - return float4(worldNormal, 1); + return float4(color, 1); #endif return 0; // shadow pass }