[Add] Synaptic AI Pro
https://assetstore.unity.com/packages/tools/generative-ai/synaptic-ai-pro-natural-language-control-for-unity-336030
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
// Synaptic AI Pro - GPU Grass Instancing Compute Shader
|
||||
// Handles culling, LOD, and instance buffer generation for massive grass rendering
|
||||
|
||||
#pragma kernel CSMain
|
||||
#pragma kernel CSClear
|
||||
|
||||
// Grass instance data
|
||||
struct GrassInstance
|
||||
{
|
||||
float3 position;
|
||||
float3 normal;
|
||||
float2 uv;
|
||||
float height;
|
||||
float width;
|
||||
float rotation;
|
||||
float stiffness;
|
||||
float windPhase;
|
||||
};
|
||||
|
||||
// Indirect draw arguments
|
||||
struct IndirectArgs
|
||||
{
|
||||
uint vertexCountPerInstance;
|
||||
uint instanceCount;
|
||||
uint startVertexLocation;
|
||||
uint startInstanceLocation;
|
||||
};
|
||||
|
||||
// Input buffers
|
||||
StructuredBuffer<GrassInstance> _SourceInstances;
|
||||
RWStructuredBuffer<GrassInstance> _CulledInstances;
|
||||
RWStructuredBuffer<IndirectArgs> _IndirectArgs;
|
||||
|
||||
// Counters
|
||||
RWStructuredBuffer<uint> _InstanceCounter;
|
||||
|
||||
// Parameters
|
||||
float4x4 _ViewProjectionMatrix;
|
||||
float4x4 _ViewMatrix;
|
||||
float3 _CameraPosition;
|
||||
float3 _CameraForward;
|
||||
float _FrustumCullMargin;
|
||||
float _MaxRenderDistance;
|
||||
float _LOD0Distance;
|
||||
float _LOD1Distance;
|
||||
float _LOD2Distance;
|
||||
float _DensityFalloff;
|
||||
float _Time;
|
||||
|
||||
// Wind parameters
|
||||
float3 _WindDirection;
|
||||
float _WindStrength;
|
||||
float _WindSpeed;
|
||||
float _WindFrequency;
|
||||
|
||||
// Frustum planes
|
||||
float4 _FrustumPlanes[6];
|
||||
|
||||
// Instance counts
|
||||
uint _TotalInstances;
|
||||
uint _MaxVisibleInstances;
|
||||
|
||||
// LOD group (0, 1, 2)
|
||||
uint _LODGroup;
|
||||
|
||||
// Check if point is inside frustum
|
||||
bool IsInsideFrustum(float3 position, float margin)
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
float dist = dot(_FrustumPlanes[i].xyz, position) + _FrustumPlanes[i].w;
|
||||
if (dist < -margin)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Calculate LOD level based on distance
|
||||
uint GetLODLevel(float distance)
|
||||
{
|
||||
if (distance < _LOD0Distance)
|
||||
return 0;
|
||||
else if (distance < _LOD1Distance)
|
||||
return 1;
|
||||
else if (distance < _LOD2Distance)
|
||||
return 2;
|
||||
else
|
||||
return 3; // Culled
|
||||
}
|
||||
|
||||
// Hash function for consistent randomization
|
||||
float Hash(float2 p)
|
||||
{
|
||||
return frac(sin(dot(p, float2(127.1, 311.7))) * 43758.5453);
|
||||
}
|
||||
|
||||
// Wind offset calculation (matches shader)
|
||||
float3 CalculateWindOffset(float3 position, float height, float windPhase)
|
||||
{
|
||||
float3 windDir = normalize(_WindDirection);
|
||||
|
||||
// Main wind wave
|
||||
float phase = dot(position.xz, windDir.xz) * _WindFrequency + _Time * _WindSpeed + windPhase;
|
||||
float wave = sin(phase) * 0.5 + 0.5;
|
||||
|
||||
// Gust
|
||||
float gustPhase = _Time * 0.5 + windPhase;
|
||||
float gust = sin(gustPhase) * sin(gustPhase * 2.3) * 0.3;
|
||||
|
||||
float windFactor = (wave + gust) * _WindStrength * height * height;
|
||||
|
||||
return windDir * windFactor;
|
||||
}
|
||||
|
||||
[numthreads(256, 1, 1)]
|
||||
void CSMain(uint3 id : SV_DispatchThreadID)
|
||||
{
|
||||
if (id.x >= _TotalInstances)
|
||||
return;
|
||||
|
||||
GrassInstance instance = _SourceInstances[id.x];
|
||||
|
||||
// Calculate distance to camera
|
||||
float3 toCamera = _CameraPosition - instance.position;
|
||||
float distance = length(toCamera);
|
||||
|
||||
// Distance culling
|
||||
if (distance > _MaxRenderDistance)
|
||||
return;
|
||||
|
||||
// LOD selection
|
||||
uint lodLevel = GetLODLevel(distance);
|
||||
if (lodLevel != _LODGroup)
|
||||
return;
|
||||
|
||||
// Density falloff (render fewer instances at distance)
|
||||
if (lodLevel > 0)
|
||||
{
|
||||
float densityThreshold = 1.0 - (distance - _LOD0Distance) / (_MaxRenderDistance - _LOD0Distance) * _DensityFalloff;
|
||||
float randomValue = Hash(instance.position.xz);
|
||||
if (randomValue > densityThreshold)
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate wind-affected position for frustum culling
|
||||
float3 windOffset = CalculateWindOffset(instance.position, instance.height, instance.windPhase);
|
||||
float3 tipPosition = instance.position + float3(0, instance.height, 0) + windOffset;
|
||||
|
||||
// Frustum culling (check both root and tip)
|
||||
float cullMargin = _FrustumCullMargin + instance.height;
|
||||
if (!IsInsideFrustum(instance.position, cullMargin) && !IsInsideFrustum(tipPosition, cullMargin))
|
||||
return;
|
||||
|
||||
// Backface culling optimization (skip grass facing away)
|
||||
float3 grassForward = instance.normal;
|
||||
float facingRatio = dot(normalize(toCamera), grassForward);
|
||||
// Allow grass to be seen from both sides, but skip if completely edge-on
|
||||
if (abs(facingRatio) < 0.1)
|
||||
return;
|
||||
|
||||
// Add to visible buffer
|
||||
uint index;
|
||||
InterlockedAdd(_InstanceCounter[0], 1, index);
|
||||
|
||||
if (index < _MaxVisibleInstances)
|
||||
{
|
||||
_CulledInstances[index] = instance;
|
||||
}
|
||||
}
|
||||
|
||||
[numthreads(1, 1, 1)]
|
||||
void CSClear(uint3 id : SV_DispatchThreadID)
|
||||
{
|
||||
_InstanceCounter[0] = 0;
|
||||
_IndirectArgs[0].instanceCount = 0;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6031fc9431d7a496bbcd62708bdb5f7a
|
||||
ComputeShaderImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 336030
|
||||
packageName: Synaptic AI Pro - Natural Language Control for Unity
|
||||
packageVersion: 1.2.23
|
||||
assetPath: Assets/Synaptic AI Pro/Shaders/Grass/GrassInstancer.compute
|
||||
uploadId: 920982
|
||||
@@ -0,0 +1,874 @@
|
||||
Shader "Synaptic/GrassPro"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
[Header(Base)]
|
||||
_MainTex ("Albedo", 2D) = "white" {}
|
||||
_BaseColor ("Base Color", Color) = (0.2, 0.6, 0.2, 1)
|
||||
_TipColor ("Tip Color", Color) = (0.5, 0.9, 0.3, 1)
|
||||
_GradientPower ("Gradient Power", Range(0.1, 3)) = 1
|
||||
|
||||
[Header(Wind Animation)]
|
||||
[Toggle(_WIND_ON)] _WindEnabled ("Enable Wind", Float) = 1
|
||||
_WindStrength ("Wind Strength", Range(0, 2)) = 0.5
|
||||
_WindSpeed ("Wind Speed", Float) = 1
|
||||
_WindFrequency ("Wind Frequency", Float) = 1
|
||||
_WindDirection ("Wind Direction", Vector) = (1, 0, 0.5, 0)
|
||||
_WindNoiseTex ("Wind Noise", 2D) = "grey" {}
|
||||
_WindNoiseScale ("Wind Noise Scale", Float) = 0.1
|
||||
_WindGustStrength ("Gust Strength", Range(0, 2)) = 0.3
|
||||
_WindGustFrequency ("Gust Frequency", Float) = 0.5
|
||||
|
||||
[Header(Player Interaction)]
|
||||
[Toggle(_INTERACTION_ON)] _InteractionEnabled ("Enable Interaction", Float) = 1
|
||||
_InteractionRadius ("Interaction Radius", Float) = 2
|
||||
_InteractionStrength ("Interaction Strength", Range(0, 2)) = 1
|
||||
_InteractionFalloff ("Interaction Falloff", Range(0.1, 5)) = 2
|
||||
|
||||
[Header(Subsurface Scattering)]
|
||||
[Toggle(_SSS_ON)] _SSSEnabled ("Enable SSS", Float) = 1
|
||||
_SSSColor ("SSS Color", Color) = (0.8, 1.0, 0.5, 1)
|
||||
_SSSStrength ("SSS Strength", Range(0, 2)) = 1
|
||||
_SSSDistortion ("SSS Distortion", Range(0, 1)) = 0.5
|
||||
_SSSPower ("SSS Power", Range(1, 16)) = 4
|
||||
|
||||
[Header(Detail)]
|
||||
_AO ("Ambient Occlusion", Range(0, 1)) = 0.5
|
||||
_AOPower ("AO Power", Range(0.1, 3)) = 1
|
||||
_Roughness ("Roughness", Range(0, 1)) = 0.8
|
||||
|
||||
[Header(Specular)]
|
||||
[Toggle(_SPECULAR_ON)] _SpecularEnabled ("Enable Specular", Float) = 1
|
||||
_SpecularColor ("Specular Color", Color) = (1, 1, 0.8, 1)
|
||||
_SpecularIntensity ("Specular Intensity", Range(0, 3)) = 0.5
|
||||
_SpecularPower ("Specular Power", Range(1, 128)) = 32
|
||||
|
||||
[Header(Distance Fade)]
|
||||
[Toggle(_DISTANCE_FADE_ON)] _DistanceFadeEnabled ("Enable Distance Fade", Float) = 1
|
||||
_FadeStart ("Fade Start", Float) = 30
|
||||
_FadeEnd ("Fade End", Float) = 50
|
||||
_FadeMinScale ("Fade Min Scale", Range(0, 1)) = 0.3
|
||||
|
||||
[Header(Cutout)]
|
||||
_Cutoff ("Alpha Cutoff", Range(0, 1)) = 0.5
|
||||
|
||||
[Header(Rendering)]
|
||||
[Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull Mode", Float) = 0
|
||||
}
|
||||
|
||||
SubShader
|
||||
{
|
||||
PackageRequirements { "com.unity.render-pipelines.universal" }
|
||||
Tags
|
||||
{
|
||||
"RenderType" = "TransparentCutout"
|
||||
"Queue" = "AlphaTest"
|
||||
"RenderPipeline" = "UniversalPipeline"
|
||||
}
|
||||
|
||||
Pass
|
||||
{
|
||||
Name "GrassForward"
|
||||
Tags { "LightMode" = "UniversalForward" }
|
||||
|
||||
Cull [_Cull]
|
||||
AlphaToMask On
|
||||
|
||||
HLSLPROGRAM
|
||||
#pragma target 4.5
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
|
||||
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE
|
||||
#pragma multi_compile_fragment _ _SHADOWS_SOFT
|
||||
#pragma multi_compile _ _ADDITIONAL_LIGHTS
|
||||
#pragma multi_compile_fog
|
||||
#pragma multi_compile_instancing
|
||||
|
||||
#pragma shader_feature_local _WIND_ON
|
||||
#pragma shader_feature_local _INTERACTION_ON
|
||||
#pragma shader_feature_local _SSS_ON
|
||||
#pragma shader_feature_local _SPECULAR_ON
|
||||
#pragma shader_feature_local _DISTANCE_FADE_ON
|
||||
|
||||
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
||||
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
|
||||
|
||||
TEXTURE2D(_MainTex);
|
||||
TEXTURE2D(_WindNoiseTex);
|
||||
SAMPLER(sampler_MainTex);
|
||||
SAMPLER(sampler_WindNoiseTex);
|
||||
|
||||
// Interaction positions (set from script)
|
||||
float4 _InteractionPositions[16];
|
||||
int _InteractionCount;
|
||||
|
||||
CBUFFER_START(UnityPerMaterial)
|
||||
float4 _MainTex_ST;
|
||||
float4 _BaseColor;
|
||||
float4 _TipColor;
|
||||
float _GradientPower;
|
||||
|
||||
float _WindStrength;
|
||||
float _WindSpeed;
|
||||
float _WindFrequency;
|
||||
float4 _WindDirection;
|
||||
float4 _WindNoiseTex_ST;
|
||||
float _WindNoiseScale;
|
||||
float _WindGustStrength;
|
||||
float _WindGustFrequency;
|
||||
|
||||
float _InteractionRadius;
|
||||
float _InteractionStrength;
|
||||
float _InteractionFalloff;
|
||||
|
||||
float4 _SSSColor;
|
||||
float _SSSStrength;
|
||||
float _SSSDistortion;
|
||||
float _SSSPower;
|
||||
|
||||
float _AO;
|
||||
float _AOPower;
|
||||
float _Roughness;
|
||||
|
||||
float4 _SpecularColor;
|
||||
float _SpecularIntensity;
|
||||
float _SpecularPower;
|
||||
|
||||
float _FadeStart;
|
||||
float _FadeEnd;
|
||||
float _FadeMinScale;
|
||||
|
||||
float _Cutoff;
|
||||
CBUFFER_END
|
||||
|
||||
struct Attributes
|
||||
{
|
||||
float4 positionOS : POSITION;
|
||||
float3 normalOS : NORMAL;
|
||||
float2 uv : TEXCOORD0;
|
||||
float4 color : COLOR; // R = height, G = AO, B = unused, A = stiffness
|
||||
UNITY_VERTEX_INPUT_INSTANCE_ID
|
||||
};
|
||||
|
||||
struct Varyings
|
||||
{
|
||||
float4 positionCS : SV_POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
float3 worldPos : TEXCOORD1;
|
||||
float3 worldNormal : TEXCOORD2;
|
||||
float4 vertexColor : TEXCOORD3;
|
||||
float4 shadowCoord : TEXCOORD4;
|
||||
float fogFactor : TEXCOORD5;
|
||||
float heightGradient : TEXCOORD6;
|
||||
UNITY_VERTEX_INPUT_INSTANCE_ID
|
||||
};
|
||||
|
||||
// Wind functions
|
||||
float3 WindAnimation(float3 worldPos, float height, float stiffness, float time)
|
||||
{
|
||||
#if defined(_WIND_ON)
|
||||
float3 windDir = normalize(_WindDirection.xyz);
|
||||
|
||||
// Sample wind noise
|
||||
float2 noiseUV = worldPos.xz * _WindNoiseScale + time * _WindSpeed * 0.1;
|
||||
float noise = SAMPLE_TEXTURE2D_LOD(_WindNoiseTex, sampler_WindNoiseTex, noiseUV, 0).r;
|
||||
|
||||
// Main wind wave
|
||||
float windPhase = dot(worldPos.xz, windDir.xz) * _WindFrequency + time * _WindSpeed;
|
||||
float wave = sin(windPhase) * 0.5 + 0.5;
|
||||
|
||||
// Gust
|
||||
float gustPhase = time * _WindGustFrequency;
|
||||
float gust = sin(gustPhase) * sin(gustPhase * 2.3) * _WindGustStrength;
|
||||
|
||||
// Combined wind
|
||||
float windFactor = (wave + gust + noise - 0.5) * _WindStrength;
|
||||
windFactor *= height * height; // Quadratic falloff from root
|
||||
windFactor *= (1 - stiffness); // Stiffness reduces wind effect
|
||||
|
||||
return windDir * windFactor;
|
||||
#else
|
||||
return float3(0, 0, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Player interaction
|
||||
float3 InteractionDisplacement(float3 worldPos, float height)
|
||||
{
|
||||
#if defined(_INTERACTION_ON)
|
||||
float3 totalDisplacement = float3(0, 0, 0);
|
||||
|
||||
for (int i = 0; i < _InteractionCount && i < 16; i++)
|
||||
{
|
||||
float3 interactorPos = _InteractionPositions[i].xyz;
|
||||
float3 toGrass = worldPos - interactorPos;
|
||||
toGrass.y = 0;
|
||||
|
||||
float dist = length(toGrass);
|
||||
float influence = 1 - saturate(pow(dist / _InteractionRadius, _InteractionFalloff));
|
||||
|
||||
if (influence > 0.001)
|
||||
{
|
||||
float3 pushDir = normalize(toGrass + float3(0.001, 0, 0.001));
|
||||
totalDisplacement += pushDir * influence * _InteractionStrength * height;
|
||||
}
|
||||
}
|
||||
|
||||
return totalDisplacement;
|
||||
#else
|
||||
return float3(0, 0, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
Varyings vert(Attributes IN)
|
||||
{
|
||||
Varyings OUT;
|
||||
UNITY_SETUP_INSTANCE_ID(IN);
|
||||
UNITY_TRANSFER_INSTANCE_ID(IN, OUT);
|
||||
|
||||
float height = IN.color.r; // Height along blade (0 = root, 1 = tip)
|
||||
float stiffness = IN.color.a;
|
||||
float time = _Time.y;
|
||||
|
||||
float3 posOS = IN.positionOS.xyz;
|
||||
float3 worldPosBase = TransformObjectToWorld(float3(0, 0, 0));
|
||||
|
||||
// Distance fade
|
||||
#if defined(_DISTANCE_FADE_ON)
|
||||
float distToCam = distance(worldPosBase, _WorldSpaceCameraPos);
|
||||
float fadeFactor = saturate((distToCam - _FadeStart) / (_FadeEnd - _FadeStart));
|
||||
float scale = lerp(1, _FadeMinScale, fadeFactor);
|
||||
posOS *= scale;
|
||||
#endif
|
||||
|
||||
float3 worldPos = TransformObjectToWorld(posOS);
|
||||
|
||||
// Apply wind
|
||||
float3 windOffset = WindAnimation(worldPos, height, stiffness, time);
|
||||
worldPos += windOffset;
|
||||
|
||||
// Apply interaction
|
||||
float3 interactOffset = InteractionDisplacement(worldPos, height);
|
||||
worldPos += interactOffset;
|
||||
|
||||
OUT.worldPos = worldPos;
|
||||
OUT.positionCS = TransformWorldToHClip(worldPos);
|
||||
OUT.uv = TRANSFORM_TEX(IN.uv, _MainTex);
|
||||
OUT.worldNormal = TransformObjectToWorldNormal(IN.normalOS);
|
||||
OUT.vertexColor = IN.color;
|
||||
OUT.shadowCoord = TransformWorldToShadowCoord(worldPos);
|
||||
OUT.fogFactor = ComputeFogFactor(OUT.positionCS.z);
|
||||
OUT.heightGradient = height;
|
||||
|
||||
return OUT;
|
||||
}
|
||||
|
||||
// SSS function
|
||||
float3 SubsurfaceScattering(float3 viewDir, float3 lightDir, float3 normal, float3 lightColor)
|
||||
{
|
||||
#if defined(_SSS_ON)
|
||||
float3 H = normalize(lightDir + normal * _SSSDistortion);
|
||||
float VdotH = pow(saturate(dot(viewDir, -H)), _SSSPower);
|
||||
return _SSSColor.rgb * VdotH * _SSSStrength * lightColor;
|
||||
#else
|
||||
return float3(0, 0, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
float4 frag(Varyings IN) : SV_Target
|
||||
{
|
||||
UNITY_SETUP_INSTANCE_ID(IN);
|
||||
|
||||
// Sample texture
|
||||
float4 texColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uv);
|
||||
clip(texColor.a - _Cutoff);
|
||||
|
||||
float3 viewDir = normalize(_WorldSpaceCameraPos - IN.worldPos);
|
||||
float3 normal = normalize(IN.worldNormal);
|
||||
|
||||
// Height-based color gradient
|
||||
float gradientFactor = pow(IN.heightGradient, _GradientPower);
|
||||
float3 albedo = lerp(_BaseColor.rgb, _TipColor.rgb, gradientFactor) * texColor.rgb;
|
||||
|
||||
// Ambient occlusion from vertex color
|
||||
float ao = lerp(1, IN.vertexColor.g, _AO);
|
||||
ao = pow(ao, _AOPower);
|
||||
|
||||
// Lighting
|
||||
Light mainLight = GetMainLight(IN.shadowCoord);
|
||||
float3 lightDir = mainLight.direction;
|
||||
float3 lightColor = mainLight.color;
|
||||
float shadow = mainLight.shadowAttenuation;
|
||||
|
||||
// Wrapped diffuse for softer look
|
||||
float NdotL = dot(normal, lightDir);
|
||||
float wrappedNdotL = NdotL * 0.5 + 0.5;
|
||||
float3 diffuse = albedo * lightColor * wrappedNdotL * shadow;
|
||||
|
||||
// SSS
|
||||
float3 sss = SubsurfaceScattering(viewDir, lightDir, normal, lightColor);
|
||||
sss *= (1 - IN.heightGradient) * shadow; // More SSS at base
|
||||
|
||||
// Specular
|
||||
float3 specular = float3(0, 0, 0);
|
||||
#if defined(_SPECULAR_ON)
|
||||
float3 halfDir = normalize(lightDir + viewDir);
|
||||
float NdotH = saturate(dot(normal, halfDir));
|
||||
float spec = pow(NdotH, _SpecularPower) * _SpecularIntensity;
|
||||
specular = _SpecularColor.rgb * spec * shadow * IN.heightGradient; // More specular at tip
|
||||
#endif
|
||||
|
||||
// Additional lights
|
||||
float3 additionalLights = float3(0, 0, 0);
|
||||
#if defined(_ADDITIONAL_LIGHTS)
|
||||
uint pixelLightCount = GetAdditionalLightsCount();
|
||||
for (uint i = 0; i < pixelLightCount; i++)
|
||||
{
|
||||
Light light = GetAdditionalLight(i, IN.worldPos);
|
||||
float addNdotL = saturate(dot(normal, light.direction));
|
||||
additionalLights += albedo * light.color * light.distanceAttenuation * addNdotL * 0.5;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Ambient
|
||||
float3 ambient = albedo * 0.1;
|
||||
|
||||
// Combine
|
||||
float3 finalColor = (diffuse + sss + specular + additionalLights + ambient) * ao;
|
||||
|
||||
// Fog
|
||||
finalColor = MixFog(finalColor, IN.fogFactor);
|
||||
|
||||
return float4(finalColor, texColor.a);
|
||||
}
|
||||
ENDHLSL
|
||||
}
|
||||
|
||||
// Shadow caster pass
|
||||
Pass
|
||||
{
|
||||
Name "ShadowCaster"
|
||||
Tags { "LightMode" = "ShadowCaster" }
|
||||
|
||||
ZWrite On
|
||||
ZTest LEqual
|
||||
ColorMask 0
|
||||
Cull Off
|
||||
|
||||
HLSLPROGRAM
|
||||
#pragma target 4.5
|
||||
#pragma vertex ShadowVert
|
||||
#pragma fragment ShadowFrag
|
||||
|
||||
#pragma multi_compile_instancing
|
||||
#pragma shader_feature_local _WIND_ON
|
||||
#pragma shader_feature_local _DISTANCE_FADE_ON
|
||||
|
||||
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
||||
|
||||
float3 _LightDirection;
|
||||
|
||||
float3 ApplyShadowBiasCustom(float3 positionWS, float3 normalWS, float3 lightDirection)
|
||||
{
|
||||
float invNdotL = 1.0 - saturate(dot(lightDirection, normalWS));
|
||||
float scale = invNdotL * 0.001;
|
||||
positionWS = lightDirection * 0.001 + positionWS;
|
||||
positionWS = normalWS * scale.xxx + positionWS;
|
||||
return positionWS;
|
||||
}
|
||||
|
||||
TEXTURE2D(_MainTex);
|
||||
TEXTURE2D(_WindNoiseTex);
|
||||
SAMPLER(sampler_MainTex);
|
||||
SAMPLER(sampler_WindNoiseTex);
|
||||
|
||||
CBUFFER_START(UnityPerMaterial)
|
||||
float4 _MainTex_ST;
|
||||
float _WindStrength;
|
||||
float _WindSpeed;
|
||||
float _WindFrequency;
|
||||
float4 _WindDirection;
|
||||
float _WindNoiseScale;
|
||||
float _WindGustStrength;
|
||||
float _WindGustFrequency;
|
||||
float _FadeStart;
|
||||
float _FadeEnd;
|
||||
float _FadeMinScale;
|
||||
float _Cutoff;
|
||||
CBUFFER_END
|
||||
|
||||
struct Attributes
|
||||
{
|
||||
float4 positionOS : POSITION;
|
||||
float3 normalOS : NORMAL;
|
||||
float2 uv : TEXCOORD0;
|
||||
float4 color : COLOR;
|
||||
UNITY_VERTEX_INPUT_INSTANCE_ID
|
||||
};
|
||||
|
||||
struct Varyings
|
||||
{
|
||||
float4 positionCS : SV_POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
UNITY_VERTEX_INPUT_INSTANCE_ID
|
||||
};
|
||||
|
||||
float3 WindAnimation(float3 worldPos, float height, float stiffness, float time)
|
||||
{
|
||||
#if defined(_WIND_ON)
|
||||
float3 windDir = normalize(_WindDirection.xyz);
|
||||
float windPhase = dot(worldPos.xz, windDir.xz) * _WindFrequency + time * _WindSpeed;
|
||||
float wave = sin(windPhase) * 0.5 + 0.5;
|
||||
float gustPhase = time * _WindGustFrequency;
|
||||
float gust = sin(gustPhase) * sin(gustPhase * 2.3) * _WindGustStrength;
|
||||
float windFactor = (wave + gust - 0.25) * _WindStrength;
|
||||
windFactor *= height * height;
|
||||
windFactor *= (1 - stiffness);
|
||||
return windDir * windFactor;
|
||||
#else
|
||||
return float3(0, 0, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
Varyings ShadowVert(Attributes IN)
|
||||
{
|
||||
Varyings OUT;
|
||||
UNITY_SETUP_INSTANCE_ID(IN);
|
||||
UNITY_TRANSFER_INSTANCE_ID(IN, OUT);
|
||||
|
||||
float height = IN.color.r;
|
||||
float stiffness = IN.color.a;
|
||||
|
||||
float3 posOS = IN.positionOS.xyz;
|
||||
|
||||
#if defined(_DISTANCE_FADE_ON)
|
||||
float3 worldPosBase = TransformObjectToWorld(float3(0, 0, 0));
|
||||
float distToCam = distance(worldPosBase, _WorldSpaceCameraPos);
|
||||
float fadeFactor = saturate((distToCam - _FadeStart) / (_FadeEnd - _FadeStart));
|
||||
float scale = lerp(1, _FadeMinScale, fadeFactor);
|
||||
posOS *= scale;
|
||||
#endif
|
||||
|
||||
float3 worldPos = TransformObjectToWorld(posOS);
|
||||
worldPos += WindAnimation(worldPos, height, stiffness, _Time.y);
|
||||
|
||||
float3 worldNormal = TransformObjectToWorldNormal(IN.normalOS);
|
||||
worldPos = ApplyShadowBiasCustom(worldPos, worldNormal, _LightDirection);
|
||||
float4 posCS = TransformWorldToHClip(worldPos);
|
||||
|
||||
#if UNITY_REVERSED_Z
|
||||
posCS.z = min(posCS.z, UNITY_NEAR_CLIP_VALUE);
|
||||
#else
|
||||
posCS.z = max(posCS.z, UNITY_NEAR_CLIP_VALUE);
|
||||
#endif
|
||||
|
||||
OUT.positionCS = posCS;
|
||||
OUT.uv = TRANSFORM_TEX(IN.uv, _MainTex);
|
||||
|
||||
return OUT;
|
||||
}
|
||||
|
||||
float4 ShadowFrag(Varyings IN) : SV_Target
|
||||
{
|
||||
float alpha = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uv).a;
|
||||
clip(alpha - _Cutoff);
|
||||
return 0;
|
||||
}
|
||||
ENDHLSL
|
||||
}
|
||||
|
||||
// Depth pass
|
||||
Pass
|
||||
{
|
||||
Name "DepthOnly"
|
||||
Tags { "LightMode" = "DepthOnly" }
|
||||
|
||||
ZWrite On
|
||||
ColorMask 0
|
||||
Cull Off
|
||||
|
||||
HLSLPROGRAM
|
||||
#pragma target 4.5
|
||||
#pragma vertex DepthVert
|
||||
#pragma fragment DepthFrag
|
||||
|
||||
#pragma multi_compile_instancing
|
||||
#pragma shader_feature_local _WIND_ON
|
||||
#pragma shader_feature_local _DISTANCE_FADE_ON
|
||||
|
||||
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
||||
|
||||
TEXTURE2D(_MainTex);
|
||||
SAMPLER(sampler_MainTex);
|
||||
|
||||
CBUFFER_START(UnityPerMaterial)
|
||||
float4 _MainTex_ST;
|
||||
float _WindStrength;
|
||||
float _WindSpeed;
|
||||
float _WindFrequency;
|
||||
float4 _WindDirection;
|
||||
float _WindGustStrength;
|
||||
float _WindGustFrequency;
|
||||
float _FadeStart;
|
||||
float _FadeEnd;
|
||||
float _FadeMinScale;
|
||||
float _Cutoff;
|
||||
CBUFFER_END
|
||||
|
||||
struct Attributes
|
||||
{
|
||||
float4 positionOS : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
float4 color : COLOR;
|
||||
UNITY_VERTEX_INPUT_INSTANCE_ID
|
||||
};
|
||||
|
||||
struct Varyings
|
||||
{
|
||||
float4 positionCS : SV_POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
float3 WindAnimation(float3 worldPos, float height, float stiffness, float time)
|
||||
{
|
||||
#if defined(_WIND_ON)
|
||||
float3 windDir = normalize(_WindDirection.xyz);
|
||||
float windPhase = dot(worldPos.xz, windDir.xz) * _WindFrequency + time * _WindSpeed;
|
||||
float wave = sin(windPhase) * 0.5 + 0.5;
|
||||
float gustPhase = time * _WindGustFrequency;
|
||||
float gust = sin(gustPhase) * sin(gustPhase * 2.3) * _WindGustStrength;
|
||||
float windFactor = (wave + gust - 0.25) * _WindStrength;
|
||||
windFactor *= height * height;
|
||||
windFactor *= (1 - stiffness);
|
||||
return windDir * windFactor;
|
||||
#else
|
||||
return float3(0, 0, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
Varyings DepthVert(Attributes IN)
|
||||
{
|
||||
Varyings OUT;
|
||||
UNITY_SETUP_INSTANCE_ID(IN);
|
||||
|
||||
float height = IN.color.r;
|
||||
float stiffness = IN.color.a;
|
||||
float3 posOS = IN.positionOS.xyz;
|
||||
|
||||
#if defined(_DISTANCE_FADE_ON)
|
||||
float3 worldPosBase = TransformObjectToWorld(float3(0, 0, 0));
|
||||
float distToCam = distance(worldPosBase, _WorldSpaceCameraPos);
|
||||
float fadeFactor = saturate((distToCam - _FadeStart) / (_FadeEnd - _FadeStart));
|
||||
posOS *= lerp(1, _FadeMinScale, fadeFactor);
|
||||
#endif
|
||||
|
||||
float3 worldPos = TransformObjectToWorld(posOS);
|
||||
worldPos += WindAnimation(worldPos, height, stiffness, _Time.y);
|
||||
|
||||
OUT.positionCS = TransformWorldToHClip(worldPos);
|
||||
OUT.uv = TRANSFORM_TEX(IN.uv, _MainTex);
|
||||
|
||||
return OUT;
|
||||
}
|
||||
|
||||
float4 DepthFrag(Varyings IN) : SV_Target
|
||||
{
|
||||
float alpha = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uv).a;
|
||||
clip(alpha - _Cutoff);
|
||||
return 0;
|
||||
}
|
||||
ENDHLSL
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== Built-in Pipeline SubShader ====================
|
||||
SubShader
|
||||
{
|
||||
Tags { "RenderType" = "TransparentCutout" "Queue" = "AlphaTest" }
|
||||
|
||||
Pass
|
||||
{
|
||||
Name "GrassBuiltIn"
|
||||
Tags { "LightMode" = "ForwardBase" }
|
||||
Cull Off
|
||||
|
||||
CGPROGRAM
|
||||
#pragma target 3.0
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
#pragma multi_compile_fwdbase
|
||||
#pragma multi_compile_fog
|
||||
#pragma multi_compile_instancing
|
||||
|
||||
#pragma shader_feature_local _WIND_ON
|
||||
#pragma shader_feature_local _SSS_ON
|
||||
#pragma shader_feature_local _SPECULAR_ON
|
||||
|
||||
#include "UnityCG.cginc"
|
||||
#include "Lighting.cginc"
|
||||
#include "AutoLight.cginc"
|
||||
|
||||
sampler2D _MainTex;
|
||||
float4 _MainTex_ST;
|
||||
float4 _BaseColor;
|
||||
float4 _TipColor;
|
||||
float _GradientPower;
|
||||
float _WindStrength;
|
||||
float _WindSpeed;
|
||||
float _WindFrequency;
|
||||
float4 _WindDirection;
|
||||
float _WindGustStrength;
|
||||
float _WindGustFrequency;
|
||||
float4 _SSSColor;
|
||||
float _SSSStrength;
|
||||
float _SSSDistortion;
|
||||
float _SSSPower;
|
||||
float4 _SpecularColor;
|
||||
float _SpecularIntensity;
|
||||
float _SpecularPower;
|
||||
float _AO;
|
||||
float _AOPower;
|
||||
float _Cutoff;
|
||||
|
||||
struct appdata
|
||||
{
|
||||
float4 vertex : POSITION;
|
||||
float3 normal : NORMAL;
|
||||
float2 uv : TEXCOORD0;
|
||||
float4 color : COLOR;
|
||||
UNITY_VERTEX_INPUT_INSTANCE_ID
|
||||
};
|
||||
|
||||
struct v2f
|
||||
{
|
||||
float4 pos : SV_POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
float3 worldPos : TEXCOORD1;
|
||||
float3 worldNormal : TEXCOORD2;
|
||||
float4 vertexColor : TEXCOORD3;
|
||||
float heightGradient : TEXCOORD4;
|
||||
SHADOW_COORDS(5)
|
||||
UNITY_FOG_COORDS(6)
|
||||
UNITY_VERTEX_INPUT_INSTANCE_ID
|
||||
};
|
||||
|
||||
float3 WindAnimation(float3 worldPos, float height, float stiffness, float time)
|
||||
{
|
||||
#if defined(_WIND_ON)
|
||||
float3 windDir = normalize(_WindDirection.xyz);
|
||||
float windPhase = dot(worldPos.xz, windDir.xz) * _WindFrequency + time * _WindSpeed;
|
||||
float wave = sin(windPhase) * 0.5 + 0.5;
|
||||
float gustPhase = time * _WindGustFrequency;
|
||||
float gust = sin(gustPhase) * sin(gustPhase * 2.3) * _WindGustStrength;
|
||||
float windFactor = (wave + gust - 0.25) * _WindStrength;
|
||||
windFactor *= height * height * (1 - stiffness);
|
||||
return windDir * windFactor;
|
||||
#else
|
||||
return float3(0, 0, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
v2f vert(appdata v)
|
||||
{
|
||||
v2f o;
|
||||
UNITY_SETUP_INSTANCE_ID(v);
|
||||
UNITY_TRANSFER_INSTANCE_ID(v, o);
|
||||
|
||||
float height = v.color.r;
|
||||
float stiffness = v.color.a;
|
||||
float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
|
||||
worldPos += WindAnimation(worldPos, height, stiffness, _Time.y);
|
||||
|
||||
o.pos = mul(UNITY_MATRIX_VP, float4(worldPos, 1));
|
||||
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
|
||||
o.worldPos = worldPos;
|
||||
o.worldNormal = UnityObjectToWorldNormal(v.normal);
|
||||
o.vertexColor = v.color;
|
||||
o.heightGradient = height;
|
||||
TRANSFER_SHADOW(o)
|
||||
UNITY_TRANSFER_FOG(o, o.pos);
|
||||
return o;
|
||||
}
|
||||
|
||||
float4 frag(v2f i) : SV_Target
|
||||
{
|
||||
UNITY_SETUP_INSTANCE_ID(i);
|
||||
|
||||
float4 texColor = tex2D(_MainTex, i.uv);
|
||||
clip(texColor.a - _Cutoff);
|
||||
|
||||
float3 viewDir = normalize(_WorldSpaceCameraPos - i.worldPos);
|
||||
float3 normal = normalize(i.worldNormal);
|
||||
|
||||
float gradientFactor = pow(i.heightGradient, _GradientPower);
|
||||
float3 albedo = lerp(_BaseColor.rgb, _TipColor.rgb, gradientFactor) * texColor.rgb;
|
||||
|
||||
float ao = pow(lerp(1, i.vertexColor.g, _AO), _AOPower);
|
||||
|
||||
float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
|
||||
float3 lightColor = _LightColor0.rgb;
|
||||
float shadow = SHADOW_ATTENUATION(i);
|
||||
|
||||
float NdotL = saturate(dot(normal, lightDir));
|
||||
float3 diffuse = albedo * lightColor * NdotL * shadow;
|
||||
|
||||
float3 sss = float3(0, 0, 0);
|
||||
#if defined(_SSS_ON)
|
||||
float3 H = normalize(lightDir + normal * _SSSDistortion);
|
||||
float VdotH = pow(saturate(dot(viewDir, -H)), _SSSPower);
|
||||
sss = _SSSColor.rgb * VdotH * _SSSStrength * lightColor * shadow;
|
||||
#endif
|
||||
|
||||
float3 specular = float3(0, 0, 0);
|
||||
#if defined(_SPECULAR_ON)
|
||||
float3 halfDir = normalize(lightDir + viewDir);
|
||||
float NdotH = saturate(dot(normal, halfDir));
|
||||
float spec = pow(NdotH, _SpecularPower);
|
||||
specular = _SpecularColor.rgb * spec * _SpecularIntensity * lightColor * shadow;
|
||||
#endif
|
||||
|
||||
float3 ambient = albedo * 0.1;
|
||||
float3 finalColor = (diffuse + sss + specular + ambient) * ao;
|
||||
UNITY_APPLY_FOG(i.fogCoord, finalColor);
|
||||
|
||||
return float4(finalColor, texColor.a);
|
||||
}
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== HDRP SubShader ====================
|
||||
SubShader
|
||||
{
|
||||
PackageRequirements { "com.unity.render-pipelines.high-definition" }
|
||||
Tags { "RenderType" = "TransparentCutout" "Queue" = "AlphaTest" "RenderPipeline" = "HDRenderPipeline" }
|
||||
|
||||
Pass
|
||||
{
|
||||
Name "GrassHDRP"
|
||||
Tags { "LightMode" = "Forward" }
|
||||
Cull Off
|
||||
|
||||
HLSLPROGRAM
|
||||
#pragma target 4.5
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
#pragma multi_compile_instancing
|
||||
#pragma shader_feature_local _WIND_ON
|
||||
#pragma shader_feature_local _SSS_ON
|
||||
|
||||
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
|
||||
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
|
||||
|
||||
TEXTURE2D(_MainTex);
|
||||
SAMPLER(sampler_MainTex);
|
||||
|
||||
CBUFFER_START(UnityPerMaterial)
|
||||
float4 _MainTex_ST;
|
||||
float4 _BaseColor;
|
||||
float4 _TipColor;
|
||||
float _GradientPower;
|
||||
float _WindStrength;
|
||||
float _WindSpeed;
|
||||
float _WindFrequency;
|
||||
float4 _WindDirection;
|
||||
float _WindGustStrength;
|
||||
float _WindGustFrequency;
|
||||
float4 _SSSColor;
|
||||
float _SSSStrength;
|
||||
float _SSSDistortion;
|
||||
float _SSSPower;
|
||||
float _AO;
|
||||
float _AOPower;
|
||||
float _Cutoff;
|
||||
CBUFFER_END
|
||||
|
||||
struct Attributes
|
||||
{
|
||||
float4 positionOS : POSITION;
|
||||
float3 normalOS : NORMAL;
|
||||
float2 uv : TEXCOORD0;
|
||||
float4 color : COLOR;
|
||||
UNITY_VERTEX_INPUT_INSTANCE_ID
|
||||
};
|
||||
|
||||
struct Varyings
|
||||
{
|
||||
float4 positionCS : SV_POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
float3 worldPos : TEXCOORD1;
|
||||
float3 worldNormal : TEXCOORD2;
|
||||
float4 vertexColor : TEXCOORD3;
|
||||
float heightGradient : TEXCOORD4;
|
||||
UNITY_VERTEX_INPUT_INSTANCE_ID
|
||||
};
|
||||
|
||||
float3 WindAnimation(float3 worldPos, float height, float stiffness, float time)
|
||||
{
|
||||
#if defined(_WIND_ON)
|
||||
float3 windDir = normalize(_WindDirection.xyz);
|
||||
float windPhase = dot(worldPos.xz, windDir.xz) * _WindFrequency + time * _WindSpeed;
|
||||
float wave = sin(windPhase) * 0.5 + 0.5;
|
||||
float gust = sin(time * _WindGustFrequency) * sin(time * _WindGustFrequency * 2.3) * _WindGustStrength;
|
||||
float windFactor = (wave + gust - 0.25) * _WindStrength * height * height * (1 - stiffness);
|
||||
return windDir * windFactor;
|
||||
#else
|
||||
return float3(0, 0, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
Varyings vert(Attributes IN)
|
||||
{
|
||||
Varyings OUT;
|
||||
UNITY_SETUP_INSTANCE_ID(IN);
|
||||
UNITY_TRANSFER_INSTANCE_ID(IN, OUT);
|
||||
|
||||
float height = IN.color.r;
|
||||
float stiffness = IN.color.a;
|
||||
float3 worldPos = TransformObjectToWorld(IN.positionOS.xyz);
|
||||
worldPos += WindAnimation(worldPos, height, stiffness, _Time.y);
|
||||
|
||||
OUT.positionCS = TransformWorldToHClip(worldPos);
|
||||
OUT.uv = IN.uv * _MainTex_ST.xy + _MainTex_ST.zw;
|
||||
OUT.worldPos = worldPos;
|
||||
OUT.worldNormal = TransformObjectToWorldNormal(IN.normalOS);
|
||||
OUT.vertexColor = IN.color;
|
||||
OUT.heightGradient = height;
|
||||
return OUT;
|
||||
}
|
||||
|
||||
float4 frag(Varyings IN) : SV_Target
|
||||
{
|
||||
UNITY_SETUP_INSTANCE_ID(IN);
|
||||
|
||||
float4 texColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.uv);
|
||||
clip(texColor.a - _Cutoff);
|
||||
|
||||
float3 viewDir = GetWorldSpaceNormalizeViewDir(IN.worldPos);
|
||||
float3 normal = normalize(IN.worldNormal);
|
||||
|
||||
float gradientFactor = pow(IN.heightGradient, _GradientPower);
|
||||
float3 albedo = lerp(_BaseColor.rgb, _TipColor.rgb, gradientFactor) * texColor.rgb;
|
||||
float ao = pow(lerp(1, IN.vertexColor.g, _AO), _AOPower);
|
||||
|
||||
float3 lightDir = float3(0.5, 0.8, 0.2);
|
||||
float NdotL = saturate(dot(normal, lightDir));
|
||||
float3 diffuse = albedo * NdotL;
|
||||
|
||||
float3 sss = float3(0, 0, 0);
|
||||
#if defined(_SSS_ON)
|
||||
float3 H = normalize(lightDir + normal * _SSSDistortion);
|
||||
float VdotH = pow(saturate(dot(viewDir, -H)), _SSSPower);
|
||||
sss = _SSSColor.rgb * VdotH * _SSSStrength;
|
||||
#endif
|
||||
|
||||
float3 finalColor = (diffuse + sss + albedo * 0.1) * ao;
|
||||
return float4(finalColor, texColor.a);
|
||||
}
|
||||
ENDHLSL
|
||||
}
|
||||
}
|
||||
|
||||
FallBack "Universal Render Pipeline/Unlit"
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 018e57d0f0e184f44b8e10e7c593c179
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 336030
|
||||
packageName: Synaptic AI Pro - Natural Language Control for Unity
|
||||
packageVersion: 1.2.23
|
||||
assetPath: Assets/Synaptic AI Pro/Shaders/Grass/SynapticGrassPro.shader
|
||||
uploadId: 920982
|
||||
Reference in New Issue
Block a user