Last active
March 18, 2023 10:44
-
-
Save nickludlam/02cb409e983a642b8dc1d2175f5aa2e9 to your computer and use it in GitHub Desktop.
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
#ifndef FOLIAGE_WIND_INCLUDED | |
#define FOLIAGE_WIND_INCLUDED | |
// This is the Unity Shadergraph port of https://mtnphil.wordpress.com/2011/10/18/wind-animations-for-vegetation/ | |
#define SIDE_TO_SIDE_FREQ1 1.975 | |
#define SIDE_TO_SIDE_FREQ2 0.793 | |
#define UP_AND_DOWN_FREQ1 0.375 | |
#define UP_AND_DOWN_FREQ2 0.193 | |
half4 SmoothCurve( half4 x ) | |
{ | |
return x * x *( 3.0 - 2.0 * x ); | |
} | |
half4 TriangleWave( half4 x ) | |
{ | |
return abs( frac( x + 0.5 ) * 2.0 - 1.0 ); | |
} | |
half4 SmoothTriangleWave( half4 x ) | |
{ | |
return SmoothCurve( TriangleWave( x ) ); | |
} | |
// This bends the entire plant in the direction of the wind. | |
// vPos: The world position of the plant *relative* to the base of the plant. | |
// (That means we assume the base is at (0, 0, 0). Ensure this before calling this function). | |
// vWind: The current direction and strength of the wind. | |
// fBendScale: How much this plant is affected by the wind. | |
void ApplyMainBending(inout float3 vPosWS, half2 vWind, half fBendScale) | |
{ | |
// Calculate the length from the ground, since we'll need it. | |
float fLength = length(vPosWS); | |
// Bend factor - Wind variation is done on the CPU. | |
float fBF = vPosWS.y * fBendScale; | |
// Smooth bending factor and increase its nearby height limit. | |
fBF += 1.0; | |
fBF *= fBF; | |
fBF = fBF * fBF - fBF; | |
// Displace position | |
float3 vNewPos = vPosWS; | |
vNewPos.xz += vWind.xy * fBF; | |
// Rescale - this keeps the plant parts from "stretching" by shortening the y (height) while | |
// they move about the xz. | |
vPosWS.xyz = normalize(vNewPos.xyz)* fLength; | |
} | |
// This provides "chaotic" motion for leaves and branches (the entire plant, really) | |
void ApplyDetailBending( | |
inout float3 vPosWS, // The final world position of the vertex being modified | |
float3 vNormalWS, // The world normal for this vertex | |
float3 objectPosition, // The world position of the plant instance (same for all vertices) | |
half fDetailPhase, // Optional phase for side-to-side. This is used to vary the phase for side-to-side motion | |
half fBranchPhase, // The green vertex channel per Crytek's convention | |
float fTime, // Ever-increasing time value (e.g. seconds ellapsed) | |
half fEdgeAtten, // "Leaf stiffness", red vertex channel per Crytek's convention | |
half fBranchAtten, // "Overall stiffness", *inverse* of blue channel per Crytek's convention | |
half fBranchAmp, // Controls how much up and down | |
half fSpeed, // Controls how quickly the leaf oscillates | |
half fDetailFreq, // Same thing as fSpeed (they could really be combined, but I suspect | |
// this could be used to let you additionally control the speed per vertex). | |
half fDetailAmp) // Controls how much back and forth | |
{ | |
// Phases (object, vertex, branch) | |
// fObjPhase: This ensures phase is different for different plant instances, but it should be | |
// the same value for all vertices of the same plant. | |
float fObjPhase = dot(objectPosition.xyz, 1); | |
// In this sample fBranchPhase is always zero, but if you want you could somehow supply a | |
// different phase for each branch. | |
fBranchPhase += fObjPhase; | |
// Detail phase is (in this sample) controlled by the GREEN vertex color. In your modelling program, | |
// assign the same "random" phase color to each vertex in a single leaf/branch so that the whole leaf/branch | |
// moves together. | |
float fVtxPhase = dot(vPosWS.xyz, fDetailPhase + fBranchPhase); | |
float2 vWavesIn = fTime + float2(fVtxPhase, fBranchPhase ); | |
float4 vWaves = (frac( vWavesIn.xxyy * | |
float4(SIDE_TO_SIDE_FREQ1, SIDE_TO_SIDE_FREQ2, UP_AND_DOWN_FREQ1, UP_AND_DOWN_FREQ2) ) * | |
2.0 - 1.0 ) * fSpeed * fDetailFreq; | |
vWaves = SmoothTriangleWave( vWaves ); | |
float2 vWavesSum = vWaves.xz + vWaves.yw; | |
// - fBranchAtten is how restricted this vertex of the leaf/branch is. e.g. close to the stem | |
// it should be 0 (maximum stiffness). At the far outer edge it might be 1. | |
// In this sample, this is controlled by the blue vertex color. | |
// - fEdgeAtten controls movement in the plane of the leaf/branch. It is controlled by the | |
// red vertex color in this sample. It is supposed to represent "leaf stiffness". Generally, it | |
// should be 0 in the middle of the leaf (maximum stiffness), and 1 on the outer edges. | |
// - Note that this is different from the Crytek code, in that we use vPosWS.xzy instead of vPosWS.xyz, | |
// because I treat y as the up-and-down direction. | |
vPosWS.xyz += vWavesSum.x * float3(fEdgeAtten * fDetailAmp * vNormalWS.xyz); | |
vPosWS.y += vWavesSum.y * fBranchAtten * fBranchAmp; | |
} | |
void CalculateFoliageWindDeformation_float(float3 positionWS, half3 normalWS, half4 vertexColor, half2 windSpeed, half bendScale, half branchAmplitude, half detailAmplitude, out float3 positionWSWind) | |
{ | |
float3 vPosWS = positionWS; | |
float3 objectPositionWS = mul(unity_ObjectToWorld, float4(0, 0, 0, 1)); // find the offset to the pivot/origin | |
vPosWS -= objectPositionWS;// Reset the vertex to base-zero | |
ApplyMainBending(vPosWS, windSpeed, bendScale); | |
vPosWS += objectPositionWS; // Restore it. | |
half windStrength = length(windSpeed); | |
ApplyDetailBending( | |
vPosWS, | |
normalWS, | |
objectPositionWS, | |
0, // Leaf phase - not used in this scenario, but would allow for variation in side-to-side motion | |
vertexColor.g, // Branch phase - should be the same for all verts in a leaf/branch. | |
_Time.x, | |
vertexColor.r, // edge attenuation, leaf stiffness | |
vertexColor.b, // branch attenuation. High values close to stem, low values furthest from stem. | |
// For some reason, Crysis uses solid blue for non-moving, and black for most movement. | |
// So we invert the blue value here. | |
branchAmplitude * windStrength, // branch amplitude. Play with this until it looks good. | |
2, // Speed. Play with this until it looks good. | |
1, // Detail frequency. Keep this at 1 unless you want to have different per-leaf frequency | |
detailAmplitude * windStrength // Detail amplitude. Play with this until it looks good. | |
); | |
positionWSWind = vPosWS.xyz; | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is a basic implementation of the Crytek wind deformation system for foliage, as outlined in GPU Gems 3. I use this in combination with trees from http://www.evolved-software.com/treeit/treeit and the code itself is a port of some shader code from https://mtnphil.wordpress.com/2011/10/18/wind-animations-for-vegetation/