惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Blog — PlanetScale
Blog — PlanetScale
Jina AI
Jina AI
C
Check Point Blog
V
V2EX
H
Help Net Security
Microsoft Azure Blog
Microsoft Azure Blog
P
Proofpoint News Feed
A
About on SuperTechFans
D
DataBreaches.Net
腾讯CDC
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
IT之家
IT之家
WordPress大学
WordPress大学
人人都是产品经理
人人都是产品经理
T
The Blog of Author Tim Ferriss
Recent Announcements
Recent Announcements
Google DeepMind News
Google DeepMind News
云风的 BLOG
云风的 BLOG
MongoDB | Blog
MongoDB | Blog
J
Java Code Geeks
博客园_首页
T
Tailwind CSS Blog
M
MIT News - Artificial intelligence
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻

Rafael Magalhaes

Internal Developer Platform 简介 故郷で野良猫を保護したことについて 我喜欢的动漫女角色 在日本租房 Blog Enhanced 我遭遇的网络安全事件及应对 きつい日々はやっと終わりそう 在东京救助流浪猫 仇恨教育真实存在吗 什么是创业 向中国程序员介绍日本 IT Blog Reimplemented Deploy Perforce Server into Kubernetes 马伯庸写做爱 Abandoned Space Werewolf Indiegame Showcase Dynamic 3D Physical Rope in Godot - Part1 我挤上了女性专用车厢 日本见闻(其一) Integrate Godot Headless Server with Nakama Jet Animation Sequence Lamp Animation Rigged 第一次用数位板画画 计算机能解决的问题 一个淘宝商品封面 黄奇帆的观点 中国历史王朝的巅峰 - 宋 历史上公司的极致 GDP 简介 为什么要读历史 两个困扰了很久的问题终于有了答案
Dynamic 3D Physical Rope in Godot - Part2
2023-11-25 · via Rafael Magalhaes

In previous article, we solve the problem of generating PinJoint3D at the right places on the fly, given two PhysicsBody3D and how long the rope is.

In this article, we try to draw a 3D rope mesh alongside those PinJoint3D in global space.

ImmediateMesh is a great fit because our rope is constantly updated in every physical frame. ImmediateMesh provides OpenGL 1.x style immediate mode API to draw mesh.

Godot also provides a class called Curve3D, representing what its name indicates. Combining these two classes we can draw our rope through following steps:

  • After all PinJoint3Ds are arranged at the right place during the rope generation, we save their positions along with two anchor positions into a Curve3D
  • In every physical frame, we update the points of curve according to the place of pinjoints and anchors, whose positions are already solved by game engine's physics.
  • In every rendering frame, we draw a 3d rope using ImmediateMesh with the points in the curve.

Draw 3D rope from a Curve3D

For every point of the curve, we extrude the point to a circle. It's not a precise circle in parametric equation, but a approximate one constitued of discrete vertices as we are doing real time rendering instead of offline ray tracing.

The function below returns the points on the cross section circle from a point of curve. With the section_circle_resolution increases, the circle is more continous at the cost of performance.

func _generate_cross_section_circle_points(point: Vector3, next_point: Vector3) -> PackedVector3Array:
    var points := PackedVector3Array()
    var dir := next_point - point
    var right := dir.cross(Vector3.UP).normalized()
    var up := right.cross(dir).normalized()

    for i in section_circle_resolution:
        var phi = 2.0 * PI * float(i) / float(section_circle_resolution)
        var local_point := Vector3(sin(phi) * radius, cos(phi) * radius, 0.0)
        var global_point := point + right * local_point.x + up * local_point.y
        points.push_back(global_point)

    return points

After we have the points on the circle, we draw quads between sibling circles. A quad is just two triangles. Note that we deliver our vertices to ImmediateMesh clockwise. ( a[i], b[i], b[j] ) then ( a[i], b[j], a[j] ).

func _draw_quad_between_circle_points(circle_points: PackedVector3Array, next_circle_points: PackedVector3Array):
    for i in section_circle_resolution:
        var j := (i + 1) % section_circle_resolution

        # First triangle
        var i_normal := -1.0 * (circle_points[i] - circle_points[j]).cross(next_circle_points[i] - circle_points[i]).normalized()
        mesh.surface_set_normal(i_normal)
        mesh.surface_add_vertex(circle_points[i])

        var next_i_normal := -1.0 * (circle_points[i] - next_circle_points[i]).cross(next_circle_points[i] - next_circle_points[j]).normalized()
        mesh.surface_set_normal(next_i_normal)
        mesh.surface_add_vertex(next_circle_points[i])

        var next_j_normal := -1.0 * (circle_points[j] - next_circle_points[j]).cross(next_circle_points[i] - next_circle_points[j]).normalized()
        mesh.surface_set_normal(next_j_normal)
        mesh.surface_add_vertex(next_circle_points[j])

        # Second triangle
        mesh.surface_set_normal(i_normal)
        mesh.surface_add_vertex(circle_points[i])

        mesh.surface_set_normal(next_j_normal)
        mesh.surface_add_vertex(next_circle_points[j])

        var j_normal := -1.0 * (circle_points[i] - circle_points[j]).cross(next_circle_points[j] - circle_points[j]).normalized()
        mesh.surface_set_normal(j_normal)
        mesh.surface_add_vertex(circle_points[j])

For more detail, you can checkout the github repo, especially the source file rope_mesh.gd

Further Improvements

The repo still has a lot to do, like UVs and rewriting in native languages like Rust to support more pinjoints at the same time. More pinjoints we have, more real it feels and behaves.

Reference

https://docs.godotengine.org/en/stable/tutorials/3d/procedural_geometry/immediatemesh.html

https://docs.godotengine.org/en/stable/classes/class_curve3d.html

https://chat.openai.com

@2023-11-25 14:47