Trong một hệ thống vật liệu dựa trên biểu đồ, làm thế nào tôi có thể hỗ trợ nhiều loại đầu vào và đầu ra?


11

nhập mô tả hình ảnh ở đây

Tôi đang cố gắng che giấu cách các hệ thống vật chất như thế này , điều này được thực hiện. Các hệ thống giống như đồ thị mạnh mẽ và thân thiện với người dùng này dường như tương đối phổ biến như một phương pháp cho phép các lập trình viên và những người không phải lập trình viên nhanh chóng tạo ra các shader. Tuy nhiên, từ kinh nghiệm tương đối hạn chế của tôi với lập trình đồ họa, tôi không hoàn toàn chắc chắn về cách chúng hoạt động.


Lý lịch:

Vì vậy, khi tôi đã lập trình các hệ thống kết xuất OpenGL đơn giản trước đây, tôi thường tạo một lớp Vật liệu tải, biên dịch và liên kết các shader từ các tệp GLSL tĩnh mà tôi đã tạo thủ công. Tôi cũng thường tạo lớp này như một trình bao bọc đơn giản để truy cập các biến thống nhất GLSL. Một ví dụ đơn giản, hãy tưởng tượng rằng tôi có một shader đỉnh cơ bản và shader mảnh, với một Texture2D đồng nhất thêm để truyền một kết cấu. Lớp Vật liệu của tôi chỉ đơn giản là tải và biên dịch hai shader đó thành một vật liệu, và từ đó, nó sẽ hiển thị một giao diện đơn giản để đọc / ghi đồng phục Texture2D của shader đó.

Để làm cho hệ thống này linh hoạt hơn một chút, tôi thường viết nó theo cách cho phép tôi cố gắng vượt qua đồng phục của bất kỳ tên / loại nào [ví dụ: SetUniform_Vec4 ("AmbientColor", colorVec4); sẽ đặt đồng phục AmbientColor thành một vectơ 4d cụ thể gọi là "colorVec4" nếu đồng phục đó tồn tại trong vật liệu.] .

class Material
{
    private:
       int shaderID;
       string vertShaderPath;
       string fragSahderPath;

       void loadShaderFiles(); //load shaders from files at internal paths.
       void buildMaterial(); //link, compile, buffer with OpenGL, etc.      

    public:
        void SetGenericUniform( string uniformName, int param );
        void SetGenericUniform( string uniformName, float param );
        void SetGenericUniform( string uniformName, vec4 param );
        //overrides for various types, etc...

        int GetUniform( string uniformName );
        float GetUniform( string uniformName );
        vec4 GetUniform( string uniformName );
        //etc...

        //ctor, dtor, etc., omitted for clarity..
}

Điều này hoạt động nhưng cảm giác như một hệ thống tồi tệ do thực tế là khách hàng của lớp Vật liệu phải truy cập đồng phục một mình - người dùng phải nhận thức được phần nào về đồng phục trong mỗi đối tượng vật chất vì họ bị buộc phải vượt qua họ bằng tên GLSL của họ. Đó không phải là vấn đề lớn khi chỉ có 1-2 người làm việc với hệ thống, nhưng tôi không thể tưởng tượng hệ thống này sẽ mở rộng rất tốt, và trước khi tôi thực hiện nỗ lực tiếp theo trong việc lập trình hệ thống kết xuất OpenGL, tôi muốn lên cấp lên một chút.


Câu hỏi:

Đó là nơi tôi ở cho đến nay, vì vậy tôi đã cố gắng nghiên cứu cách các công cụ kết xuất khác xử lý các hệ thống vật liệu của họ.

Cách tiếp cận dựa trên nút này là tuyệt vời và nó dường như là một hệ thống cực kỳ phổ biến để tạo ra các hệ thống vật liệu thân thiện với người dùng trong các công cụ và công cụ hiện đại. Từ những gì tôi có thể nói họ dựa trên cấu trúc dữ liệu đồ thị trong đó mỗi nút đại diện cho một số khía cạnh đổ bóng của tài liệu của bạn và mỗi đường dẫn đại diện cho một loại mối quan hệ giữa chúng.

Từ những gì tôi có thể nói, việc triển khai loại hệ thống đó sẽ đơn giản như một lớp MaterialNode với nhiều lớp con khác nhau (TextureNode, FloatNode, LerpNode, v.v.). Trong đó mỗi lớp con MaterialNode sẽ có MaterialConnections.

class MaterialConnection
{
    MatNode_Out * fromNode;
    MatNode_In * toNode;
}

class LerpNode : MaterialNode
{
    MatNode_In x;
    MatNode_In y;
    MatNode_In alpha;

    MatNode_Out result;
}

Đó là ý tưởng rất cơ bản , nhưng tôi hơi không chắc chắn về cách một vài khía cạnh của hệ thống này sẽ hoạt động:

1.) Nếu bạn xem các 'Biểu thức vật chất' (nút) khác nhau mà Unreal Engine 4 sử dụng , bạn sẽ thấy rằng mỗi loại có kết nối đầu vào và đầu ra của nhiều loại. Một số nút đầu ra nổi, một số vector2 đầu ra, một số vector4 đầu ra, v.v ... Làm cách nào tôi có thể cải thiện các nút và kết nối ở trên để chúng có thể hỗ trợ nhiều loại đầu vào và đầu ra? Liệu phân lớp MatNode_Out với MatNode_Out_Float và MatNode_Out_Vec4 (vân vân) có phải là một lựa chọn khôn ngoan?

2.) Cuối cùng, loại hệ thống này liên quan đến các shader GLSL như thế nào? Nhìn lại UE4 (và tương tự cho các hệ thống khác được liên kết ở trên), người dùng cuối cùng được yêu cầu cắm một số nút vật liệu vào một nút lớn với các tham số khác nhau đại diện cho các tham số shader (màu cơ bản, độ kim loại, độ bóng, độ phát xạ, v.v.) . Giả định ban đầu của tôi là UE4 có một loại 'shader chính' được mã hóa cứng với nhiều loại đồng phục khác nhau, và mọi thứ mà người dùng làm trong 'vật liệu' của họ chỉ đơn giản được chuyển cho 'shader chính' khi họ cắm các nút của họ vào ' nút chủ '.

Tuy nhiên, tài liệu UE4 nêu rõ:

"Mỗi nút chứa một đoạn mã HLSL, được chỉ định để thực hiện một tác vụ cụ thể. Điều này có nghĩa là khi bạn xây dựng Tài liệu, bạn đang tạo mã HLSL thông qua tập lệnh trực quan."

Nếu đó là sự thật, hệ thống này có tạo ra một kịch bản đổ bóng thực sự không? Làm thế nào chính xác để làm việc này?


1
Liên quan đến câu hỏi của bạn: gameangst.com/?p=441
glampert

Câu trả lời:


10

Tôi sẽ cố gắng trả lời theo kiến ​​thức tốt nhất của tôi, với ít kiến ​​thức về trường hợp cụ thể của UE4, mà là về kỹ thuật chung.

Các tài liệu dựa trên đồ thị cũng lập trình nhiều như tự viết mã. Nó chỉ không cảm thấy như vậy đối với những người không có nền tảng về mã, làm cho nó có vẻ dễ dàng hơn. Vì vậy, khi một nhà thiết kế liên kết một nút "Thêm", về cơ bản anh ta đang viết add (value1, value2) và liên kết đầu ra với một thứ khác. Đây là những gì họ có nghĩa là mỗi nút sẽ tạo mã HLSL, đó là lệnh gọi hàm hoặc chỉ là các hướng dẫn đơn giản.

Cuối cùng, việc sử dụng biểu đồ vật liệu cũng giống như lập trình các shader thô với một thư viện các hàm được xác định trước, thực hiện một số điều hữu ích phổ biến, và đó cũng là những gì UE4 làm. Nó có một thư viện mã shader mà trình biên dịch shader sẽ lấy và đưa vào nguồn shader cuối cùng khi áp dụng.

Trong trường hợp của UE4, nếu họ yêu cầu nó được chuyển đổi thành HLSL, tôi giả sử họ sử dụng một công cụ chuyển đổi có khả năng chuyển đổi mã byte HLSL thành mã byte GLSL, vì vậy nó có thể sử dụng được trên các nền tảng GL. Nhưng các thư viện khác chỉ có nhiều trình biên dịch shader, nó sẽ đọc biểu đồ và trực tiếp tạo ra các nguồn ngôn ngữ tô bóng cần thiết.

Biểu đồ vật liệu cũng là một cách hay để trừu tượng từ các chi tiết cụ thể của nền tảng và tập trung vào những gì quan trọng từ quan điểm định hướng nghệ thuật. Vì nó không bị ràng buộc với một ngôn ngữ và mức độ cao hơn nhiều, nên việc tối ưu hóa cho nền tảng đích dễ dàng hơn và tự động tiêm mã khác như xử lý ánh sáng vào trình đổ bóng.

1) Bây giờ để trả lời câu hỏi của bạn trực tiếp hơn, bạn nên có một cách tiếp cận dựa trên dữ liệu để thiết kế một hệ thống như vậy. Tìm một định dạng phẳng có thể được xác định trong các cấu trúc rất đơn giản và thậm chí được xác định trong tệp văn bản. Về bản chất, mỗi biểu đồ nên là một mảng các nút, với một loại, một tập hợp các đầu vào và đầu ra và mỗi trường này phải có một link_id cục bộ để đảm bảo các kết nối đồ thị không rõ ràng. Ngoài ra, mỗi trường trong số các trường này có thể có cấu hình bổ sung cho trường hỗ trợ (ví dụ: phạm vi loại dữ liệu nào được hỗ trợ).

Với cách tiếp cận này, bạn có thể dễ dàng xác định trường của một nút là (float | double) và để nó suy ra kiểu từ các kết nối hoặc buộc một kiểu vào đó, không có phân cấp lớp hoặc áp đảo. Tùy thuộc vào bạn để thiết kế cấu trúc dữ liệu biểu đồ này cứng nhắc hoặc linh hoạt như bạn muốn. Tất cả những gì bạn cần là nó có đủ thông tin để trình tạo mã sẽ không có sự mơ hồ và do đó có khả năng xử lý sai những gì bạn muốn làm. Điều quan trọng là ở cấp cấu trúc dữ liệu cơ bản, bạn giữ cho nó linh hoạt và tập trung vào việc giải quyết nhiệm vụ xác định một tài liệu một mình.

Khi tôi nói, "định nghĩa một vật liệu" tôi đặc biệt đề cập đến việc xác định bề mặt lưới, vượt ra ngoài những gì hình học cung cấp. Điều này bao gồm sử dụng các thuộc tính đỉnh bổ sung để định cấu hình khía cạnh của bề mặt, thêm chuyển vị cho bề mặt đó bằng sơ đồ chiều cao, làm xáo trộn các quy tắc với các thông số trên mỗi pixel, thay đổi các tham số vật lý, để thay đổi BRDF, v.v. Bạn không muốn mô tả bất cứ điều gì khác như HDR, tonemaps, skin skin, xử lý ánh sáng hoặc nhiều thứ khác được thực hiện trong shader.

2) Sau đó, tùy thuộc vào trình tạo bóng đổ của trình kết xuất để duyệt qua cấu trúc dữ liệu này và bằng cách đọc thông tin của nó, tập hợp một tập hợp các biến và liên kết chúng lại với nhau bằng cách sử dụng các hàm tiền tố và tiêm mã để tính toán ánh sáng và các hiệu ứng khác. Chỉ cần nhớ rằng các trình tạo bóng không chỉ khác nhau từ các API đồ họa khác nhau, mà còn giữa các trình kết xuất khác nhau (một trình kết xuất bị trì hoãn so với trình kết xuất chuyển tiếp so với trình kết xuất chuyển tiếp đều yêu cầu các trình tạo bóng khác nhau hoạt động) và với một hệ thống vật liệu như thế này, bạn có thể trừu tượng khỏi sự khó chịu lớp cấp thấp và chỉ tập trung vào mô tả bề mặt.

Đối với UE4, họ đã đưa ra một danh sách các thứ cho nút đầu ra cuối cùng mà bạn đề cập, mà họ nghĩ mô tả 99% bề mặt trong các trò chơi cũ và hiện đại. Họ đã phát triển bộ thông số này trong nhiều thập kỷ và chứng minh điều đó bằng số lượng trò chơi điên rồ mà công cụ Unreal đã sản xuất cho đến nay. Do đó, bạn sẽ ổn nếu bạn làm mọi thứ giống như không thật.

Để gói nó, tôi đề xuất một tệp .m vật liệu chỉ để xử lý mỗi biểu đồ. Trong quá trình phát triển, nó có thể chứa định dạng dựa trên văn bản để gỡ lỗi và sau đó được đóng gói hoặc biên dịch thành nhị phân để phát hành. Mỗi .m vật liệu sẽ được tạo bởi N nút và N kết nối, giống như cơ sở dữ liệu SQL. Mỗi nút sẽ có N trường, với một tên và một số cờ cho các loại được chấp nhận, nếu đầu vào hoặc đầu ra của nó, nếu các loại được suy ra, v.v. Cấu trúc dữ liệu thời gian chạy để giữ vật liệu được tải sẽ đơn giản và đơn giản, do đó, biên tập viên có thể dễ dàng điều chỉnh nó và lưu lại vào tập tin.

Và sau đó để lại sự nâng đỡ thực sự cho thế hệ shader cuối cùng, đây thực sự là phần khó nhất để làm. Phần hay là tài liệu của bạn không liên quan đến nền tảng kết xuất, theo lý thuyết, nó sẽ hoạt động với bất kỳ kỹ thuật kết xuất và API nào miễn là bạn thể hiện tài liệu bằng ngôn ngữ tạo bóng phù hợp.

Hãy cho tôi biết nếu bạn cần thêm chi tiết hoặc bất kỳ sửa chữa nào trong câu trả lời của tôi, tôi đã mất tổng quan về tất cả các văn bản.


Tôi không thể cảm ơn bạn đủ để viết một câu trả lời công phu và xuất sắc như vậy. Tôi cảm thấy như tôi có một ý tưởng tuyệt vời về nơi tôi nên đi từ đây! Cảm ơn!
MrKatSwordfish

1
Không có vấn đề bạn đời, hãy nhắn tin cho tôi nếu bạn cần thêm trợ giúp. Tôi thực sự đang làm việc trên một cái gì đó tương đương cho các công cụ của riêng tôi, vì vậy nếu bạn muốn trao đổi suy nghĩ, hãy là khách của tôi! Chúc bạn buổi chiều vui vẻ: D
Grimshaw
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.