Bones Animation - Ma trận và tính toán


7

Chúng tôi đang 'vào chung kết' khi hoàn thành dự án, nhưng ngay trước khi triển khai hệ thống hoạt hình.

Khách hàng của chúng tôi đã quyết định chọn "Hoạt hình xương" - đó là tôi nên xuất từng Ma trận chuyển đổi (ma trận xoay4x4 + bản dịch) cho mọi khung hình và cho mọi xương mà đối tượng hoạt hình này có.

Các đối tượng trong trò chơi của chúng tôi được làm động bằng 3DS Max Physique Modifier, vì vậy chúng tôi sẽ có dữ liệu xương / trọng số trên mỗi đỉnh. Nhưng tôi sẽ đơn giản hóa mọi thứ ở đây chỉ để có một chút ánh sáng về chủ đề này.

Tôi muốn chia bài này thành 2 điểm, trong đó:

  1. Xuất ma trận xương cho mọi khung

    • xử lý về phương pháp chính xác để xuất các vị trí xương cho các mục đích hoạt hình sau này, trong đó tôi phải 'di chuyển' và 'xoay' mọi đỉnh bị ảnh hưởng bởi vị trí xương này sang vị trí xương ở khung X.
  2. Tính toán vị trí đỉnh cuối cùng

    • xử lý các hoạt động ma trận thích hợp để tính toán vị trí đỉnh mới theo sự biến đổi xương trong khung X.

1. XUẤT KHẨU VẬT LIỆU TIỀN THƯỞNG CHO MỌI KHUNG

Tôi có hiểu chính xác rằng trong khi xuất đối tượng hoạt hình tôi nên:

  1. Lấy ma trận biến đổi BONE ở khung 0 và Đảo ngược ma trận này

  2. Lấy ma trận chuyển đổi Bone tại FRAMEx

  3. Nhân 1 * 2 để lấy phần bù chuyển đổi của Bones tại FRAMEx

[pseudocode]
// Animation export

// For each frame, export bone transformation offset
for(int iFrame = 0; iFrame < vFrames.size(); iFrame++)
{
    // For every bone in the object
    for(int iBone = 0; iBone < vBones.size(); iBone++)
    {
        // Grab transformation matrix for this bone at frame 0 and inverse it
        Matrix3 matBoneMatrixAtStart = pNode->GetObjectTMAfterWSM( 0 );
        matBoneMatrixAtStart.Inverse();

        // Grab transformation matrix for this bone at frame iFrame
        Matrix3 matBoneMatrixAtCurrentFrame = pNode->GetObjectTMAfterWSM( iFrame );

        // Multiply Inversed Transformation Matrix of this bone at frame 0 - with
        //  current frame transformation matrix
        Matrix3 matBoneTransformationOffset = matBoneMatrixAtStart
                                              * matBoneMatrixAtCurrentFrame ;

        // Save matBoneTransformationOffset - vertex will be multiplied by this
        //  matrix for animation purposes
        fwrite(.....)
    }

}
[/pseudocode]

Như vậy đã đủ chưa? Hoặc có một cái gì đó tôi đang thiếu ở đây?

2. TÍNH TOÁN CÁC VỊ TRÍ CHỨNG NHẬN MỚI (VỊ TRÍ VERTEX CUỐI CÙNG TẠI KHUNG X)

Sau này, khi kết xuất, các đỉnh đối tượng sẽ được nhân với ma trận biến đổi xương xuất khẩu cho khung hình động thực tế, và sau đó nhân với toàn bộ ma trận biến đổi mô hình này để đặt đối tượng vào đúng vị trí bên trong mức:

[pseudocode]

Update()
{
    // The model transformation matrix describing the position of
    //  the model in the level
    matModelTransformationMatrix


    // Calculate new vertex position according to it's bone transformation offset
    NewVertexPosition = (OriginalVertexPosition * matBoneTransformationOffset[iFrame])
                           * matModelTransformationMatrix;

    // Increment the frame for testing purposes
    iFrame++;
}

[/pseudocode]

Tôi có nghĩ đúng ở đây không? Vì vậy, có bù chuyển đổi xương cho khung X, nhân mọi đỉnh bị ảnh hưởng bởi xương này bằng bù này sẽ dẫn đến một đỉnh biến đổi chính xác như xương này phải không?

Câu trả lời:


8

Tốt nhất bạn nên đọc các trang của nVidia có chứa một số bài viết về GPU Gems. Có một công thức chính mà tôi sẽ giải thích ngắn gọn cho bạn trong câu trả lời giả sau:nhập mô tả hình ảnh ở đây

Đây là nơi bạn sẽ tìm thấy bài viết hoàn chỉnh và bây giờ nó là một tài nguyên cổ điển. Tôi sẽ chỉ cho rằng bạn muốn một lời giải thích về quá trình đó, được thực hiện theo cách đơn giản (càng nhiều càng tốt).

Công thức và ý nghĩa của nó:

Bạn bắt đầu với một lưới các đỉnh, tức là một tập hợp các đỉnh có kết nối. Bạn không quan tâm đến cấu trúc liên kết nhiều như vậy, vì vậy, không quan tâm đến kết nối (đó là thứ gì đó không nên làm xấu đi, nó sẽ giữ cho các đa tạp trông giống như đa tạp, bảo tồn cấu trúc liên kết, v.v.). Trong công thức đó, BBindpose cung cấp cho bạn vị trí còn lại của đỉnh của nhân vật. Đây là trong không gian đối tượng, tức là không gian "thế giới" của khung của nhân vật đó. Bây giờ, mỗi xương có khung riêng và cách chuyển đổi một vectơ được viết trong khung xương [i] thành khung toàn cầu của đối tượng bằng cách nhân nó với ma trậnBindpose [i]. (hãy tưởng tượng bạn phải lắp ráp một con robot, và các đỉnh cẳng tay của nó được trao cho bạn trong khung tham chiếu khuỷu tay của nó .. và khuỷu tay được kết nối với xương cánh tay / xương vai .. đó là lý do tại sao bạn cần những biến đổi này, chủ yếu để lắp ráp các bộ đỉnh thành một lưới)

Vậy, INV (matrixBindpose [i]) x BBindpose có nghĩa là gì? Điều đó có nghĩa là bạn có được tọa độ của đỉnh v trong khung cục bộ của xương [i] xương đó. Tại sao? Bởi vì mỗi xương có thể ghi nhớ phiên bản của chính nó trong đó một đỉnh mà nó ảnh hưởng liên quan đến khung tọa độ của chính nó. Điều đó có nghĩa là, mỗi xương có thể cung cấp cho bạn một cái nhìn tương đối riêng về vị trí mà nó ảnh hưởng đến, bất kể các xương khác nhìn thấy điểm đó như thế nào.

Bây giờ, điều gì xảy ra khi bạn nhân với ma trận ma trận biến đổi xương mới [i] ? Nhớ lại từ điểm cuối cùng mà bây giờ bạn có một phiên bản cục bộ của đỉnh v , tức là cách xương [i] nghĩ rằng đỉnh đó trông như thế nào đối với khung của chính nó. Bằng cách nhân với ma trận [i] , bạn kết thúc với một vectơ / đỉnh nằm trong khung tọa độ toàn cục / đối tượng.

Tiếp theo, bạn nhân đỉnh đó với sự đóng góp / trọng lượng vô hướng của xương. Bạn có gì sau đó? Bạn kết thúc với một tổng các vectơ có trọng số nằm trong cùng một khung tọa độ. Đó là lý do tại sao bạn có thể thêm chúng / tức là lấy tổng đó trên tất cả các xương ảnh hưởng đến một đỉnh.

Mã của bạn không thực sự phản ánh rằng bạn hoàn toàn hiểu thủ tục. Bài báo của nVidia tập trung nhiều hơn vào cách thực hiện điều đó thông qua các shader, đó là lý do tại sao họ cho rằng có nhiều nhất bốn xương có thể ảnh hưởng đến một đỉnh của lưới ban đầu / liên kết.

Như bạn đã nói, nếu bạn thực hiện tư thế bắt đầu của mình, ma trận ràng buộc, thì ma trận [i] x ma trận [i] ^ - 1 là ma trận danh tính. Điều đó ổn vì tổng sẽ bằng _sum (w_i) * BBindpose_. Vì BBindpose là vectơ được viết trong khung toàn cục / đối tượng, nên nó đã được lắp ráp và ở vị trí. Tổng các trọng số đó, bằng cách xây dựng là 1 (tổ hợp lồi do quá trình chuẩn hóa trọng lượng - thường được hệ thống thực hiện sau khi các trọng số được gán cho mỗi đỉnh). Vì vậy, công thức đó có thể được sử dụng để kiểm tra xem một mô hình có thể được lắp ráp chính xác hay không (nó thường được thực hiện bởi MD5 Doom3bộ tải mô hình hoạt hình nếu tôi nhớ chính xác). Tóm lại, điều đó có nghĩa là ở mỗi bước bạn cần tối ưu hóa một chút tính toán để bạn tính kết quả của công thức lil'ol đó. Chúc mừng mã hóa :)


Ồ, đó là rất nhiều thứ tôi phải đọc vài lần bây giờ - tôi không nghi ngờ nó quá phức tạp .. Cảm ơn vì sự giúp đỡ của bạn, điều này sẽ giúp tôi chạy ...
PeeS

Xin chào, đây thực sự là một chủ đề khá đơn giản, tôi đã làm một hướng dẫn về vấn đề này, nhưng vì nó không phải bằng tiếng Anh, nên nó sẽ không giúp bạn đưa ra bản pdf về điều đó. Tôi dự định thực hiện nó trong một video, bằng tiếng Anh thuần túy và đăng nó lên một kênh youtube, nhưng hiện tại tôi không có thời gian. Phát âm các câu hỏi của bạn về chủ đề này ở đây trong tương lai gần .. thật tốt khi tranh luận về các chủ đề đó.
teodron
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.