main.lua 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. local function knot(u, p, q, r)
  2. local c1, s1 = math.cos(u), math.sin(u)
  3. local c2, s2 = math.cos(q / p * u), math.sin(q / p * u)
  4. return
  5. r * (2 + c2) * .5 * c1,
  6. r * (2 + c2) * .5 * s1,
  7. r * s2 * .5
  8. end
  9. points = {}
  10. local ct = 300
  11. local p, q, r = 2, 3, 1
  12. for t = 0, ct do
  13. local th = t / ct * p * 2 * math.pi
  14. local x, y, z = knot(th, p, q, r)
  15. table.insert(points, x)
  16. table.insert(points, y)
  17. table.insert(points, z)
  18. end
  19. local quads = {}
  20. local indexData = { 0,1,2, 2,1,3 ; 1,5,3, 3,5,7 }
  21. for i = 1, ct do
  22. for j = 1, #indexData do
  23. table.insert(quads, (i - 1) * 8 + indexData[j])
  24. end
  25. end
  26. local vertices = lovr.graphics.newBuffer('float', points)
  27. local indices = lovr.graphics.newBuffer('u16', quads)
  28. local shader = lovr.graphics.newShader([[
  29. readonly buffer Points { float data[]; };
  30. flat out vec3 head;
  31. flat out vec3 tail;
  32. flat out vec4 headColor;
  33. flat out vec4 tailColor;
  34. out float width;
  35. vec3 hsv2rgb(vec3 c) {
  36. vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
  37. vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
  38. return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
  39. }
  40. vec4 lovrmain() {
  41. uint p = 3 * (VertexIndex >> 3);
  42. head = vec3(ViewFromLocal * vec4(data[p + 0], data[p + 1], data[p + 2], 1.));
  43. tail = vec3(ViewFromLocal * vec4(data[p + 3], data[p + 4], data[p + 5], 1.));
  44. vec4 headClip = ClipFromView * vec4(head, 1.);
  45. vec4 tailClip = ClipFromView * vec4(tail, 1.);
  46. vec3 mid = mix(head, tail, .5);
  47. vec3 az = normalize(tail - head);
  48. vec3 a_ = normalize(cross(az, mid));
  49. vec3 ax = normalize(cross(az, a_));
  50. vec3 ay = normalize(cross(az, ax));
  51. float x = (VertexIndex & 0x1) >> 0;
  52. float y = (VertexIndex & 0x2) >> 1;
  53. float z = (VertexIndex & 0x4) >> 2;
  54. if (dot(mid, ax) > 0.) x = 1. - x;
  55. if (dot(mid, az) < 0.) z = 1. - z;
  56. width = .4;
  57. float w = mix(headClip.w, tailClip.w, z);
  58. if (w > 0.) {
  59. float minPixelWidth = 1.;
  60. width = max(width, Projection[0][0] * w * (minPixelWidth / Resolution.x));
  61. }
  62. vec3 local = vec3(x - .5, y - .5, z);
  63. mat3 basis = mat3(ax * width, ay * width, az * (length(tail - head) + width));
  64. vec3 start = head - az * width * .5;
  65. PositionWorld = start + basis * local;
  66. headColor = vec4(hsv2rgb(vec3(float(p/3 + 0) / 101., 1, 1)), 1.);
  67. tailColor = vec4(hsv2rgb(vec3(float(p/3 + 1) / 101., 1, 1)), 1.);
  68. return ClipFromView * vec4(PositionWorld, 1.);
  69. }
  70. ]], [[
  71. flat in vec3 head;
  72. flat in vec3 tail;
  73. flat in vec4 headColor;
  74. flat in vec4 tailColor;
  75. in float width;
  76. layout(depth_less) out float FragDepth;
  77. vec4 lovrmain() {
  78. vec3 A = tail - head;
  79. vec3 B = head;
  80. float AoA = dot(A, A);
  81. float AoB = dot(A, B);
  82. float BoB = dot(B, B);
  83. float r = width * .5;
  84. int coverage = 0;
  85. float param;
  86. for (int i = 0; i < 4; i++) {
  87. vec3 N = normalize(interpolateAtSample(PositionWorld, i));
  88. float NoA = dot(N, A);
  89. float NoB = dot(N, B);
  90. float a = AoA - NoA * NoA;
  91. float t1 = clamp((NoB * NoA - AoB) / a, 0., 1.);
  92. float t2 = t1 * NoA + NoB;
  93. float dist = distance(N * t2, head + A * t1);
  94. if (dist <= r) {
  95. coverage |= (1 << i);
  96. param = t1;
  97. }
  98. }
  99. gl_SampleMask[0] = coverage;
  100. if (coverage == 0) {
  101. discard;
  102. }
  103. vec3 N = normalize(PositionWorld);
  104. B = -head;
  105. AoB = dot(A, B);
  106. BoB = dot(B, B);
  107. float NoA = dot(N, A);
  108. float NoB = dot(N, B);
  109. // Quadratic formula
  110. float a = AoA - NoA * NoA;
  111. float b = AoA * NoB - AoB * NoA;
  112. float c = AoA * BoB - AoB * AoB - r * r * AoA;
  113. float d = max(b * b - a * c, 0.);
  114. float t1 = (-b - sqrt(d)) / a;
  115. float t2 = (AoB + t1 * NoA) / AoA;
  116. // If the hit is outside the cylindrical part of the capsule, see if it intersects the end caps
  117. if (t2 <= 0. || t2 >= 1.) {
  118. vec3 C = t2 <= 0. ? B : -tail;
  119. b = dot(N, C);
  120. c = dot(C, C) - r * r;
  121. d = max(b * b - c, 0.);
  122. t1 = -b - sqrt(d);
  123. }
  124. vec3 P = N * t1;
  125. vec4 clip = Projection * vec4(P, 1.);
  126. FragDepth = clip.z / clip.w;
  127. return Color * mix(headColor, tailColor, clamp(t2, 0., 1.));
  128. }
  129. ]])
  130. function lovr.draw(pass)
  131. pass:push()
  132. pass:translate(0, 1.7, -3)
  133. pass:rotate(lovr.timer.getTime() / 3, 0, 1, 0)
  134. pass:setShader(shader)
  135. pass:send('Points', vertices)
  136. pass:mesh(nil, indices)
  137. pass:pop()
  138. end