HLSL Code
Custom Expression Node Code
// WIND SYSTEM - RΓ©aliste avec 3 axes fonctionnels
// Inputs: WorldPos, WindDir, WindStr, WindSpd, GustStr, GustFreq, GustScale, TurbScale, TurbInt, TurbSpd, WindScale, TrunkBend, TreeHeight, FlexMask, TimeVal
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// TURBULENCE - NE PAS TOUCHER (fonctionne bien)
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
float turbPhase1 = sin(TimeVal * TurbSpd + WorldPos.x * TurbScale);
float turbPhase2 = sin(TimeVal * TurbSpd * 0.7 + WorldPos.y * TurbScale * 1.5);
float turbSwayX = (turbPhase1 + turbPhase2 * 0.5) * TurbInt;
float turbPhase3 = sin(TimeVal * TurbSpd * 1.3 + WorldPos.y * TurbScale);
float turbPhase4 = sin(TimeVal * TurbSpd * 0.9 + WorldPos.x * TurbScale * 1.2);
float turbSwayY = (turbPhase3 + turbPhase4 * 0.5) * TurbInt;
float turbPhase5 = sin(TimeVal * TurbSpd * 1.1 + WorldPos.z * TurbScale * 0.5);
float turbSwayZ = turbPhase5 * TurbInt * 0.5;
float3 turbulence = float3(turbSwayX, turbSwayY, turbSwayZ);
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// PRIMARY WIND - Mouvement rΓ©aliste sur 3 axes
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// Convertir WindScale en frΓ©quence spatiale (0.01 = global, 0.25 = local)
float spatialFreq = WindScale * 100.0;
// Oscillation principale (contrΓ΄lΓ©e par WindStr et WindSpd)
float windPhase1 = sin(TimeVal * WindSpd * 3.14159 + WorldPos.x * spatialFreq * 0.01 + WorldPos.y * spatialFreq * 0.007);
float windPhase2 = sin(TimeVal * WindSpd * 2.5 + WorldPos.y * spatialFreq * 0.012 + WorldPos.x * spatialFreq * 0.005);
// Combiner les phases (oscillation -1 Γ 1)
float windOscillation = (windPhase1 * 0.6 + windPhase2 * 0.4);
// Appliquer WindStr (si WindStr = 0, pas de vent)
float windIntensity = windOscillation * WindStr;
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// GUST - Rafales multicouches (jamais statique)
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// Convertir GustScale en frΓ©quence spatiale
float gustSpatialFreq = GustScale * 100.0;
// COUCHE 1 - Gust principal (vague lente) avec variation Z
float gust1Phase = sin(WorldPos.x * gustSpatialFreq * 0.01 + WorldPos.y * gustSpatialFreq * 0.007 + WorldPos.z * gustSpatialFreq * 0.005 - TimeVal * GustFreq * 6.28);
float gust1Intensity = (gust1Phase * 0.5 + 0.5) * 0.4; // 0 Γ 0.4
// COUCHE 2 - Gust secondaire (vague moyenne) avec variation Z
float gust2Phase = sin(WorldPos.y * gustSpatialFreq * 0.015 - WorldPos.x * gustSpatialFreq * 0.01 + WorldPos.z * gustSpatialFreq * 0.008 - TimeVal * GustFreq * 4.7 + 1.3);
float gust2Intensity = (gust2Phase * 0.5 + 0.5) * 0.3; // 0 Γ 0.3
// COUCHE 3 - Gust tertiaire (vague rapide) avec variation Z
float gust3Phase = sin(WorldPos.x * gustSpatialFreq * 0.02 + WorldPos.y * gustSpatialFreq * 0.018 + WorldPos.z * gustSpatialFreq * 0.012 - TimeVal * GustFreq * 9.5 + 2.7);
float gust3Intensity = (gust3Phase * 0.5 + 0.5) * 0.2; // 0 Γ 0.2
// COUCHE 4 - Gust de base (toujours prΓ©sent)
float gust4Phase = sin(TimeVal * GustFreq * 0.37 + 1.2);
float gust4Intensity = (gust4Phase * 0.5 + 0.5) * 0.1; // 0 Γ 0.1
// Combiner toutes les couches (jamais Γ 0, minimum 0.1)
float gustIntensityBase = gust1Intensity + gust2Intensity + gust3Intensity + gust4Intensity;
// Variation d'intensitΓ© globale (battements)
float gustBeat1 = sin(TimeVal * GustFreq * 0.53 + 2.8) * 0.2 + 0.8; // 0.6 Γ 1.0
float gustBeat2 = sin(TimeVal * GustFreq * 0.71 + 4.1) * 0.15 + 0.85; // 0.7 Γ 1.0
// IntensitΓ© finale
float gustIntensity = gustIntensityBase * gustBeat1 * gustBeat2 * GustStr;
// DIRECTION LOCALE VARIABLE (change selon position ET temps)
// Direction principale (temporelle)
float gustDirTime1 = sin(TimeVal * GustFreq * 0.41);
float gustDirTime2 = sin(TimeVal * GustFreq * 0.67 + 1.7);
float gustDirTime3 = sin(TimeVal * GustFreq * 0.29 + 2.3);
// Direction locale (spatiale) avec variation Z
float gustDirLocal1 = sin(WorldPos.x * gustSpatialFreq * 0.005 + WorldPos.y * gustSpatialFreq * 0.003 + WorldPos.z * gustSpatialFreq * 0.004);
float gustDirLocal2 = sin(WorldPos.y * gustSpatialFreq * 0.006 - WorldPos.x * gustSpatialFreq * 0.004 + WorldPos.z * gustSpatialFreq * 0.003 + 1.5);
float gustDirLocal3 = sin((WorldPos.x + WorldPos.y) * gustSpatialFreq * 0.004 + WorldPos.z * gustSpatialFreq * 0.005 + 2.8);
// Combiner direction temporelle et locale
float3 gustDirection = normalize(float3(
(gustDirTime1 * 0.6 + gustDirLocal1 * 0.4) * 0.7 + 0.3, // Bias positif
(gustDirTime2 * 0.6 + gustDirLocal2 * 0.4) * 0.6,
(gustDirTime3 * 0.6 + gustDirLocal3 * 0.4) * 0.3 // Moins vertical
));
// Mouvement du gust avec direction variable
float3 gustMovement = gustDirection * gustIntensity;
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// PRIMARY WIND - Appliquer direction
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// Normaliser WindDir pour avoir une direction unitaire
float3 windDir = normalize(WindDir);
// CrΓ©er le mouvement 3D dans la direction du vent
float3 windMovement = float3(
windDir.x * windIntensity, // Mouvement X (gauche-droite)
windDir.y * windIntensity, // Mouvement Y (avant-arrière)
windDir.z * windIntensity // Mouvement Z (haut-bas)
);
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// TRUNK BENDING - Mouvement des branches (plus rapide, moins distordu)
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// Calculer gradient de hauteur (0 = base, 1 = sommet)
float heightGradient = saturate(WorldPos.z / TreeHeight);
// Gradient exponentiel (base rigide, sommet flexible)
float trunkFlexibility = pow(heightGradient, 2.0);
// Trunk bend - Encore plus rapide (1.0), amplitude rΓ©duite
float trunkPhase1 = sin(TimeVal * WindSpd * 1.0 + WorldPos.x * 0.01);
float trunkPhase2 = sin(TimeVal * WindSpd * 0.8 + WorldPos.y * 0.008 + 1.5);
float trunkBendAmount = (trunkPhase1 * 0.7 + trunkPhase2 * 0.3);
// RΓ©duire l'amplitude pour moins de distorsion (divisΓ© par 10)
float3 trunkBendOffset = windDir * trunkBendAmount * (TrunkBend * 0.1) * trunkFlexibility;
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// COMBINE & APPLY
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// Combiner tous les mouvements
float3 combinedMovement = windMovement + gustMovement + trunkBendOffset;
// Appliquer FlexMask
combinedMovement *= FlexMask;
// Ajouter turbulence (toujours prΓ©sente)
float3 finalOffset = combinedMovement + turbulence;
return finalOffset;
βοΈ Setup Instructions
1. Create a Custom Expression node in your material
2. Set Output Type to Float3
3. Add all 15 inputs listed below
4. Connect output to World Position Offset
2. Set Output Type to Float3
3. Add all 15 inputs listed below
4. Connect output to World Position Offset
Custom Expression Inputs (15 Total)
Input 0: WorldPos
Vector3
Connect: Absolute World Position node
Input 1: WindDir
Vector3
Parameter: Wind Direction (default: 1, 0, 0)
Input 2: WindStr
Float
Parameter: Wind Strength (0-5.5)
Input 3: WindSpd
Float
Parameter: Wind Speed (0-2.0)
Input 4: GustStr
Float
Parameter: Gust Strength (0-10.0)
Input 5: GustFreq
Float
Parameter: Gust Frequency (0-1.7)
Input 6: GustScale
Float
Parameter: Gust Scale (0-0.25)
Input 7: TurbScale
Float
Parameter: Turbulence Scale (0-100)
Input 8: TurbInt
Float
Parameter: Turbulence Intensity (0-1.0)
Input 9: TurbSpd
Float
Parameter: Turbulence Speed (0-15)
Input 10: WindScale
Float
Parameter: Wind Scale (0-0.25)
Input 11: TrunkBend
Float
Parameter: Trunk Bending (0-100)
Input 12: TreeHeight
Float
Parameter: Tree Height (e.g., 500)
Input 13: FlexMask
Float
Connect: Vertex Color (R channel)
Input 14: TimeVal
Float
Connect: Time node