나만의 장면 그래프 구르기


23

안녕하세요 게임 개발 SE!

간단 하고 매우 가벼운 게임 엔진 을 만들 겠다는 희망으로 OpenGL을 탐색하고 있습니다. 나는이 프로젝트를 결국에는 약간의 돈을 벌 수있는 학습 경험으로 보지만 어느 쪽이든 재미있을 것입니다.

지금까지 GLFW를 사용하여 몇 가지 기본 I / O, 창 (아주 멋진 F11 전체 화면 키 포함) 및 OpenGL 컨텍스트를 얻었습니다. 또한 Windows를 사용하고 있고 모든 OpenGL 3.0 이상을 사용하고 싶기 때문에 GLEW를 사용하여 나머지 OpenGL 확장을 노출했습니다.

장면 그래프가 나타납니다. 요컨대, 나는 내 자신의 롤을하고 싶습니다. 이 결정은 OSG를보고 장면 그래프의 개념이 어떻게 왜곡되고 구부러지고 깨지는 지에 대한 몇 가지 기사를 읽은 후에 이루어졌습니다. 그러한 기사 중 하나 는 장면 그래프가 어떻게 발전했는지 설명했습니다 ...

그런 다음 장식품 중 일부는 멋진 육즙이 많은 스테이크이고 일부는 전체 살아있는 소라는 것을 제외하고는 크리스마스 트리에 장식품을 매달는 것과 같이이 여분의 모든 것을 추가했습니다.

유추에 따르면, 스테이크, 장면 코드가 필요한 고기, 여분의 코드 더미 또는 전체 소를 묶을 필요가 없습니다.

그래서 그것을 염두에두고, 장면 그래프가 무엇인지, 간단한 장면 그래프를 어떻게 구현 해야하는지 궁금해합니다. 여기까지 내가 가진 것입니다 ...

하나의 부모, n- 자식 트리 또는 DAG ...

  • 게임 오브젝트 변형 (위치, 회전, 스케일)을 추적해야합니다.
  • 최적화를 위해 렌더링 상태를 유지해야합니다
  • 뷰 프러스 텀 내에 있지 않은 오브젝트 컬링 수단을 제공해야합니다.

다음과 같은 속성으로 ...

  • 모든 노드는 렌더링 할 수없는 것으로 취급해야합니다 (렌더링하지 않더라도).

    • 모두 cull (), state () 및 draw () 메서드가 있어야합니다 (표시되지 않는 경우 0을 반환 함)
    • cull ()은 모든 자식에서 cull ()을 재귀 적으로 호출하여 전체 노드와 모든 자식에 대해 완전한 컬 메시를 생성합니다. 또 다른 방법 인 hasChanged ()를 사용하면 소위 스태틱 메시가 각 프레임마다 컬링 지오메트리를 계산할 필요가 없습니다. 하위 트리의 노드가 변경된 경우 루트까지 모든 지오메트리가 다시 작성되도록 작동합니다.
  • 렌더 상태는 간단한 열거로 유지되며 각 노드는이 열거에서 필요한 OpenGL 상태 세트를 선택하며 해당 노드에서 draw ()가 호출되기 전에 해당 상태가 설정됩니다. 이를 통해 일괄 처리가 가능하며 주어진 상태 세트의 모든 노드가 함께 렌더링 된 후 다음 상태 세트가 설정됩니다.

  • 노드는 지오메트리 / 쉐이더 / 텍스처 데이터를 직접 보유해서는 안되며 대신 노드는 공유 객체 (아마도 리소스 관리자와 같은 단일 객체로 관리)를 가리켜 야합니다.

  • 장면 그래프 같은 상황 있도록 (아마도 프록시 노드를 사용하여) 다른 장면 그래프를 참조 할 수 있어야 이를 따라서 모델 멀티 메쉬 복잡한 / 데이터의 톤을 추가하지 않고 장면 그래프의 주위에 복사 할 개체 수.

현재 디자인에 대한 귀중한 피드백을 받기를 바랍니다. 기능이 없습니까? 훨씬 더 좋은 방법 / 디자인 패턴이 있습니까? 다소 단순한 3D 게임을 위해이 디자인에 포함되어야 할 더 큰 개념이 누락 되었습니까? 기타.

고마워

답변:


15

개념

기본적으로 장면 그래프는 계층 구조 구조의 공간 관계를 나타내는 Bi-directed acyclic 그래프에 지나지 않습니다.

야생의 엔진은 언급 된 바와 같이 장면 그래프에 다른 장점을 포함시키는 경향이 있습니다. 육류 또는 소로 볼지 여부는 엔진과 라이브러리에 대한 경험에 달려있을 것입니다.

경량 유지

나는 장면 그래프 노드 (심장에 공간 / 지형 구조가 아닌 토폴로지)가 본질적으로 공간 매개 변수와 기능을 포함하는 Unity3D 스타일을 선호합니다. 내 엔진에서 노드는 Unity3D보다 가벼워 수퍼 클래스 / 구현 된 인터페이스에서 불필요한 정크 멤버를 상속받습니다.

  • 부모 / 자식 포인터 멤버.
  • 사전 변환 공간 매개 변수 멤버 : xyz 위치, 피치, 요 및 롤.
  • 변환 매트릭스; 계층 적 체인의 행렬은 트리를 반복적으로 위 / 아래로 걸어서 매우 쉽고 빠르게 곱할 수 있으며 장면 그래프의 주요 특징 인 계층 적 공간 변환을 제공합니다.
  • 노드의 변환 행렬 만을updateLocal() 갱신 하는 메소드
  • 노드 와 모든 자손 노드의 변환 매트릭스 updateAll()를 갱신 하는 메소드

... 또한 모션 방정식 논리 및 노드 클래스의 속도 / 가속도 멤버 (선형 및 각도)도 포함합니다. 이를 잊어 버릴 수 있으며 원하는 경우 메인 컨트롤러에서 처리 할 수 ​​있습니다. 그러나 그것은 실제로 매우 가볍습니다. 수천 개의 엔티티에이를 가질 수 있음을 기억하십시오. 제안한대로 가볍게 유지하십시오.

계층 구조 생성

다른 장면 그래프를 참조하는 장면 그래프에 대해 어떻게 말하는가 ... 펀치 라인을 기다리고 있습니까? 물론 그렇습니다. 그것이 그들의 주요 용도입니다. 다른 노드에 노드를 추가 할 수 있으며 변환은 새 변환의 로컬 공간 내에서 자동으로 수행되어야합니다. 당신이하고있는 일은 포인터를 변경하는 것입니다. 데이터를 복사하는 것과는 다릅니다! 포인터를 변경하면 더 깊은 장면 그래프가 생깁니다. 프록시를 사용하면 업무 효율성이 높아지지만 그 필요성을 본 적이 없습니다.

렌더 관련 로직 방지

장면 그래프 노드 클래스를 작성할 때 렌더링하는 것을 잊어 버리십시오. 중요한 것은 장면 그래프이든 아니든 상관없이 데이터 모델이 있고 일부 렌더러는 데이터 모델을 검사하여 그에 따라 세계의 오브젝트를 1, 2로 렌더링한다는 것입니다. , 3 또는 7 치수. 내가하고있는 요점은 : 렌더 로직으로 장면 그래프를 오염시키지 마십시오. 장면 그래프는 토폴로지 및 지형, 즉 연결 및 공간 특성에 관한 것입니다. 이는 시뮬레이션의 실제 상태이며 렌더링이없는 경우에도 존재합니다 (1 인칭 시점에서 통계 그래프, 텍스트 설명에 이르기까지 태양 아래 어떤 형태로든 가능). 노드는 렌더링 관련 객체를 가리 키지 않지만 반대의 경우도 마찬가지입니다. 또한 이것을 고려하십시오 : 전체 트리의 모든 장면 그래프 노드를 렌더링 할 수있는 것은 아닙니다. 많은 사람들이 단지 용기 일 것입니다. 그렇다면 렌더링 대상 객체에 메모리를 할당해야하는 이유는 무엇입니까? 결코 사용되지 않은 포인터 멤버조차도 여전히 메모리를 차지하고 있습니다. 따라서 포인터 방향을 반대로하십시오. 렌더 관련 인스턴스는 데이터 모델 (장면 그래프 노드이거나 포함 할 수 있음)을 참조하며 그 반대도 아닙니다. 그리고 컨트롤러 목록을 쉽게 실행하면서 관련 뷰에 액세스하려면 O (1) 읽기 액세스 시간에 접근하는 사전 / 해시 테이블을 사용하십시오. 그렇게하면 오염이없고 시뮬레이션 로직은 렌더러가 어디에 있는지 신경 쓰지 않으므로 밤낮으로 코딩 할 수 있습니다. 그렇다면 렌더링 대상 객체에 메모리를 할당해야하는 이유는 무엇입니까? 결코 사용되지 않은 포인터 멤버조차도 여전히 메모리를 차지하고 있습니다. 따라서 포인터 방향을 반대로하십시오. 렌더 관련 인스턴스는 데이터 모델 (장면 그래프 노드이거나 포함 할 수 있음)을 참조하며 그 반대도 아닙니다. 그리고 컨트롤러 목록을 쉽게 실행하면서 관련 뷰에 액세스하려면 O (1) 읽기 액세스 시간에 접근하는 사전 / 해시 테이블을 사용하십시오. 그렇게하면 오염이없고 시뮬레이션 로직은 렌더러가 어디에 있는지 신경 쓰지 않으므로 밤낮으로 코딩 할 수 있습니다. 그렇다면 렌더링 대상 객체에 메모리를 할당해야하는 이유는 무엇입니까? 결코 사용되지 않은 포인터 멤버조차도 여전히 메모리를 차지하고 있습니다. 따라서 포인터 방향을 반대로하십시오. 렌더 관련 인스턴스는 데이터 모델 (장면 그래프 노드이거나 포함 할 수 있음)을 참조하며 그 반대도 아닙니다. 그리고 컨트롤러 목록을 쉽게 실행하면서 관련 뷰에 액세스하려면 O (1) 읽기 액세스 시간에 접근하는 사전 / 해시 테이블을 사용하십시오. 그렇게하면 오염이없고 시뮬레이션 로직은 렌더러가 어디에 있는지 신경 쓰지 않으므로 밤낮으로 코딩 할 수 있습니다. 그리고 컨트롤러 목록을 쉽게 실행하면서 관련 뷰에 액세스하려면 O (1) 읽기 액세스 시간에 접근하는 사전 / 해시 테이블을 사용하십시오. 그렇게하면 오염이없고 시뮬레이션 로직은 렌더러가 어디에 있는지 신경 쓰지 않으므로 밤낮으로 코딩 할 수 있습니다. 그리고 컨트롤러 목록을 쉽게 실행하면서 관련 뷰에 액세스하려면 O (1) 읽기 액세스 시간에 접근하는 사전 / 해시 테이블을 사용하십시오. 그렇게하면 오염이없고 시뮬레이션 로직은 렌더러가 어디에 있는지 신경 쓰지 않으므로 밤낮으로 코딩 할 수 있습니다.세상이 더 쉬워졌습니다.

컬링은 위를 참조하십시오. 관심 영역 컬링은 시뮬레이션 논리 개념입니다. 즉,이 상자 (일반적으로 박스형, 원형 ​​또는 구형) 외부의 세계를 처리하지 않습니다. 렌더링이 발생하기 전에 메인 컨트롤러 / 게임 루프에서 발생합니다. 반면에, 절두체 컬링은 순전히 렌더 관련입니다. 따라서 지금 컬링을 잊어 버리십시오. 장면 그래프와는 아무런 관련이 없으며, 초점을 맞추면 달성하려는 목표의 실제 목적을 모호하게됩니다.

마지막 주 ...

여기에 포함 된 렌더링에 대한 모든 세부 사항을 고려하면 Flash (특히 AS3) 배경에서 오는 느낌이 듭니다. 예, Flash Stage / DisplayObject 패러다임에는 장면 그래프의 일부로 모든 렌더링 논리가 포함됩니다. 그러나 Flash는 반드시 원하지 않는 많은 가정을합니다. 본격적인 게임 엔진의 경우 적절한 SoC를 통해 성능, 편의성 및 코드 복잡성을 제어하기 위해 두 가지를 혼합하지 않는 것이 좋습니다 .


1
고마워 닉. 저는 실제로 3D 애니메이터 (실제 3D 플래시가 아님)가 된 프로그래머이므로 그래픽 측면에서 생각하는 경향이 있습니다. 그것이 나쁘지 않다면, 나는 Java로 시작하여 그 언어로 주입 된 "모든 것이 객체 여야한다"라는 생각에서 스스로를 훔쳐왔다. 장면 그래프를 렌더링 및 컬링 코드와 분리해야한다고 확신했습니다. 이제 내 기어가 정확히 어떻게 수행되는지를 결정하고 있습니다. 변환 데이터 등의 장면 그래프를 참조하는 고유 한 시스템처럼 렌더러를 처리하려고합니다.
Cody Smith

1
@CodySmith, 기뻤습니다. 뻔뻔한 플러그,하지만 SoC / MVC에 관한 프레임 워크 를 유지합니다 . 그렇게하면서 모든 것이 중앙의 모 놀리 식 객체에 있어야한다고 주장하는 업계의 더 전통적인 캠프를 시작하게되었습니다. 그러나 그들은 일반적으로 당신에게 말할 것입니다-렌더링을 장면 그래프와 분리하십시오. SoC / SRP는 내가 충분히 강조 할 수없는 것입니다. 필요한 것보다 더 많은 로직을 단일 클래스에 혼용하지 마십시오. 나는 당신이 내 머리에 총을 넣으면 같은 클래스의 혼합 논리보다 복잡한 OO 상속 체인을 옹호합니다!
엔지니어

아니, 나는 개념을 좋아한다. 그리고 당신의 권리, 이것은 게임 디자인에 관해 수년 동안 읽은 SoC에 대한 첫 번째 언급입니다. 다시 감사합니다.
코디 스미스

@CodySmith 다시 탐색하는 동안 빠른 생각. 일반적으로 사물을 분리하는 것이 좋습니다. 렌더링을 거칩니다 코드베이스의 모델 컨트롤러 객체의 다양한 유형의 경우, 그러나, 이다 당신의 컬렉션을 유지하기위한 좋은 Renderable그 핵심 모델 컨트롤러 객체에 내부적으로 (인터페이스 또는 추상 클래스 인)들. 이것의 좋은 예는 엔티티 또는 UI 요소입니다. 따라서 엔티티 클래스를 오염시키는 인터페이스를 사용하지 않는 구현 세부 사항없이 특정 코어 객체와 관련된 렌더러에만 빠르게 액세스 할 수 있습니다.
엔지니어

@CodySmith 예를 들어 엔터티를 사용하면 이점이 분명합니다. 월드 뷰포트와 미니 맵에 모두 표시됩니다. 따라서 컬렉션입니다. 또는 각 모델 컨트롤러 객체에 대해 해당 객체 내부에 단일 렌더러 슬롯 만 허용 할 수 있습니다. 그러나 일반적인 인터페이스를 유지하십시오! 구체적인 사항은 없습니다 Renderer.
엔지니어
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.