dynamic_grass.glslv 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. #ifndef DYNAMIC_GRASS_GLSLV
  2. #define DYNAMIC_GRASS_GLSLV
  3. // #import u_scale_threshold
  4. /*==============================================================================
  5. VARS
  6. ==============================================================================*/
  7. #var PRECISION highp
  8. #var DYNAMIC_GRASS 0
  9. #var BILLBOARD 0
  10. #var GRASS_TEXTURE_SIZE 1024.0
  11. /*============================================================================*/
  12. #if DYNAMIC_GRASS
  13. #include <math.glslv>
  14. #include <to_world.glslv>
  15. // U along X, V along -Z (0..1)
  16. vec2 pos_to_uv(vec3 position, float dim, vec2 base_point)
  17. {
  18. vec2 pos_uv = vec2((position.x - base_point.x) / dim,
  19. (position.y - base_point.y) / dim);
  20. return fract(pos_uv);
  21. }
  22. vec2 uv_to_pos(vec2 uv, float dim, vec2 base_point)
  23. {
  24. return vec2(uv.x * dim, uv.y * dim) + base_point;
  25. }
  26. // compose infinity vertex
  27. vertex infinity_vertex()
  28. {
  29. return vertex(vec3(-10000.0), vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0),
  30. vec3(0.0), vec3(0.0));
  31. }
  32. #if GLSL3
  33. vec4 texture2D_linear(sampler2D texture_sampler, vec2 tex_coord) {
  34. float grass_texel_size = 1.0 / GRASS_TEXTURE_SIZE;
  35. vec4 x_0_y_0 = GLSL_TEXTURE(texture_sampler, tex_coord);
  36. vec4 x_1_y_0 = GLSL_TEXTURE(texture_sampler, tex_coord + vec2(grass_texel_size, 0.0));
  37. vec4 x_0_y_1 = GLSL_TEXTURE(texture_sampler, tex_coord + vec2(0.0, grass_texel_size));
  38. vec4 x_1_y_1 = GLSL_TEXTURE(texture_sampler, tex_coord + vec2(grass_texel_size, grass_texel_size));
  39. float a = fract(tex_coord.x * GRASS_TEXTURE_SIZE);
  40. vec4 x_int_y_0 = mix(x_0_y_0, x_1_y_0, a);
  41. vec4 x_int_y_1 = mix(x_0_y_1, x_1_y_1, a);
  42. float b = fract(tex_coord.y * GRASS_TEXTURE_SIZE);
  43. return mix(x_int_y_0, x_int_y_1, b);
  44. }
  45. #endif
  46. // Translate grass vertex from local to world space using grass maps
  47. vertex grass_vertex(vec3 position, vec3 tangent, vec3 shade_tan, vec3 binormal,
  48. vec3 normal, vec3 center, PRECISION sampler2D grass_map_depth,
  49. sampler2D grass_map_color, vec3 grass_map_dim, float grass_size,
  50. vec3 camera_eye, vec4 camera_quat, mat3 view_tsr)
  51. {
  52. // get camera view angles
  53. vec3 cam_view = qrot(camera_quat, vec3(0.0, 0.0, -1.0));
  54. float sin_alpha = -cam_view.x;
  55. float cos_alpha = cam_view.y;
  56. // get world position of base point ([0.0, 0.0] (left lower) on UV)
  57. vec2 base_point =vec2(camera_eye.x - grass_size * (1.0 + sin_alpha) / 2.0,
  58. camera_eye.y - grass_size * (1.0 - cos_alpha) / 2.0);
  59. vec2 cen_uv = pos_to_uv(center, grass_size, base_point);
  60. // rounding grass plane
  61. float grass_edge_length = grass_size / 2.0;
  62. vec2 pos_from_map_center = abs(uv_to_pos(cen_uv - vec2(0.5), grass_size, vec2(0.0)));
  63. float max_radius = grass_edge_length * (1.0 + sqrt(2.0)) / 2.0;
  64. if (length(pos_from_map_center) > max_radius)
  65. return infinity_vertex();
  66. // for map sampling scale uv coords according to BATCH/MAP size ratio
  67. float map_size_mult = grass_size / grass_map_dim.z;
  68. vec2 cen_uv_scaled = (cen_uv - vec2(0.5)) * map_size_mult + vec2(0.5);
  69. vec3 grass_map_trans = cam_view * (grass_size / grass_map_dim.z - 1.0) / 2.0;
  70. cen_uv_scaled.x += grass_map_trans.x;
  71. cen_uv_scaled.y += grass_map_trans.y;
  72. // remove short grass
  73. vec4 scale_color = GLSL_TEXTURE(grass_map_color, cen_uv_scaled);
  74. float scale = scale_color.r;
  75. if (scale < u_scale_threshold)
  76. return infinity_vertex();
  77. // (DELTA = (HIGH - LOW)) > 0
  78. float height_delta = grass_map_dim.y - grass_map_dim.x;
  79. // in world space: HIGH - MAP * DELTA
  80. #if GLSL3
  81. float height = grass_map_dim.y -
  82. (texture2D_linear(grass_map_depth, cen_uv_scaled)).r * height_delta;
  83. #else
  84. float height = grass_map_dim.y -
  85. (GLSL_TEXTURE(grass_map_depth, cen_uv_scaled)).r * height_delta;
  86. #endif
  87. // calculate new center and position
  88. vec2 pos_cen_delta = position.xy - center.xy;
  89. center.xy = uv_to_pos(cen_uv, grass_size, base_point);
  90. center.z = height;
  91. position.xy = center.xy + pos_cen_delta;
  92. // scale only grass height for now
  93. position.z *= scale;
  94. position.z += height;
  95. vec3 color = scale_color.gba;
  96. # if BILLBOARD
  97. // NOTE: position in local space: position - center
  98. position -= center;
  99. mat3 bill_tsr = billboard_tsr(camera_eye, center, view_tsr);
  100. vertex world = to_world(position, center, tangent, shade_tan, binormal,
  101. normal, bill_tsr);
  102. world.center = center;
  103. world.color = color;
  104. return tbn_norm(world);
  105. # else
  106. return tbn_norm(vertex(position, center, tangent, shade_tan, binormal, normal,
  107. color));
  108. # endif
  109. }
  110. #endif
  111. #endif