builtin-sprite.effect 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // Copyright (c) 2017-2020 Xiamen Yaji Software Co., Ltd.
  2. CCEffect %{
  3. techniques:
  4. - passes:
  5. - vert: sprite-vs:vert
  6. frag: sprite-fs:frag
  7. depthStencilState:
  8. depthTest: false
  9. depthWrite: false
  10. blendState:
  11. targets:
  12. - blend: true
  13. blendSrc: src_alpha
  14. blendDst: one_minus_src_alpha
  15. blendDstAlpha: one_minus_src_alpha
  16. rasterizerState:
  17. cullMode: none
  18. properties:
  19. edgeColor: { value: [1.0, 1.0, 1.0, 1.0] }
  20. textureSize: { value: [512.0, 512.0] }
  21. edgeWidth: { value: 50.0 }
  22. alphaThreshold: { value: 0.5 }
  23. }%
  24. CCProgram sprite-vs %{
  25. precision highp float;
  26. #include <builtin/uniforms/cc-global>
  27. #if USE_LOCAL
  28. #include <builtin/uniforms/cc-local>
  29. #endif
  30. #if SAMPLE_FROM_RT
  31. #include <common/common-define>
  32. #endif
  33. in vec3 a_position;
  34. in vec2 a_texCoord;
  35. in vec4 a_color;
  36. out vec4 color;
  37. out vec2 uv0;
  38. vec4 vert () {
  39. vec4 pos = vec4(a_position, 1);
  40. #if USE_LOCAL
  41. pos = cc_matWorld * pos;
  42. #endif
  43. #if USE_PIXEL_ALIGNMENT
  44. pos = cc_matView * pos;
  45. pos.xyz = floor(pos.xyz);
  46. pos = cc_matProj * pos;
  47. #else
  48. pos = cc_matViewProj * pos;
  49. #endif
  50. uv0 = a_texCoord;
  51. #if SAMPLE_FROM_RT
  52. CC_HANDLE_RT_SAMPLE_FLIP(uv0);
  53. #endif
  54. color = a_color;
  55. return pos;
  56. }
  57. }%
  58. CCProgram sprite-fs %{
  59. precision highp float;
  60. #include <builtin/internal/embedded-alpha>
  61. #include <builtin/internal/alpha-test>
  62. #define MAX_EDGE_WIDTH 50.0 // 最大边缘宽度(可根据需求调整)
  63. in vec4 color;
  64. #if USE_TEXTURE
  65. in vec2 uv0;
  66. #pragma builtin(local)
  67. layout(set = 2, binding = 12) uniform sampler2D cc_spriteTexture;
  68. #endif
  69. uniform EdgeUniforms {
  70. vec4 edgeColor;
  71. vec2 textureSize;
  72. float edgeWidth;
  73. };
  74. vec4 frag () {
  75. vec4 o = vec4(1, 1, 1, 1);
  76. #if USE_TEXTURE
  77. o *= CCSampleWithAlphaSeparated(cc_spriteTexture, uv0);
  78. // Edge detection based on alpha channel
  79. vec2 texelSize = 1.0 / textureSize;
  80. float currentAlpha = o.a;
  81. // Sample surrounding pixels to detect edge
  82. float edgeDetected = 0.0;
  83. if (currentAlpha > 0.01) {
  84. // Check if we're at the edge by sampling neighboring pixels
  85. float maxDistance = min(edgeWidth, MAX_EDGE_WIDTH);
  86. bool isEdge = false;
  87. // Check boundary conditions first (image edges)
  88. vec2 pixelPos = uv0 * textureSize;
  89. float distToLeft = pixelPos.x;
  90. float distToRight = textureSize.x - pixelPos.x;
  91. float distToTop = pixelPos.y;
  92. float distToBottom = textureSize.y - pixelPos.y;
  93. float minDistToBorder = min(min(distToLeft, distToRight), min(distToTop, distToBottom));
  94. if (minDistToBorder <= maxDistance) {
  95. isEdge = true;
  96. edgeDetected = max(edgeDetected, 1.0 - (minDistToBorder / maxDistance));
  97. }
  98. // Also check for alpha transitions
  99. if (!isEdge) {
  100. // 改为固定范围循环(-MAX_EDGE_WIDTH 到 MAX_EDGE_WIDTH)
  101. for (float x = -MAX_EDGE_WIDTH; x <= MAX_EDGE_WIDTH; x += 1.0) {
  102. for (float y = -MAX_EDGE_WIDTH; y <= MAX_EDGE_WIDTH; y += 1.0) {
  103. if (x == 0.0 && y == 0.0) continue;
  104. vec2 sampleUV = uv0 + vec2(x, y) * texelSize;
  105. float sampleAlpha = CCSampleWithAlphaSeparated(cc_spriteTexture, sampleUV).a;
  106. // If we find a transparent pixel nearby, we're at an edge
  107. if (sampleAlpha < 0.01) {
  108. float distance = length(vec2(x, y));
  109. if (distance <= maxDistance) {
  110. float edgeStrength = 1.0 - (distance / maxDistance);
  111. edgeDetected = max(edgeDetected, edgeStrength);
  112. isEdge = true;
  113. }
  114. }
  115. }
  116. }
  117. }
  118. }
  119. // Apply edge effect
  120. if (edgeDetected > 0.0) {
  121. o.rgb = mix(o.rgb, edgeColor.rgb, edgeDetected * edgeColor.a);
  122. }
  123. #endif
  124. o *= color;
  125. ALPHA_TEST(o);
  126. return o;
  127. }
  128. }%