Làm thế nào để tự động làm động một phần của mô hình 3d đối với một cái gì đó


8

Tôi tò mò về cách loại hoạt hình này thường được thực hiện theo mã.

Một vài ví dụ:

  • Một nhân vật nhặt thứ gì đó lên - chỉ có bàn tay hoạt hình hướng tới mục tiêu http://www.youtube.com/watch?v=rW-7iatedhx4 nhìn thấy từ 4:50 khi người chơi nhặt vũ khí.
  • Treo ký tự từ một gờ - tay được đặt ở một vị trí cụ thể (gờ) http://www.youtube.com/watch?v=SOiwArn4Bmw ngay từ đầu.
  • Nhân vật nhìn vào một cái gì đó - đầu được chỉ vào mục tiêu (npc nhìn vào máy tính)

Câu trả lời:


4

Điều này được gọi là động học nghịch đảo. Google có lẽ là người bạn tốt nhất của bạn trên trang này vì nó có thể trở nên phức tạp.


Tôi nhận được nó, tôi phải tính toán các chuyển động cần thiết để đạt được một vị trí mong muốn. Trong trường hợp này, tôi sẽ chỉ tính toán các chuyển động cho xương mong muốn.
Gerstmann

Thật vậy, mô tả video cho biết "... một hệ thống hoạt hình hoàn toàn dựa trên động học nghịch đảo ..."
MichaelHouse

0

Bài viết gốc: Cách mã hóa hệ thống IK

Đôi khi IK được tích hợp vào Unity là không đủ. Tôi sẽ chỉ cho bạn cách xây dựng tập lệnh IK của riêng bạn cho Unity. Bạn có thể áp dụng IK này cho bất kỳ cơ thể có khớp nối nào - ngón tay, bàn tay hoặc bàn chân. IK mà tôi sẽ xem xét hiện đang được Unity, Unreal, Panda và một số công cụ trò chơi khác sử dụng. Nó được gọi là FABRIK.

FABRIK là một phương pháp lặp. Phương pháp lặp là phương pháp không nhận được giải pháp ngay lập tức. Một phương thức lặp ngày càng gần hơn với giải pháp đúng với nhiều lần lặp hơn của phương thức - nói cách khác, lặp lại một vòng lặp.

Bất kỳ vấn đề IK nào cũng có một cơ thể khớp nối nhất định (một tập hợp các chi được kết nối với chiều dài và góc). Hiệu ứng cuối (vị trí của điểm cuối của chi cuối cùng) có vị trí bắt đầu với vị trí mục tiêu. Nó có thể có các mục tiêu khác, chẳng hạn như các góc.

Mỗi lần lặp FABRIK có hai phần chính.

void FABRIK() {
    while( abs(endEffectorPosition  goalPosition) > EPS ) {
        FinalToRoot(); // PartOne
        RootToFinal(); // PartTwo
    }
}

Phần đầu tiên lặp lại từ chi cuối cùng đến chi gốc. Đối với chi cuối cùng, bạn cần thay đổi góc / xoay của chi để chỉ vào vị trí mục tiêu (giữ vị trí trong bảng được neo và để cho vị trí ngoài của bảng được dịch bằng cách thay đổi góc). Tiếp theo, bạn dịch chi cuối cùng dọc theo góc cập nhật về vị trí mục tiêu, cho đến khi vị trí ngoài của chi bằng với vị trí mục tiêu (duy trì góc, nhưng để thay đổi vị trí trong của chi). Đó là khá nhiều cho chi cuối cùng, ngoại trừ rằng bây giờ bạn cần cập nhật vị trí mục tiêu hiện tại. Vị trí mục tiêu hiện tại được đặt thành vị trí bên trong được cập nhật của chi cuối cùng.

Đối với mỗi chi trong liên tiếp, bạn làm điều tương tự. Để rõ ràng tôi sẽ phác thảo nó. Đối với chi hiện tại, bạn cần thay đổi góc / góc quay của chi để hướng về vị trí mục tiêu hiện tại. Tiếp theo, bạn dịch chi hiện tại dọc theo góc được cập nhật về vị trí mục tiêu hiện tại, cho đến khi vị trí ngoài của chi bằng với vị trí mục tiêu hiện tại. Cuối cùng, bạn cập nhật vị trí mục tiêu hiện tại bằng với vị trí trong bảng được cập nhật của chi hiện tại.

Lặp lại các thao tác này cho đến khi bạn hoàn thành các thao tác này trên chi gốc. Sau đó, phần đầu tiên đã được hoàn thành.

/* Part One */
void FinalToRoot() {
    currentGoal = goalPosition;
    currentLimb = finalLimb;
    while (currentLimb != NULL) {
        currentLimb.rotation = RotFromTo(Vector.UP,
            currentGoal  currentLimb.inboardPosition);
        currentGoal = currentLimb.inboardPosition;
        currentLimb = currentLimb->inboardLimb;
    }
}

Phần thứ hai lặp theo hướng ngược lại: từ chi gốc đến chi cuối cùng. Đối với chi gốc, bạn cần cập nhật vị trí trong của nó lên vị trí gốc. Điều này sẽ dịch toàn bộ chi (mà không kéo dài). Đó là khá nhiều cho các chi gốc, ngoại trừ rằng bây giờ bạn cần cập nhật vị trí trong bảng hiện tại. Vị trí trong bảng hiện tại được đặt thành vị trí phía ngoài được cập nhật của chi gốc. Đối với mỗi chi ngoài liên tiếp, bạn làm điều tương tự. Để rõ ràng tôi sẽ phác thảo nó. Đối với chi hiện tại, bạn cần cập nhật vị trí trong của nó thành vị trí trong bảng hiện tại. Điều này sẽ dịch toàn bộ chi. Đó là khá nhiều cho các chi hiện tại, ngoại trừ rằng bây giờ bạn cần cập nhật vị trí trong bảng hiện tại. Vị trí trong bảng hiện tại được đặt thành vị trí phía ngoài được cập nhật của chi hiện tại.

Lặp lại các thao tác này cho đến khi bạn hoàn thành các thao tác này trên chi cuối cùng. Sau đó, phần thứ hai đã được hoàn thành.

/* Part Two */
void RootToFinal() {
    currentInboardPosition = rootLimb.inboardPosition;
    currentLimb = rootLimb;
    while (currentLimb != NULL) {
        currentLimb.inboardPosition = currentInboardPosition;
        currentInboardPosition = currentLimb.outboardPosition;
        currentLimb = currentLimb->inboardLimb;
    }
}

Khi phần đầu tiên và phần thứ hai đã được hoàn thành, bạn đã hoàn thành lần lặp đầu tiên của phương pháp FABRIK. Tiếp tục lặp lại ở phần một và hai cho đến khi bộ kết thúc gần như bạn cần đến vị trí mục tiêu, được xác định bởi một số EPS (giá trị epsilon).

Đó là nó! Đó là phương pháp FABRIK. Phần một lặp lại từ chi cuối cùng. Phần thứ hai lặp đi lặp lại từ chi gốc. Phương pháp FABRIK lặp lại Phần một và Phần thứ hai cho đến khi bộ kết thúc đủ gần với vị trí mục tiêu.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.