Advertisement
CirilXD

Godot 3D Real Time Rope Mesh Generator V.1 + UV1 Mapping

Mar 9th, 2024
979
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. @tool
  2. extends MeshInstance3D
  3.  
  4. @export var iterations = 5
  5. @export var dirty = false
  6. @export var resolution = 10
  7.  
  8. var grapple_hook_position : Vector3 = Vector3.ZERO
  9. var player_position : Vector3 = Vector3.ZERO
  10.  
  11. var vertex_array : PackedVector3Array = []
  12. var uv1_array : PackedVector2Array = []
  13. var index_array : PackedInt32Array = []
  14. var normal_array : PackedVector3Array = []
  15.  
  16. var tangent_array : PackedVector3Array = []
  17. var uv_array : PackedVector2Array = []
  18.  
  19. var points : PackedVector3Array = []
  20. var points_old : PackedVector3Array = []
  21.  
  22. @export var point_count = 20
  23.  
  24. var rope_length : float = 0.0
  25. var point_spacing : float = 0.0
  26. @export var rope_width = .02
  27. @export var uv_scale = .5
  28.  
  29. @export var isDrawing = false
  30. @export var firstTime = true
  31.  
  32. @onready var temp_player = $tempPlayer
  33. @onready var temp_hook = $tempHook
  34.  
  35. var texture_height_to_width = 0.5
  36.  
  37. var gravity_default = ProjectSettings.get_setting("physics/3d/default_gravity")
  38.  
  39. # Called when the node enters the scene tree for the first time.
  40. func _ready():
  41.     SetGrappleHookPosition(temp_hook.position)
  42.     SetPlayerPosition(temp_player.position)
  43.     PreparePoints()
  44.     pass # Replace with function body.
  45.  
  46.  
  47. # Called every frame. 'delta' is the elapsed time since the previous frame.
  48. func _process(delta):
  49.     SetPlayerPosition(temp_player.position)
  50. #   SetGrappleHookPosition(temp_hook.position)
  51.    
  52.     if isDrawing || dirty:
  53.         if firstTime:
  54.             PreparePoints()
  55.             firstTime = false
  56.         UpdatePoints(delta)
  57.        
  58.         GenerateMesh()
  59.        
  60.         dirty = false
  61.  
  62. func SetGrappleHookPosition(val : Vector3):
  63.     grapple_hook_position = val
  64.     firstTime = true
  65.  
  66. func SetPlayerPosition(val : Vector3):
  67.     player_position = val
  68.  
  69. func StartDrawing():
  70.     isDrawing = true
  71.    
  72. func StopDrawing():
  73.     isDrawing = false
  74.  
  75. func PreparePoints():
  76.     points.clear()
  77.     points_old.clear()
  78.    
  79.     for i in range(point_count):
  80.         var t = i / (point_count - 1.0)
  81.        
  82.         points.append(lerp(player_position, grapple_hook_position, t))
  83.         points_old.append(points[i])
  84.        
  85.     _UpdatePointSpacing()
  86.    
  87. func _UpdatePointSpacing():
  88.     rope_length = (grapple_hook_position - player_position).length()
  89.     point_spacing = rope_length / (point_count - 1.0)
  90.  
  91. func UpdatePoints(delta):
  92.     points[0] = player_position
  93.     points[point_count-1] = grapple_hook_position
  94.  
  95.     _UpdatePointSpacing()
  96.  
  97.     for i in range(1, point_count - 1):
  98.         var curr : Vector3 = points[i]
  99.         points[i] = points[i] + (points[i] - points_old[i]) + (
  100.             Vector3.DOWN * gravity_default * delta * delta)
  101.         points_old[i] = curr
  102.    
  103.     for i in range(iterations):
  104.         ConstraintConnections()
  105.    
  106. func ConstraintConnections():
  107.     for i in range(point_count - 1):
  108.         var centre : Vector3 = (points[i+1] + points[i]) / 2.0
  109.         var offset : Vector3 = (points[i+1] - points[i])
  110.         var length : float = offset.length()
  111.         var dir : Vector3 = offset.normalized()
  112.        
  113.         var d = length - point_spacing
  114.        
  115.         if i != 0:
  116. #           points[i] = centre + dir * d / 2.0
  117.             points[i] += dir * d * 0.5
  118.        
  119.         if i + 1 != point_count - 1:
  120. #           points[i+1] = centre - dir * d / 2.0
  121.             points[i+1] -= dir * d * 0.5
  122.  
  123. func GenerateMesh():
  124.    
  125.     vertex_array.clear()
  126.     uv1_array.clear()
  127.    
  128.     CalculateNormals()
  129.  
  130.     index_array.clear()
  131.    
  132.     var circumference = 2.0 * PI * rope_width
  133.     var uv_segment_length = circumference * texture_height_to_width
  134.    
  135.     #segment / point
  136.     for p in range(point_count):
  137.        
  138.         var center : Vector3 = points[p]
  139.        
  140.         var forward = tangent_array[p]
  141.         var norm = normal_array[p]
  142.         var bitangent = -norm.cross(forward).normalized()
  143.        
  144.         #UV1
  145.         #V coordinate
  146. #       var distance_from_end_point = (player_position - center).length()
  147.         var distance_from_end_point = (grapple_hook_position - center).length()
  148.  
  149.         var uv1_v = distance_from_end_point / uv_segment_length
  150.        
  151.         #current resolution
  152.         for c in range(resolution):
  153.             var angle = (float(c) / resolution) * 2.0 * PI
  154.            
  155.             var xVal = sin(angle) * rope_width
  156.             var yVal = cos(angle) * rope_width
  157.            
  158.             var point = (norm * yVal) + (bitangent * xVal) + center
  159.            
  160.             vertex_array.append(point)
  161.            
  162.             #U coordinate
  163.             var maxAngle = 2.0 * PI
  164.            
  165. #           var t_u = (angle - 0.0) / (maxAngle - 0.0)
  166.             var t_u = angle / maxAngle - 0.0
  167.            
  168. #           var uv1_u = lerp(0.0, 1.0, t_u) #This is therefore not necessary
  169.             var uv1_u = t_u
  170.            
  171.             uv1_array.append(Vector2(uv1_u, uv1_v))
  172.            
  173.             if p < point_count - 1:
  174.                 var start_index = resolution * p
  175.                 #INT values
  176.                 index_array.append(start_index + c);
  177.                 index_array.append(start_index + c + resolution);
  178.                 index_array.append(start_index + ((c + 1) % resolution));
  179. #               index_array.append(start_index + c + resolution);
  180.  
  181.                 index_array.append(start_index + ((c + 1) % resolution));
  182.                 index_array.append(start_index + c + resolution);
  183.                 index_array.append(start_index + ((c + 1) % resolution) + resolution);
  184. #               index_array.append(start_index + c + resolution);
  185.        
  186. #   if mesh.surface_get_arrays(0).size() != 0: print(mesh.surface_get_arrays(0)[5])
  187. #   print("<---BEFORE-------------------------")
  188.     mesh.clear_surfaces()
  189.    
  190.     mesh.surface_begin(Mesh.PRIMITIVE_TRIANGLES)
  191.  
  192.     var first_triangle : bool = true
  193.    
  194.     var current_iter = 0
  195.     var max_iter = resolution * 2
  196.    
  197. #   print(index_array.size())
  198.     for i in range(index_array.size() / 3):
  199.         var i1 = index_array[3*i]
  200.         var i2 = index_array[3*i+1]
  201.         var i3 = index_array[3*i+2]
  202.        
  203.         var p1 = vertex_array[i1]
  204.         var p2 = vertex_array[i2]
  205.         var p3 = vertex_array[i3]
  206.        
  207.         var uv1 = uv1_array[i1]
  208.         var uv2 = uv1_array[i2]
  209.         var uv3 = uv1_array[i3]
  210.        
  211.         if current_iter == max_iter - 1:
  212. #           uv1.x = ceil(uv1.x)
  213. #           uv3.x = ceil(uv3.x)
  214.             uv1.x = 1
  215.             uv3.x = 1
  216.            
  217.         elif current_iter == max_iter - 2:
  218. #           uv3.x = ceil(uv3.x)
  219.             uv3.x = 1
  220.        
  221.         var tangent = Plane(p1, p2, p3)
  222.         var normal = tangent.normal
  223.        
  224.         #1. point
  225.         mesh.surface_set_tangent(tangent)
  226.         mesh.surface_set_normal(normal)
  227.        
  228. #       if first_triangle:
  229. #           mesh.surface_set_uv(Vector2.ONE * uv_scale)
  230. #           mesh.surface_set_uv2(Vector2.ONE * uv_scale)
  231. #       else:
  232. #           mesh.surface_set_uv(Vector2.DOWN * uv_scale)
  233. #           mesh.surface_set_uv2(Vector2.DOWN * uv_scale)
  234.            
  235.         mesh.surface_set_uv(uv1 * uv_scale)
  236. #       mesh.surface_set_uv2((uv1 * uv_scale))
  237.        
  238.        
  239.        
  240.         mesh.surface_add_vertex(p1)
  241.        
  242.         #2. point
  243.         mesh.surface_set_tangent(tangent)
  244.         mesh.surface_set_normal(normal)
  245.        
  246. #       if first_triangle:
  247. #           mesh.surface_set_uv(Vector2.RIGHT * uv_scale)
  248. #           mesh.surface_set_uv2(Vector2.RIGHT * uv_scale)
  249. #       else:
  250. #           mesh.surface_set_uv(Vector2.RIGHT * uv_scale)
  251. #           mesh.surface_set_uv2(Vector2.RIGHT * uv_scale)
  252.            
  253.         mesh.surface_set_uv(uv2 * uv_scale)
  254. #       mesh.surface_set_uv2(uv2 * uv_scale)   
  255.        
  256.         mesh.surface_add_vertex(p2)
  257.        
  258.         #3. point
  259.         mesh.surface_set_tangent(tangent)
  260.         mesh.surface_set_normal(normal)
  261.        
  262. #       if first_triangle:
  263. #           mesh.surface_set_uv(Vector2.DOWN * uv_scale)
  264. #           mesh.surface_set_uv2(Vector2.DOWN * uv_scale)
  265. #       else:
  266. #           mesh.surface_set_uv(Vector2.ZERO * uv_scale)
  267. #           mesh.surface_set_uv2(Vector2.ZERO * uv_scale)
  268.  
  269.         mesh.surface_set_uv(uv3 * uv_scale)
  270. #       mesh.surface_set_uv2(uv3 * uv_scale)
  271.        
  272.         mesh.surface_add_vertex(p3)
  273.        
  274.         first_triangle = !first_triangle
  275.         current_iter += 1
  276.         if current_iter == max_iter: current_iter = 0
  277.     # End drawing.
  278.     mesh.surface_end()
  279. #   print(mesh.surface_get_arrays(0)[5])
  280.    
  281.  
  282. func CalculateNormals():
  283.     normal_array.clear()
  284.     tangent_array.clear()
  285.    
  286.     var helper
  287.    
  288.     for i in range(point_count):
  289.         var tangent := Vector3(0,0,0)
  290.         var normal := Vector3(0,0,0)
  291.        
  292.         var temp_helper_vector := Vector3(0,0,0)
  293.        
  294.         #first point
  295.         if i == 0:
  296.             tangent = (points[i+1] - points[i]).normalized()
  297.         #last point
  298.         elif i == point_count - 1:
  299.             tangent = (points[i] - points[i-1]).normalized()
  300.         #between
  301.         else:
  302.             tangent = (points[i+1] - points[i]).normalized() + (
  303.                 points[i] - points[i-1]).normalized()
  304.            
  305.         if i == 0:
  306.             temp_helper_vector = -Vector3.FORWARD if (
  307.                 tangent.dot(Vector3.UP) > 0.5) else Vector3.UP
  308.                
  309.             normal = temp_helper_vector.cross(tangent).normalized()
  310.            
  311.         else:
  312.             var tangent_prev = tangent_array[i-1]
  313.             var normal_prev = normal_array[i-1]
  314.             var bitangent = tangent_prev.cross(tangent)
  315.            
  316.             if bitangent.length() == 0:
  317.                 normal = normal_prev
  318.             else:
  319.                 var bitangent_dir = bitangent.normalized()
  320.                 var theta = acos(tangent_prev.dot(tangent))
  321.  
  322.                 var rotate_matrix = Basis(bitangent_dir, theta)
  323.                 normal = rotate_matrix * normal_prev
  324.  
  325.         tangent_array.append(tangent)
  326.         normal_array.append(normal)
  327.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement