#ifndef SPEEDTREE_VERTEX_INCLUDED #define SPEEDTREE_VERTEX_INCLUDED /////////////////////////////////////////////////////////////////////// // SpeedTree v6 Vertex Processing /////////////////////////////////////////////////////////////////////// // struct SpeedTreeVB // texcoord setup // // BRANCHES FRONDS LEAVES // 0 diffuse uv, branch wind xy " " // 1 lod xyz, 0 lod xyz, 0 anchor xyz, lod scalar // 2 detail/seam uv, seam amount, 0 frond wind xyz, 0 leaf wind xyz, leaf group struct SpeedTreeVB { float4 vertex : POSITION; float4 tangent : TANGENT; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; float4 texcoord1 : TEXCOORD1; float4 texcoord2 : TEXCOORD2; float2 texcoord3 : TEXCOORD3; half4 color : COLOR; UNITY_VERTEX_INPUT_INSTANCE_ID }; /////////////////////////////////////////////////////////////////////// // SpeedTree winds #ifdef ENABLE_WIND #define WIND_QUALITY_NONE 0 #define WIND_QUALITY_FASTEST 1 #define WIND_QUALITY_FAST 2 #define WIND_QUALITY_BETTER 3 #define WIND_QUALITY_BEST 4 #define WIND_QUALITY_PALM 5 uniform half _WindQuality; uniform half _WindEnabled; #include "SpeedTreeWind.cginc" #endif /////////////////////////////////////////////////////////////////////// // OffsetSpeedTreeVertex void OffsetSpeedTreeVertex(inout SpeedTreeVB data, float lodValue) { float3 finalPosition = data.vertex.xyz; #ifdef ENABLE_WIND half windQuality = _WindQuality * _WindEnabled; float3 rotatedWindVector, rotatedBranchAnchor; if (windQuality <= WIND_QUALITY_NONE) { rotatedWindVector = float3(0.0f, 0.0f, 0.0f); rotatedBranchAnchor = float3(0.0f, 0.0f, 0.0f); } else { // compute rotated wind parameters rotatedWindVector = normalize(mul(_ST_WindVector.xyz, (float3x3)unity_ObjectToWorld)); rotatedBranchAnchor = normalize(mul(_ST_WindBranchAnchor.xyz, (float3x3)unity_ObjectToWorld)) * _ST_WindBranchAnchor.w; } #endif #if defined(GEOM_TYPE_BRANCH) || defined(GEOM_TYPE_FROND) // smooth LOD #ifdef LOD_FADE_PERCENTAGE finalPosition = lerp(finalPosition, data.texcoord1.xyz, lodValue); #endif // frond wind, if needed #if defined(ENABLE_WIND) && defined(GEOM_TYPE_FROND) if (windQuality == WIND_QUALITY_PALM) finalPosition = RippleFrond(finalPosition, data.normal, data.texcoord.x, data.texcoord.y, data.texcoord2.x, data.texcoord2.y, data.texcoord2.z); #endif #elif defined(GEOM_TYPE_LEAF) // remove anchor position finalPosition -= data.texcoord1.xyz; bool isFacingLeaf = data.color.a == 0; if (isFacingLeaf) { #ifdef LOD_FADE_PERCENTAGE finalPosition *= lerp(1.0, data.texcoord1.w, lodValue); #endif // face camera-facing leaf to camera float offsetLen = length(finalPosition); finalPosition = mul(finalPosition.xyz, (float3x3)UNITY_MATRIX_IT_MV); // inv(MV) * finalPosition finalPosition = normalize(finalPosition) * offsetLen; // make sure the offset vector is still scaled } else { #ifdef LOD_FADE_PERCENTAGE float3 lodPosition = float3(data.texcoord1.w, data.texcoord3.x, data.texcoord3.y); finalPosition = lerp(finalPosition, lodPosition, lodValue); #endif } #ifdef ENABLE_WIND // leaf wind if (windQuality > WIND_QUALITY_FASTEST && windQuality < WIND_QUALITY_PALM) { float leafWindTrigOffset = data.texcoord1.x + data.texcoord1.y; finalPosition = LeafWind(windQuality == WIND_QUALITY_BEST, data.texcoord2.w > 0.0, finalPosition, data.normal, data.texcoord2.x, float3(0,0,0), data.texcoord2.y, data.texcoord2.z, leafWindTrigOffset, rotatedWindVector); } #endif // move back out to anchor finalPosition += data.texcoord1.xyz; #endif #ifdef ENABLE_WIND float3 treePos = float3(unity_ObjectToWorld[0].w, unity_ObjectToWorld[1].w, unity_ObjectToWorld[2].w); #ifndef GEOM_TYPE_MESH if (windQuality >= WIND_QUALITY_BETTER) { // branch wind (applies to all 3D geometry) finalPosition = BranchWind(windQuality == WIND_QUALITY_PALM, finalPosition, treePos, float4(data.texcoord.zw, 0, 0), rotatedWindVector, rotatedBranchAnchor); } #endif if (windQuality > WIND_QUALITY_NONE) { // global wind finalPosition = GlobalWind(finalPosition, treePos, true, rotatedWindVector, _ST_WindGlobal.x); } #endif data.vertex.xyz = finalPosition; } #endif // SPEEDTREE_VERTEX_INCLUDED