Hang động vô hạn 3D trong Unity


8

Một người bạn và tôi đang hy vọng tạo ra một trò chơi trong Unity trong đó bạn bay qua một hang động 3D vô tận có thể xoắn và uốn theo bất kỳ hướng nào (mặc dù rõ ràng là không đến mức không thể thực hiện được các ngã rẽ). Chúng tôi đã suy nghĩ về việc tạo ra một số "mảnh" đường hầm mà mỗi đường cong một số lượng nhất định và sinh ra mỗi cái ở cuối của cái trước đó.

Nhưng chúng tôi không biết làm thế nào để đảm bảo rằng miệng của một đoạn đường hầm luôn thẳng hàng hoàn hảo (ở cả vị trí và xoay) với phần cuối của phần trước. Bất cứ ai có thể cung cấp bất kỳ lời khuyên về làm thế nào để thực hiện điều này?

Chúng ta thậm chí đang đi về nó theo cách đúng đắn, hay có cách nào tốt hơn để thủ tục tạo ra hang động? Điểm thưởng: Thật tuyệt vời nếu hang động cũng có thể thay đổi đường kính và / hoặc hình dạng, mặc dù đó chỉ là nước thịt.

Câu trả lời:


6

Rất hiếm khi "đúng cách" hay "sai cách" khi nói đến thiết kế trò chơi. Có rất nhiều cách để giải quyết vấn đề này, nhưng đây là một vài cách tiếp cận có thể để khám phá:

  • Hạn chế các đoạn đường hầm để cả bắt đầu và kết thúc chỉ theo một số hướng nhất định; ví dụ chỉ dọc theo các trục. Sau đó, bạn chỉ cần theo dõi phần bù từ đầu đến cuối đoạn, cùng với các enum mô tả hướng chuyển động ở đầu và cuối đoạn. Bằng cách này, bạn không phải lo lắng về việc xoay lưới đường hầm của mình, miễn là bạn luôn chọn cái tiếp theo sao cho nó bắt đầu theo cùng hướng với cái cuối cùng kết thúc.

  • Làm cho mỗi phân đoạn bắt đầu tại điểm gốc của không gian mô hình cục bộ của nó với đường hầm đi dọc theo một trục cụ thể (+ X, + Z hoặc -Z sẽ là các lựa chọn hợp lý nhất, nhưng tất cả các mô hình nên sử dụng cùng một) lưu trữ vị trí cuối đường hầm và hướng di chuyển cuối cùng theo một cách nào đó để lưới tiếp theo có thể được chuyển đổi chính xác. (một ma trận biến đổi có lẽ là cách dễ nhất để lưu trữ thông tin này, nhưng bạn cũng có thể sử dụng một vectơ dịch chuyển + bậc bốn, bậc bốn, chuyển vị + vectơ cơ sở mới, chuyển vị + xoay góc euler, v.v.)

  • Thủ tục tạo hang động của bạn bằng cách truyền dữ liệu đỉnh mới đến một vài mắt lưới. Bạn có thể làm điều này bằng cách sử dụng Meshlớp . Khi tạo dữ liệu đỉnh mới, cách dễ nhất có lẽ là chọn một điểm ở đâu đó theo cùng hướng với đoạn hang trước đó, sau đó để cho tâm của hang di chuyển về điểm đó. Sau đó, bạn có thể sử dụng tọa độ hình trụ để thủ tục tạo chi tiết trên các bức tường của hang động. Hãy nghĩ về nó như đùn ra phần cuối của một hình trụ, sau đó dịch riêng từng đỉnh gần hoặc xa hơn từ tâm của hình trụ đó.

Bất kỳ giải pháp nào sử dụng các phân đoạn có sẵn sẽ yêu cầu bạn đảm bảo rằng tất cả các mắt lưới có hình dạng và đường kính giống nhau quanh tâm của đường hầm, nhưng bạn có thể khắc phục điều này bằng cách để các phân đoạn chồng lên nhau ở một mức độ và khiến mỗi phân đoạn bùng lên ra ở cuối Nếu được thực hiện đúng, nó không quá rõ ràng với người chơi rằng có một đường may.

Mặt khác, nếu bạn sử dụng hình học hoàn toàn được tạo theo thủ tục, bạn sẽ có nhiều việc hơn để đảm bảo rằng bạn không tạo ra các phần không thể đi qua và bạn có thể gặp phải các vấn đề với phát hiện va chạm.

Hãy nhớ rằng, với bất kỳ trò chơi "vô hạn" nào, bạn nên nhận thức được những hạn chế của biểu diễn dấu phẩy động. Nếu người chơi ở quá xa nguồn gốc thế giới, sẽ dễ mất độ chính xác trong các phép tính dấu phẩy động (ví dụ: khi hai giá trị lớn được trừ vào nhau). Để tránh điều này, bạn có thể khiến thế giới di chuyển xung quanh người chơi, thay vì người chơi di chuyển khắp thế giới, nhưng thường thì việc kiểm tra vị trí của người chơi thường xuyên hơn và nếu họ ở quá xa nguồn gốc, hãy xây dựng lại thế giới với người chơi ở hoặc gần nguồn gốc.


2
+1 đặc biệt cho nhận xét 'không đúng cách' (mặc dù tôi sẽ phải hơi không đồng ý: có rất nhiều, rất nhiều cách sai ...)
Steven Stadnicki

Cám ơn rất nhiều! Chúng tôi đã kết thúc bằng cách sử dụng một vài đoạn đường hầm khác nhau với các vị trí và hướng kết thúc trước, đặt các điểm đánh dấu ở các vị trí / góc đó và đặt từng mảnh mới liên quan đến điểm đánh dấu của mảnh cũ. Thật tuyệt khi làm điều gì đó công phu hơn, nhưng hiện tại, việc tạo ra thủ tục hợp pháp hơn đã vượt ra khỏi phạm vi kỹ năng và giới hạn thời gian của chúng tôi. Cảm ơn một lần nữa!
richardmherndon

3

Đây là một kỹ thuật tôi đã thử nghiệm gần đây. Nguyên mẫu RenderMonkey của tôi cho thấy một phần của hẻm núi kiểu badlands, nhưng nguyên tắc tương tự sẽ hoạt động trong các hang động.

Ý tưởng là bắt đầu với các ô chung chung, hết sức nhàm chán, với các cạnh có thể dự đoán đơn giản để chúng dễ dàng xếp hàng mà không có đường nối hoặc khoảng trống:

Ngói, gạch có thể dự đoán

Những viên gạch bắt đầu này có thể là hình dạng mà bạn đã tạo mô hình hoặc các ống macaroni được tạo theo quy trình hình học hình trụ (hình thức này là một biến thể theo đề xuất của bcrist và Steven Stadnicki). Sử dụng các mô hình bạn đã tạo giúp dễ dàng xử lý cấu trúc liên kết tùy ý như đường dẫn phân nhánh hoặc các điểm ưa thích như hang động mở. Điều này vẫn có thể thực hiện được với thủ tục thuần túy (xem gợi ý của Gyroninja về các kỹ thuật metaball), nhưng đầy thách thức.

Khi một ô được đặt vào thế giới, thay thế các đỉnh của nó bằng các hàm nhiễu được áp dụng trong không gian thế giới. Điều này bảo tồn tính kết nối và tính liền mạch giữa các ô (vì các đỉnh trùng khớp có cùng một đầu vào không gian thế giới và có cùng đầu ra chuyển vị), nhưng làm cho mọi ô đều trông độc đáo và hữu cơ:

Điều đó thú vị hơn

Kết cấu và quy tắc cũng được áp dụng trong không gian thế giới - ở đây sử dụng ánh xạ triplanar - để các ô liền kề hoàn toàn liền mạch, không bị ràng buộc UV khó khăn.

Cũng thú vị hơn

Hy vọng là một kỹ thuật như thế này cho phép bạn dễ dàng lập kế hoạch và kiểm soát thiết kế cấp độ của bản đồ lát gạch, không có sự lặp lại có thể nhìn thấy hoặc cấu trúc trông giống cơ học trong kết quả có thể chơi được.

Bạn có thể sử dụng lưới độ phân giải thấp hơn chỉ với các thành phần nhiễu tần số thấp được áp dụng để tạo biểu diễn va chạm. Như bcrist lưu ý, bạn sẽ cần kiểm soát biên độ tối đa của tiếng ồn so với bán kính và độ sắc nét của các đường hầm, để đảm bảo nó không bao giờ bị tắt hoàn toàn.

Một lưu ý nữa: nếu hang của bạn thực sự là vô hạn, bạn có thể cần phải "thu hồi" nó theo định kỳ khi người chơi di chuyển xa hơn và xa hơn từ gốc. Bởi vì các số dấu phẩy động mất độ chính xác ở cường độ cao, vật lý và kết xuất đồ tạo tác có thể bò vào ở khoảng cách cực xa. Nếu bạn làm điều này, bạn sẽ muốn tiếng ồn trong thế giới của bạn được định kỳ trên một quy mô lớn, với khoảng thời gian khớp chính xác với phần bù của bạn, vì vậy bạn không gặp phải các đường nối sau khi thu lại.


2

Bạn có thể mô hình hóa hang động của mình như một chuỗi các điểm, mỗi điểm có kích thước liên kết, với các đường nối chúng. Sau đó coi mỗi điểm và đường là metaballs và metacylinder. Điều này cung cấp cho bạn một hình dạng cơ bản cho hang động của bạn, mà bạn có thể muốn bắt đầu thêm biến thể, chẳng hạn như bằng cách bù đắp ngẫu nhiên các đỉnh.


2

Đây là một cách tiếp cận khác để tạo ra thủ tục chưa được đề cập rõ ràng: lột da. Bạn có thể sử dụng một phiên bản của Hermite Splines(cung cấp một vị trí và các tiếp tuyến nội suy đường cong) để xác định các đường cong: khi đến lúc tạo một phân đoạn mới, chỉ cần chọn một vị trí (theo hướng của phân đoạn trước, như bcrist nói) và một hướng (gần giống nhau hướng - ví dụ: trong một số hình nón được xác định rõ của hướng trước đó), sau đó sử dụng vị trí + hướng mới và vị trí trước đó + hướng của bạn để tạo một 'cột sống' mới cho hang động của bạn. Khi bạn có xương sống này, bạn có thể ghép nó với cấu trúc hình trụ: xác định vị trí và tiếp tuyến của (ví dụ) 10 điểm dọc theo đường cong, sử dụng các vị trí / tiếp tuyến đó để tìm một 'khung' trực giao, sau đó sử dụng các khung này để xây dựng các đoạn hình trụ. Một lưu ý nhỏ với điều này là hang không thể cong quá nhiều, hoặc nếu không bạn có thể gặp phải các vấn đề tự giao nhau.

EDIT: Đây là một phân tích mã giả thô của thuật toán:

Parameters:
  L = (average) segment length,
  V = segment length variation,
  R = cylinder radius,
  T = segment angular variation
  S = number of 'rings' per segment

Setup:
Choose an initial point P_0 and direction D_0 (for concreteness' sake, these can be
the origin and the X axis).  Set P_prev and D_prev to these values.
Initialize u_prev to be the Y axis and v_prev to be the Y and Z axes.
  (Note that (D_prev, u_prev, v_prev) form a mutually-orthogonal 'coordinate frame')

Generate a segment (do this as many times as you want):
{
  Choose a (temporary) direction D within a cone of size T around the previous direction D_prev
  Choose a segment length L_cur = at random from within the range [L-V, L+V].
  Set the current terminal point P_cur to P_prev+D*L_cur - this is the position
  we'll interpolate to
  Set the current terminal direction D_cur to a direction chosen at random from
  within a cone of size T around the previous direction.  (There are good ways
  of doing this - if you look back through gamedev.SE you should find some)
  'Build' the Hermite spline H that goes from (P_prev, D_prev) to (P_cur, D_cur)

  Now, skin that spline:
  for ( i = 1; i <= S; i++ ) {
    find the position P of the hermite spline H at t=i/S
    find the direction D of the spline at t (this will be just the derivative)
    'transport' the orthogonal frame to the new spot: for instance,
      v_new = D x u_prev
      u_new = v_new x D
    (note that this keeps u_new, v_new close to their old values, and orthogonal
    to each other and to D)
    Use the previous and current frames and positions to build a cylindrical 'ring':
    For theta from 0 to 2pi {
      find the points (P+(u_new, v_new, D) * (cos theta, sin theta, 0))
      and connect them to their counterparts from the previous ring
      (note that that multiplication is a matrix-vector multiply)
    }
    update u_prev and v_prev to u_new and v_new
  }
  update the other prev variables to their 'new' values
}

Đây rõ ràng là mã giả rất thô; nếu có bất kỳ phần nào của nó không rõ ràng chỉ cho tôi biết và tôi sẽ cố gắng giải thích, nhưng sẽ rất khó để bao quát tất cả các chi tiết mà không chỉ là một bãi mã lớn ...


(Ngẫu nhiên, nếu bạn muốn mã giả cho cách tiếp cận này, hãy cho tôi biết; tôi đã phải làm một cái gì đó giống như thế này ở một công việc trước đó, vì vậy tôi đã tìm ra tất cả các chi tiết nhỏ.)
Steven Stadnicki

Tôi tò mò muốn xem triển khai của bạn; Thay vào đó, tôi cũng đã từng làm điều gì đó tương tự nhưng sử dụng các đường cong Bezier hình khối 3D.
bcrist
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.