GraphicsSpriteMesh.ts 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /** @format */
  2. // author: http://lamyoung.com/
  3. const {ccclass, property, requireComponent} = cc._decorator
  4. @ccclass
  5. @requireComponent(cc.Graphics)
  6. export default class GraphicsSpriteMesh extends cc.Component {
  7. @property(cc.Sprite)
  8. sprite: cc.Sprite = null
  9. graphics: cc.Graphics = null
  10. private _vertices: {x: number[]; y: number[]; nu: number[]; nv: number[]; triangles: number[]} = {
  11. x: [],
  12. y: [],
  13. nu: [],
  14. nv: [],
  15. triangles: [],
  16. }
  17. onLoad() {
  18. this.graphics = this.node.getComponent(cc.Graphics)
  19. this.sprite.type = cc.Sprite.Type.MESH
  20. this.sprite.node.anchorY = 1
  21. this.sprite.node.anchorX = 0
  22. this.sprite.node.scaleY = -1
  23. this.sprite.node.x = this.node.y = 0
  24. this.sprite.spriteFrame['vertices'] = this._vertices
  25. }
  26. stroke() {
  27. if (cc.game.renderType === cc.game.RENDER_TYPE_WEBGL) {
  28. const vertices = this._vertices
  29. vertices.x.length = vertices.y.length = vertices.nu.length = vertices.nv.length = vertices.triangles.length = 0
  30. const _impl = this.graphics['_impl']
  31. // const _assembler = this.graphics['_assembler'];
  32. // cc.log(_impl);
  33. const w = this.graphics.lineWidth
  34. const uv_mul = 1 / 50
  35. let trianglesCache: number[][] = []
  36. let offsetX = cc.v2() // 记录每节长度
  37. for (let index = 0; index < _impl._paths.length; index++) {
  38. const path = _impl._paths[index]
  39. const pathPoints = path.points
  40. // cc.log(index, path);
  41. if (pathPoints.length < 2) continue
  42. for (let index2 = pathPoints.length - 1; index2 > 0; index2--) {
  43. let triangles: number[] = []
  44. const p = cc.v2(pathPoints[index2].x, pathPoints[index2].y) // 当前点
  45. const p_pre = cc.v2(pathPoints[index2 - 1].x, pathPoints[index2 - 1].y) //上一个点
  46. const dir = p.sub(p_pre) //方向
  47. const cross_dir = (dir.y == 0 ? cc.v2(0, 1) : cc.v2(1, -dir.x / dir.y).normalize()).mulSelf(w / 2) //垂直方向
  48. const p_r_t = p.add(cross_dir) //右上
  49. const p_r_b = p.sub(cross_dir) // 右下
  50. const p_l_t = p_pre.add(cross_dir) // 左上
  51. const p_l_b = p_pre.sub(cross_dir) // 左下
  52. // 当前线段长度
  53. const dirLen = dir.len()
  54. // 画长方形
  55. let i_offset = vertices.x.length
  56. vertices.x.push(p_r_t.x, p_r_b.x, p_l_t.x, p_l_b.x)
  57. vertices.y.push(p_r_t.y, p_r_b.y, p_l_t.y, p_l_b.y)
  58. // 计算长方形的uv
  59. vertices.nu.push(
  60. offsetX.x * uv_mul,
  61. offsetX.x * uv_mul,
  62. (offsetX.x + dirLen) * uv_mul,
  63. (offsetX.x + dirLen) * uv_mul,
  64. )
  65. vertices.nv.push(1, 0, 1, 0)
  66. triangles.push(i_offset + 0)
  67. triangles.push(i_offset + 1)
  68. triangles.push(i_offset + 2)
  69. triangles.push(i_offset + 1)
  70. triangles.push(i_offset + 2)
  71. triangles.push(i_offset + 3)
  72. //画圆
  73. const dir_angle = dir.signAngle(cc.v2(-1, 0)) //与x轴的负方向的夹角
  74. const count = 12
  75. i_offset = vertices.x.length
  76. // 这里是圆心
  77. vertices.x.push(p.x)
  78. vertices.y.push(p.y)
  79. vertices.nu.push(offsetX.x * uv_mul)
  80. vertices.nv.push(0.5)
  81. for (let index3 = 0; index3 < count; index3++) {
  82. const r = (2 * Math.PI * index3) / count
  83. // 圆心到各个边的向量
  84. const pos_circle = cc.v2((w / 2) * Math.cos(r), (w / 2) * Math.sin(r))
  85. vertices.x.push(pos_circle.add(p).x)
  86. vertices.y.push(pos_circle.add(p).y)
  87. // 对于圆的uv需要旋转
  88. vertices.nu.push((pos_circle.rotate(dir_angle).x + offsetX.x) * uv_mul)
  89. vertices.nv.push(pos_circle.rotate(dir_angle).y / w + 0.5)
  90. if (index3 === 0) {
  91. triangles.push(i_offset, i_offset + 1 + index3, i_offset + count)
  92. } else {
  93. triangles.push(i_offset, i_offset + 1 + index3, i_offset + index3)
  94. }
  95. }
  96. trianglesCache.push(triangles)
  97. offsetX.addSelf(cc.v2(dirLen, 0)) // 记录已经画的长度长度
  98. }
  99. }
  100. trianglesCache.reverse() // 顶点索引反转
  101. trianglesCache.forEach(v => {
  102. // 真正的顶点索引顺序
  103. vertices.triangles.push(...v)
  104. })
  105. // cc.log(vertices);
  106. this.sprite['setVertsDirty']()
  107. // this.graphics.stroke();
  108. } else {
  109. this.graphics.stroke()
  110. }
  111. }
  112. clear() {
  113. this.graphics.clear(true)
  114. if (cc.game.renderType === cc.game.RENDER_TYPE_WEBGL) {
  115. const vertices = this._vertices
  116. vertices.x.length = vertices.y.length = vertices.nu.length = vertices.nv.length = vertices.triangles.length = 0
  117. this.sprite['setVertsDirty']()
  118. }
  119. }
  120. }
  121. /**
  122. *
  123. *
  124. 前置教程:
  125. [初探精灵中的网格渲染模式 !](https://mp.weixin.qq.com/s/2FcixeoV-Fg-7OodILECeg)
  126. 图文:
  127. part-1: https://mp.weixin.qq.com/s/ozXjdpyid5f2Xwo7uo0MuQ
  128. part-2: https://mp.weixin.qq.com/s/xniwz-a_FI0snWqqPd2NOg
  129. */
  130. // 欢迎关注微信公众号[白玉无冰]
  131. /**
  132. █████████████████████████████████████
  133. █████████████████████████████████████
  134. ████ ▄▄▄▄▄ █▀█ █▄██▀▄ ▄▄██ ▄▄▄▄▄ ████
  135. ████ █ █ █▀▀▀█ ▀▄▀▀▀█▄▀█ █ █ ████
  136. ████ █▄▄▄█ █▀ █▀▀▀ ▀▄▄ ▄ █ █▄▄▄█ ████
  137. ████▄▄▄▄▄▄▄█▄▀ ▀▄█ ▀▄█▄▀ █▄▄▄▄▄▄▄████
  138. ████▄▄ ▄▀▄▄ ▄▀▄▀▀▄▄▄ █ █ ▀ ▀▄█▄▀████
  139. ████▀ ▄ █▄█▀█▄█▀█ ▀▄ █ ▀ ▄▄██▀█████
  140. ████ ▄▀▄▄▀▄ █▄▄█▄ ▀▄▀ ▀ ▀ ▀▀▀▄ █▀████
  141. ████▀ ██ ▀▄ ▄██ ▄█▀▄ ██▀ ▀ █▄█▄▀█████
  142. ████ ▄██▄▀ █▀▄▀▄▀▄▄▄▄ ▀█▀ ▀▀ █▀████
  143. ████ █▄ █ ▄ █▀ █▀▄█▄▄▄▄▀▄▄█▄▄▄▄▀█████
  144. ████▄█▄█▄█▄█▀ ▄█▄ ▀▄██ ▄▄▄ ▀ ████
  145. ████ ▄▄▄▄▄ █▄██ ▄█▀ ▄ █▄█ ▄▀█████
  146. ████ █ █ █ ▄█▄ ▀ ▀▀██ ▄▄▄▄ ▄▀ ████
  147. ████ █▄▄▄█ █ ▄▄▀ ▄█▄█▄█▄ ▀▄ ▄ █████
  148. ████▄▄▄▄▄▄▄█▄██▄▄██▄▄▄█████▄▄█▄██████
  149. █████████████████████████████████████
  150. █████████████████████████████████████
  151. */