그래프 기반 머티리얼 시스템에서 다양한 입력 및 출력 유형을 어떻게 지원할 수 있습니까?


11

여기에 이미지 설명을 입력하십시오

내가 좋아하는 재료 시스템 어떻게 내 머리 주위에 포장하기 위해 노력하고있어 이는 , 구현됩니다. 이 강력하고 사용자 친화적 인 그래프 형 시스템은 프로그래머와 프로그래머가 아닌 사람이 모두 셰이더를 빠르게 만들 수있는 방법 으로 비교적 일반적 으로 보입니다 . 그러나 그래픽 프로그래밍에 대한 상대적으로 제한된 경험으로 인해 어떻게 작동하는지 확실하지 않습니다.


배경:

따라서 이전에 간단한 OpenGL 렌더링 시스템을 프로그래밍 한 경우 일반적으로 수동으로 만든 정적 GLSL 파일에서 셰이더를로드, 컴파일 및 링크하는 Material 클래스를 만듭니다. 또한 보통이 클래스를 GLSL 균일 변수에 액세스하기위한 간단한 래퍼로 만듭니다. 간단한 예로, 기본 정점 셰이더와 프래그먼트 셰이더가 있고 텍스처를 전달하기 위해 균일 한 Texture2D가 있다고 상상해보십시오. 내 머티리얼 클래스는 단순히이 두 쉐이더를 머티리얼에로드하고 컴파일하며, 그 시점부터 해당 쉐이더의 Texture2D 유니폼을 읽고 쓰는 간단한 인터페이스를 노출시킵니다.

이 시스템을 좀 더 융통성있게 만들기 위해, 나는 보통 어떤 이름 / 유형의 유니폼이라도 전달할 수있는 방식으로 작성합니다 . 이것은 AmbientColor 균일 성을 머티리얼에 존재하는 경우 "colorVec4"라는 특정 4d 벡터로 설정합니다.] .

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..
}

이것은 작동 하지만 Material 클래스의 클라이언트가 믿음으로 유니폼에 액세스해야한다는 사실 때문에 나쁜 시스템처럼 느껴집니다. 사용자는 각 머티리얼 객체에있는 유니폼을 알고 있어야합니다. GLSL 이름으로 전달하십시오. 시스템을 사용하는 사람이 1-2 명인 경우에는 큰 문제가되지 않지만이 시스템이 전혀 확장되지 않을 것이라고 생각할 수 없으며 OpenGL 렌더링 시스템을 프로그래밍하기 위해 다음 시도를하기 전에 레벨을 조정하고 싶습니다. 조금 위로.


질문:

그것이 지금까지의 위치이므로 다른 렌더링 엔진이 머티리얼 시스템을 처리하는 방법을 연구하려고 노력했습니다.

이 노드 기반 접근 방식은 훌륭 하며 현대 엔진 및 도구에서 사용자 친화적 인 재료 시스템을 생성하기위한 매우 일반적인 시스템 인 것 같습니다. 내가 말할 수 있는 것은 각 노드가 머티리얼의 일부 쉐이더 측면을 나타내고 각 경로는 그들 사이의 일종의 관계를 나타내는 그래프 데이터 구조를 기반으로한다는 것입니다.

내가 알 수 있듯이, 그러한 종류의 시스템을 구현하는 것은 다양한 서브 클래스 (TextureNode, FloatNode, LerpNode 등)를 가진 단순한 MaterialNode 클래스 일 것입니다. 각 MaterialNode 서브 클래스에 MaterialConnections가있는 곳.

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

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

    MatNode_Out result;
}

이것이 가장 기본적인 아이디어이지만,이 시스템의 몇 가지 측면이 어떻게 작동하는지에 대해서는 조금 불확실합니다.

1.) Unreal Engine 4에서 사용 하는 다양한 'Material Expressions'(노드)를 보면 각각 다양한 유형의 입력 및 출력 연결이 있음을 알 수 있습니다. 일부 노드 출력 플로트, 일부 출력 벡터 2, 일부 출력 벡터 4 등 다양한 입력 및 출력 유형을 지원할 수 있도록 노드 및 연결을 개선하려면 어떻게해야합니까? MatNode_Out_Float 및 MatNode_Out_Vec4 등으로 MatNode_Out을 서브 클래 싱하는 것이 현명한 선택입니까?

2.) 마지막으로, 이런 종류의 시스템은 GLSL 쉐이더와 어떤 관련이 있습니까? UE4를 다시 살펴보면 (그리고 위에 링크 된 다른 시스템과 유사하게), 사용자는 쉐이더 매개 변수 (기본 색상, 금속성, 광택, 방사율 등)를 나타내는 다양한 매개 변수가있는 일부 노드를 큰 노드에 연결해야합니다. . 필자의 원래 가정은 UE4에 다양한 유니폼이있는 일종의 하드 코딩 된 '마스터 셰이더'가 있으며, '재료'에서 사용자가하는 모든 것은 노드를 '마스터 셰이더'에 전달하는 것입니다. 마스터 노드 '.

그러나 UE4 문서 에는 다음이 명시되어 있습니다.

"각 노드에는 특정 작업을 수행하도록 지정된 HLSL 코드가 포함되어 있습니다. 이는 머티리얼을 구성 할 때 시각적 스크립팅을 통해 HLSL 코드를 생성한다는 의미입니다."

그것이 사실이라면, 이 시스템은 실제 셰이더 스크립트를 생성합니까? 이것이 정확히 어떻게 작동합니까?


1
질문과 관련이 있습니다 : gameangst.com/?p=441
glampert

답변:


10

UE4의 특정 사례에 대한 지식은 거의 없지만 일반적인 기술에 대한 지식으로 최대한의 지식을 얻으려고 노력할 것입니다.

그래프 기반 자료는 코드를 직접 작성하는 것만 큼 많은 프로그래밍입니다. 코드에 대한 배경 지식이없는 사람들에게는 느낌이 들지 않으므로 더 쉽게 보일 수 있습니다. 따라서 디자이너가 "Add"노드를 연결할 때 기본적으로 add (value1, value2)를 작성하고 출력을 다른 것에 연결합니다. 이것이 바로 각 노드가 함수 호출이나 간단한 명령 인 HLSL 코드를 생성한다는 의미입니다.

결국 머티리얼 그래프를 사용하는 것은 일반적인 유용한 기능을 수행하는 미리 정의 된 함수 라이브러리를 사용하여 원시 셰이더를 프로그래밍하는 것과 비슷하며 UE4도 마찬가지입니다. 여기에는 셰이더 컴파일러가 적용 가능한 경우 최종 셰이더 소스로 가져 와서 주입하는 셰이더 코드 라이브러리가 있습니다.

UE4의 경우 HLSL로 변환되었다고 주장하면 HLSL 바이트 코드를 GLSL 바이트 코드로 변환 할 수있는 변환기 도구를 사용한다고 가정하므로 GL 플랫폼에서 사용할 수 있습니다. 그러나 다른 라이브러리에는 여러 셰이더 컴파일러가 있으며 그래프를 읽고 필요한 음영 언어 소스를 직접 생성합니다.

머티리얼 그래프는 플랫폼 별 세부 정보를 추상화하고 예술적인 관점에서 중요한 것에 집중할 수있는 좋은 방법이기도합니다. 언어에 의존하지 않고 수준이 높기 때문에 대상 플랫폼에 최적화하기 쉽고 라이트 핸들링과 같은 다른 코드를 셰이더에 동적으로 삽입합니다.

1) 이제 귀하의 질문에보다 직접적으로 대답하려면 그러한 시스템을 설계하는 데 데이터 중심의 접근 방식이 있어야합니다. 매우 평범한 구조로 정의 할 수 있고 텍스트 파일로 정의 할 수있는 플랫 형식을 찾으십시오. 본질적으로 각 그래프는 유형, 입력 및 출력 세트가있는 노드의 배열이어야하며 이러한 각 필드에는 그래프 연결이 명확하도록 로컬 link_id가 있어야합니다. 또한 이러한 각 필드는 필드가 지원하는 항목 (예 : 지원되는 데이터 유형 범위)에 대한 추가 구성을 가질 수 있습니다.

이 접근 방식을 사용하면 노드 필드를 쉽게 (float | double) 것으로 정의하고 클래스 계층 구조 나 오버 엔지니어링없이 연결에서 유형을 유추하거나 유형을 강제로 지정할 수 있습니다. 이 그래프 데이터 구조를 원하는대로 단단하거나 유연하게 디자인 할 수 있습니다. 코드 생성기에 모호함이 없으므로 원하는 정보를 잘못 처리 할 수 ​​있도록 충분한 정보가 있어야합니다. 중요한 것은 기본 데이터 구조 수준에서 유연성을 유지하고 자재 만 정의하는 작업을 해결하는 데 집중해야한다는 것입니다.

"소재 정의"라고 말하면 지오메트리 자체가 제공하는 것 이상의 메시 표면 정의를 매우 구체적으로 언급합니다. 여기에는 추가 정점 속성을 사용하여 표면의 측면을 구성하고, 높이 맵을 사용하여 표면에 변위를 추가하고, 픽셀 당 법선으로 법선을 방해하고, 물리적 기반 매개 변수를 변경하고, BRDF 등을 변경하는 등이 포함됩니다. HDR, 톤 매핑, 스키닝 애니메이션, 라이트 핸들링 또는 셰이더에서 수행되는 다른 많은 것들을 설명하고 싶지 않습니다.

2) 그런 다음 렌더러의 쉐이더 생성기에서이 데이터 구조를 탐색하고 해당 정보를 읽어 변수 세트를 조립하고 사전 작성된 함수를 사용하여 조명과 기타 효과를 계산하는 코드를 주입하여 연결합니다. 셰이더는 다른 그래픽 API뿐만 아니라 다른 렌더러 (디퍼 드 렌더링 대 타일 기반 vs 포워드 렌더러 모두 작동하려면 서로 다른 셰이더가 필요함)마다 다르며, 이와 같은 머티리얼 시스템을 사용하면 불쾌한 부분에서 추상화 할 수 있습니다 낮은 수준의 층으로 표면을 묘사하는 데에만 집중하십시오.

UE4의 경우, 여러분이 언급 한 최종 출력 노드에 대한 목록을 생각해 냈습니다. 구식 및 현대 게임에서 표면의 99 %를 설명합니다. 그들은 수십 년에 걸쳐 이러한 매개 변수 세트를 개발했으며 지금까지 Unreal 엔진이 제작 한 엄청난 양의 게임으로 증명했습니다. 따라서 비현실적인 방식으로 일을하면 괜찮을 것입니다.

마무리하기 위해 각 그래프를 처리하기 위해 .material 파일을 제안합니다. 개발 중에는 디버깅 할 텍스트 기반 형식을 포함하고 릴리스를 위해 바이너리로 패키지하거나 컴파일 할 수 있습니다. 각 .material은 SQL 데이터베이스와 매우 유사한 N 개의 노드와 N 개의 연결로 구성됩니다. 각 노드에는 N 필드가 있으며, 입력 또는 출력, 유형이 유추 된 경우 등 유형에 대한 이름 및 일부 플래그가 허용됩니다.로드 된 재질을 보유하는 런타임 데이터 구조는 평평하고 단순합니다. 편집기는 쉽게 적용하여 파일로 다시 저장할 수 있습니다.

그런 다음 최종 셰이더 생성을 위해 실제 무거운 부분을 남겨 두십시오. 실제로 가장 어려운 부분입니다. 아름다운 부분은 머티리얼이 렌더링 플랫폼에 독립적으로 유지된다는 것입니다. 이론적으로 머티리얼을 적절한 쉐이딩 언어로 표현하는 한 모든 렌더링 기술 및 API와 작동합니다.

추가 답변이나 수정 사항이 필요하면 알려주십시오. 모든 텍스트에 대한 개요를 잃어 버렸습니다.


정교하고 훌륭한 답변을 작성해 주셔서 감사합니다. 나는 내가 여기서 어디로 가야할지에 대한 좋은 생각이있는 것 같습니다! 감사!
MrKatSwordfish 2014

1
문제가없는 배우자입니다. 추가 도움이 필요하면 언제든지 메시지를 보내주십시오. 나는 실제로 내 자신의 도구와 동등한 것을 연구하고 있으므로 생각을 교환하고 싶다면 내 손님이 되십시오! 좋은 오후 되세요 : D
그림 쇼
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.