[3D 게임 개발 실습] Cocos Cyberpunk 소스 코드 해석 - 지연 렌더링 파이프라인의 원리와 실습을 얻는 하나의 기사

Cocos Cyberpunk는 엔진의 강력한 3D 게임 제작 능력을 시연하고 커뮤니티의 학습 동기를 향상시키기 위해 Cocos 엔진의 공식 팀에서 출시한 완전한 오픈 소스 TPS 3D 게임으로 웹, IOS 및 Android 멀티 터미널 릴리스를 지원합니다.

이 기사 시리즈는 모든 사람의 학습 효율성을 향상시키기 위해 다양한 측면에서 소스 코드를 해석합니다. 3D 게임 개발의 길을 더 나아가는 데 도움이 되기를 바랍니다.

프로젝트 소스 코드 무료 다운로드 페이지:
https://store.cocos.com/app/detail/4543

메인 콘텐츠

지연 렌더링 기술은 2004년 GDC에서 공식적으로 제안되었지만 거의 20년이 지났지만 대부분의 친구들, 특히 3D 프로그래밍이 처음인 사람들은 여전히 ​​세부 사항을 모릅니다.

이 문서는 길지 않지만 몇 가지 사항을 간략하게 설명합니다.

  1. 지연 렌더링 기술이 참여하는 렌더링 링크
  2. 지연 렌더링 기술이 해결 하는 문제
  3. 지연 렌더링 기술 원리 분석
  4. Cocos Cyberpunk의 지연 렌더링 파이프라인 구현 세부 정보
  5. 지연 렌더링 기술 메모리, 호환성, GPU 하드웨어 매개변수
  6. 투명한 렌더링 솔루션

새로운 친구들에게 : 코코스 사이버펑크는 코코스 엔진 공식팀이 엔진의 중후한 3D 게임 제작 능력을 시연하고 커뮤니티의 학습 동기를 높이기 위해 출시한 완전 오픈소스 TPS 3D 게임으로 웹, IOS, 안드로이드 멀티터미널을 지원한다. 릴리스. 프로젝트 소스 코드 무료 다운로드 페이지로 들어가려면 원본 텍스트를 읽으려면

클릭하십시오 .

인터넷에는 포워드 렌더링과 디퍼드 렌더링에 대한 비교 차트와 순서도가 많이 있습니다.

그러나 시청을 하지 않는 것과 동일하게 만드는 몇 가지 매우 심각한 문제가 있습니다.

  1. 너무 학구적이고 고급스러운 단어지만 모호함
  2. 지연 렌더링 기술의 작업 경계를 명확히 하지 않아 사람들이 지연 렌더링이 모든 문제를 해결할 수 있다고 잘못 생각하게 함
  3. 실제 사례와 결합되지 않아 읽은 후 잊어버리고 학습한 후 폐기됩니다.

Qilinzi는 Cocos Cyberpunk 오픈 소스 프로젝트 의 소스 코드와 결합하여 오늘 간단하고 직설적으로 설명하려고 노력했습니다 .

Cocos Cyberpunk 프로덕션 팀 에게 다시 한 번 감사드립니다 . 이 오픈 소스 프로젝트가 없었다면 이 주제를 공유할 엔지니어링 수준의 사례가 없었을 것입니다.

참여

기술의 원리를 이해하려면 기술이 참여하는 링크와 기술이 나타나는 이유를 이해해야 합니다.

작업 경계를 알고 적절한 적용 사례를 결정하여 남용을 방지합니다.

지연된 렌더링에 대한 많은 기사가 있지만 전체 렌더링 프로세스에서 지연된 렌더링과 관련된 특정 링크를 언급하는 사람은 거의 없습니다.

지연 렌더링이 모든 것을 할 수 있다고 생각하지만 실제로는 작은 부분만 참여합니다.

다음으로 엔진의 일반적인 3D 렌더링 프로세스인 그림자 맵 렌더링 --> 주요 장면 렌더링 --> 효과 후 화면 렌더링 --> 2D&UI 렌더링 을 살펴보겠습니다 .

1. 섀도우 맵 렌더링

이 단계에서 장면의 모든 개체는 통합된 재질로 렌더링되어 다음 렌더링 단계에서 사용할 그림자 맵을 생성합니다.

2. 장면 렌더링

이 단계는 일반 렌더링 단계로 장면의 모든 객체를 렌더링하고 그림자 맵을 사용하여 그림자를 생성하며 조명 계산을 수행하고 다양한 질감을 생성합니다.
장면의 객체는 불투명 객체반투명 객체 의 두 가지 범주로 나눌 수 있으며 서로 다르게 처리됩니다.

3. 화면 공간에 따른 효과 렌더링

이 단계에서 적절한 이미지 알고리즘을 사용하여 렌더링된 장면 콘텐츠에 대한 일부 특수 처리를 수행하여 그림 효과를 향상시킵니다.

4. 2D/UI 렌더링

카메라와 함께 변경되지 않는 일부 2D 요소, UI 요소는 이 단계에서 렌더링됩니다.

위는 핵심 표준 렌더링 프로세스일 뿐이며 일부 프로젝트는 필요에 따라 사용자 정의되며 일부 특수 목적 렌더링 프로세스가 추가됩니다.

이러한 긴 렌더링 프로세스에서 지연 렌더링은 주로 장면 렌더링 프로세스에서 불투명 개체를 대상으로 합니다.

나머지 작업은 포워드 렌더링과 디퍼드 렌더링 파이프라인에서 거의 동일하며 큰 차이는 없습니다.

상상했던 것과 다른가요?

그럼 다음으로 왜 탄생했는지 알아보자.

포워드 렌더링의 문제

지연 렌더링은 이 부분에만 참여하므로 다음 설명은 장면 렌더링 프로세스에만 적용됩니다.

위의 시나리오에는 다음이 있습니다.

  • 10개 모델(1개 평면, 9개 큐브)
  • 광원 7개(평행광 1개, 구형광 7개)

포워드 렌더링을 사용하는 방법은 다음과 같습니다.

  1. 모델을 가져와 렌더링을 위해 그래픽 카드에 제출
  2. 정점 셰이더에서 정점 변환, UV 등 처리
  3. Fragment Shader에서 조명 계산을 위해 7개의 광원이 차례로 사용됩니다.
  4. 다음 모델 처리

모델이 10개이므로 위의 과정을 10번 거쳐야 하고 각 모델은 7개의 광원으로 조명 계산을 수행해야 함을 쉽게 알 수 있습니다.

그런 다음 전체 조명 작업을 10 * 7 = 70 번 수행해야 합니다.

주로 두 가지 문제가 발생합니다.

1. 셰이더 명령 제한 사항

특정 개수의 조명만 지원할 수 있습니다. 조명의 수가 특정 값을 초과하면 조명 계산을 완료하기 위해 여러 렌더링이 필요합니다.

2. GPU 컴퓨팅 파워의 낭비

조명 계산은 특히 PBR 재질의 경우 렌더링에서 가장 비용이 많이 드는 부분입니다.

위의 렌더링 프로세스에서 모델의 가려진 일부 부분은 최종적으로 보이지 않지만 여전히 조명 계산에 참여하므로 낭비가 발생합니다.

장면이 매우 크고 많은 모델과 광원이 있는 경우 이 두 가지 문제가 얼마나 심각한지 상상해 보십시오.

지연 렌더링의 등장으로 이 두 가지 문제가 해결되었습니다.

지연 렌더링의 원리와 이 두 가지 문제를 해결하는 데 왜 좋은지 살펴보겠습니다.

지연 렌더링 분석

두 단계만

1. 준비 단계(기하학적 렌더링)

이 단계에서 모델의 조명을 계산하는 데 필요한 기본 정보는 월드 공간 위치 정보, 일반 정보, 색상 정보, 깊이 정보 등과 같은 다른 RenderTexture에 렌더링 및 저장됩니다.

2. 일루미네이션 스테이지

조명 단계는 이름에서 알 수 있듯이 이전 단계에서 렌더링된 RenderTexture를 장면의 조명 데이터와 결합하여 픽셀의 최종 색상 값을 계산하는 것입니다.

지연 렌더링에서 지연의 원인이 되는 두 번째 단계에서 픽셀의 색상 계산이 균일하게 수행됨을 알 수 있습니다.

두 번째 단계에서 픽셀의 색상 계산이 통합되기 때문에 가려진 모델 부분의 픽셀이 깊이 테스트에 의해 제거되어 불필요한 계산을 크게 피하고 성능을 향상시킵니다.

G버퍼

GBuffer의 정의

지연 렌더링 기술에서 가장 중요한 개념은 GBuffer 입니다 .

GBuffer는 Geometry Buffer의 약자로 기하학 정보를 저장하는 버퍼를 의미합니다. 좀 더 구체적으로 말하자면 위에서 언급한 지오메트리 렌더링 단계에서 객체의 위치, 법선, 색상 및 기타 정보를 설명하는 데 사용되는 RenderTexture의 조합입니다.

따라서 위에서 언급한 지오메트리 렌더링 단계는 일반적으로 GBuffer 단계 라고도 합니다.

지연된 렌더링은 단지 아이디어일 뿐이며 다양한 버전이 있다는 점은 주목할 가치가 있습니다. GBuffer의 RenderTexture에 저장되는 것은 균일하지 않습니다.

엔진 엔지니어가 지연 렌더링 파이프라인을 구현할 때 요구 사항에 따라 적절한 조합을 선택합니다.

GBuffer 콘텐츠 구성

조명 계산을 완료하려면 몇 가지 기본 정보가 필요합니다. 예를 들어:

  • 월드 공간에서의 위치 정보
  • 세계 공간 법선 정보
  • 개체 표면 색상 정보

그러나 그 외에 무엇이 더 필요합니까?

GBuffer는 주로 조명 계산에 필요한 정보를 제공하므로 GBuffer의 내용을 이해하기 위해서는 관련 조명 계산 내용을 이해할 필요가 있다.

조명 계산은 3D 그래픽 렌더링의 핵심 이슈로, 그래픽 렌더링에 대한 대부분의 연구는 조명 계산을 중심으로 이루어지므로 한두 단락으로 설명할 수 없습니다.

그러나 모든 사람이 GBuffer를 더 잘 이해하게 하려면 개념만 이해하면 됩니다.

Blinn-Phong 이든 PBR 이든 모두 가장 기본적인 조명 공식을 따릅니다.

물체의 최종 색상 = 주변광 + 난반사 + 정반사 + 자체 조명

이 네 부분의 계산을 다룰 때 두 사람이 사용하는 데이터와 계산 방법이 다를뿐입니다.

주변광 : Blinn-Phong에서는 상수이고 PBR에서는 모델 재료 매개변수의 영향을 받습니다.

난반사 : 모델 재료 및 조명 매개변수에 따라 결정됩니다.

정반사 : 모델 재료 매개변수, 조명 매개변수 및 관측 위치에 따라 결정됨

자체 조명 : 모델 재질의 Emissive 관련 매개변수에 의해 결정됩니다.

Blinn-Phong에서 사용되는 공식은 매우 단순하며 대부분 상수와 간단한 벡터 연산 공식으로 구성됩니다.

그러나 PBR에서 사용되는 조명 계산 공식은 매우 복잡합니다.예를 들어 Cook-Torrance BRDF 모델을 사용하여 객체의 확산 반사 및 정반사를 계산합니다. Ambient Light는 IBL을 사용하여 처리되는 Ambient Diffuse와 Ring Specular로 세분화됩니다.

최신 엔진에서 PBR 재질은 기본 제공 재질이 되었기 때문에 최신 엔진의 GBuffer에는 최소한 다음 정보가 포함됩니다.

1. 주변 폐색(AO)

조명 계산 단계에서 모델의 난반사에 참여하기 위해 사용됩니다.

2, 거칠기/금속

PBR에는 하나의 모델만 있는 것이 아니라 간단히 하기 위해 이 기사에서는 Cocos Creator에서 사용되는 러프니스/메탈릭 모델을 예로 들어 설명합니다.

3、발광

개체의 자체 발광 매개변수는 조명 계산에 간단히 추가됩니다. 더 큰 역할은 네온 불빛과 같은 개체 글로우 효과를 형성하는 데 사용할 수 있다는 것입니다.

다중 렌더 타겟(MRT)

위에서 언급했듯이 GBuffer는 위치, 법선, 색상, 재료 매개변수 등과 같은 조명 계산을 위한 정보를 저장하는 RenderTexture 묶음으로 구성됩니다.

어떻게 그렇게 많은 RenderTexture를 얻을 수 있습니까?

가장 쉬운 방법 중 하나는 장면을 여러 번 렌더링하고 렌더링할 때마다 해당하는 RenderTexture에 다른 콘텐츠를 출력하는 것입니다.

하지만 이 방법은 신뢰할 수 없는 것 같습니다. 장면은 여러 번 렌더링되며 이는 DrawCall의 여러 번에 해당하며 CPU와 GPU 모두에 대한 부담이 두 배가 됩니다.

그런 다음 매우 중요한 그래픽 카드 기능인 다중 렌더링 대상을 언급해야 합니다.

다중 렌더링 대상의 영어 이름은 다중 렌더링 대상 또는 줄여서 MRT입니다. 이것은 지연 파이프라인 기술의 적용을 위한 기초입니다.

그래픽 파이프라인에서는 화면 프레임 버퍼와 렌더링 텍스처를 렌더링 대상 으로 참조합니다 .

일반 렌더링 프로세스에서는 장면 콘텐츠를 화면에 렌더링하든 텍스처에 렌더링하든 하나의 렌더링 대상에만 렌더링하면 됩니다.

그러나 다양한 렌더링 요구 사항이 등장함에 따라 그래픽 카드는 콘텐츠를 렌더링할 때 동시에 여러 렌더링 대상에 대한 렌더링을 점차 지원합니다.

여러 렌더링 대상의 지원으로 하나의 도면에서 모든 GBuffer의 RenderTexture를 채울 수 있습니다.

G버퍼 압축

위의 설명에서 알 수 있습니다. PBR 기반 지연 렌더링 파이프라인에서 GBuffer는 최소한 다음 정보를 포함해야 합니다.

AO 외에도 위에서 언급한 러프 니스 , 메탈릭이미시브가 있습니다 .

  • 위치 : vec3, 고정밀, 예측 불가능한 부품 범위
  • 일반 : vec3, 고정밀, 구성요소 범위 0.0 ~ 1.0
  • 색상 : vec3, 낮은 정밀도, 구성 요소 범위 0.0 ~ 1.0
  • AO : float, 값 범위 0.0 ~ 1.0
  • 조도 : float, 값 범위 0.0 ~ 1.0
  • 메탈릭 : float, 값 범위 0.0 ~ 1.0
  • Emissive : vec3, 구성 요소 범위를 예측할 수 없습니다.
  • 깊이 : d24s8, 구성 요소 범위 0.0 ~ 1.0

그래픽 API 및 그래픽 카드 기능에 따라 수동 처리 없이 직접 깊이 맵을 얻을 수 있습니다.

3개의 PBR 매개변수 AO|roughness|metallic을 RenderTexture에 넣더라도 수요를 충족하려면 여전히 5개의 RenderTexture(위치, 일반, 색상, PBR, Emissive)가 필요합니다.

그러나 현재 그래픽 API 표준에서 OpenGL ES 3.0은 GL_MAX_COLOR_ATTACHMENTS가 4 이상이라고만 규정하고 있습니다.

즉, 모바일 기기에서 다중 렌더링 대상(MRT)의 수가 4보다 크면 호환성이 매우 떨어집니다.

4개의 RenderTexture만 사용하도록 데이터를 압축하는 방법을 찾아야 합니다.

법선은 정규화될 수 있으므로 정규화된 법선의 두 구성 요소를 알고 있는 한 세 번째 구성 요소를 계산할 수 있습니다. 이렇게 하면 법선에 두 개의 패스만 필요합니다. 각 데이터의 값 범위와 결합하여 완료 후 다음과 같은 GBuffer를 얻을 수 있습니다.

  • GBuffer_slot0 : RGBA8
    • xyz -> albedo.rgb
    • 승 -> 무료
  • GBuffer_slot1:RGBA16F
    • xy -> 정상.xy
    • z -> 거칠기
    • w -> 메탈릭
  • GBuffer_slot2:RGBA16F
    • xyz -> 이미시브
    • 승 -> 아오
  • GBuffer_slot3:RGBA16F
    • xyz -> 위치.xyz
    • 승 -> 무료

물론 깊이 맵을 위한 숨겨진 GBuffer_slot4: D24S8도 있습니다. 그러나 깊이 버퍼의 기능이며 MRT의 수를 차지하지 않습니다.

코코스 사이버펑크

Cocos Creator v3.1 버전 부터 지연 렌더링 파이프라인 ( 지연 렌더링 파이프라인 )을 선택할 수 있습니다.

Cocos Cyberpunk 프로젝트 에서 Cocos Creator 3.7 의 새로운 사용자 지정 파이프라인 기능 에 의존하여 프로덕션 팀은 프로젝트 요구 사항에 따라 지연된 렌더링 파이프라인의 사용자 지정 버전도 구현했습니다.

다음으로 Qilinzi는 Cocos Cyberpunk 소스 코드, 파이프라인 흐름, GBuffer 구성 및 채우기, 조명 계산을 결합하여 실제 지연 렌더링 파이프라인의 구현 세부 정보를 보여줍니다.

Cocos Cyberpunk 전체 프로젝트 소스 코드는 https://store.cocos.com/app/detail/4543 에서 무료로 얻을 수 있습니다 .

이전 기사에서 언급한 방법에 따라 Custom Render Pipeline Graph 창을 열면 메인 파이프라인에서 DeferredBufferPassDeferredLightingPass를 찾을 수 있습니다 .

GBuffer 구축

deferred-gbuffer-pass.ts 파일을 열고 DeferredGBufferPass 클래스를 찾습니다.

const colFormat = Format.RGBA16F;
let posFormat = colFormat;
if (!sys.isMobile) {
    
    
    posFormat = Format.RGBA32F
}
passUtils.addRasterPass(width, height, 'default', `${
      
      slot0}_Pass`)
    .setViewport(area.x, area.y, width, height)
    .addRasterView(slot0, colFormat, true)
    .addRasterView(slot1, colFormat, true)
    .addRasterView(slot2, colFormat, true)
    .addRasterView(slot3, posFormat, true)
    .addRasterView(slot4, Format.DEPTH_STENCIL, true)

addRasterPass 메소드의 기능은 드로잉 프로세스를 추가하는 것입니다.

addRasterView 메서드의 기능은 렌더링 대상을 추가하는 것입니다.

여기에는 총 5개의 렌더 타겟이 생성되며 슬롯 3은 위치를 저장하는 데 사용되고 슬롯 4는 깊이 맵에 사용됩니다. slot0, slot1, slot2는 여기서 효과를 볼 수 없습니다.

그들의 형식을 다시 살펴보자.

slot4는 깊이 맵이기 때문에 전용 형식인 Format.DEPTH_STENCIL을 사용하는 것을 볼 수 있습니다.

slot3은 위치를 저장하는 데 사용되며, 모바일이 아닌 쪽에서는 정확도를 높이기 위해 Format.RGBA32F 고정밀 형식도 사용합니다.

나머지 렌더링 대상은 Format.RGBA16F를 사용합니다.

GBuffer 패딩

GBuffer 채우기 단계의 주요 작업은 모델 도면을 호출하고
파이프라인/리소스/표면/맞춤 표면 효과를 여는 것 입니다.

다음 코드를 찾을 수 있습니다.

  #elif CC_PIPELINE_TYPE == CC_PIPELINE_TYPE_DEFERRED   
    layout(location = 0) out vec4 fragColor0; 
    layout(location = 1) out vec4 fragColor1;           
    layout(location = 2) out vec4 fragColor2;
    layout(location = 3) out vec4 fragColor3;
  ...
  #endif

이 코드는 4개의 렌더링 대상 fragColor0~3을 선언하고 레이아웃(위치 = 숫자)을 사용하여 렌더링 대상 인덱스를 지정합니다.

아래로 스크롤하면 이 코드를 찾을 수 있습니다. 이것이 Cocos Creator PBR Shader의 주요 기능으로 약간의 변화가 있긴 하지만 전체적인 개념은 동일합니다.

void main () {
    
    
  StandardSurface s; surf(s);

  #if CC_FORCE_FORWARD_SHADING
    fragColor0 = CCStandardShadingBase(s, CC_SHADOW_POSITION);
    return;
  #endif

  if (cc_fogBase.x == 0.) {
    
           // forward
    fragColor0 = CCStandardShadingBase(s, CC_SHADOW_POSITION);
  }
  else if (cc_fogBase.x == 1.) {
    
      // deferred
    vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);
    vec3 lightmapColor = diffuse * s.lightmap.rgb;
    float occlusion = s.occlusion * s.lightmap_test;

    fragColor0 = s.albedo;
    fragColor1 = vec4(float32x3_to_oct(s.normal), s.roughness, s.metallic);
    fragColor2 = vec4(s.emissive + lightmapColor, occlusion);
    fragColor3 = vec4(s.position, 1.);
  }

}     

Cocos Creator의 PBR 렌더링 프로세스는 재료 매개변수 획득조명 계산의 두 가지 주요 단계로 나뉩니다 .

이 구분의 장점은 셰이더의 작성을 잘 통합할 수 있어 개발자가 순방향 렌더링과 지연 렌더링의 차이를 처리할 필요가 없다는 것입니다.

메인 함수의 첫 번째 문장은 surf 함수를 호출하며, 그 함수는 albedo, roughnes, metallic, emissive 등과 같은 객체의 PBR 재질을 얻는 것입니다.

StandardSurface s; surf(s);

조명 계산 단계에서 포워드 렌더링과 디퍼드 렌더링에는 약간의 차이가 있습니다.

포워드 렌더링은 셰이딩 관련 함수를 직접 호출하여 계산을 완료합니다.

지연 렌더링은 먼저 오브젝트 재질 매개변수를 GBuffer로 렌더링한 다음 나중에 균일하게 계산합니다.

다음 코드는 콘텐츠를 GBuffer에 채우는 데 사용됩니다.

fragColor0 = s.albedo;
fragColor1 = vec4(float32x3_to_oct(s.normal), s.roughness, s.metallic);
fragColor2 = vec4(s.emissive + lightmapColor, occlusion);
fragColor3 = vec4(s.position, 1.);

여기서 우리는 한 눈에 볼 수 있습니다.

  • fragColor0 : RGBA16F
    • xyzw -> albedo.rgba
  • fragColor1 : RGBA16F
    • xy -> 정상.xy
    • z -> 거칠기
    • w -> 메탈릭
  • fragColor2 : RGBA16F
    • xyz -> 이미시브
    • 승 -> 아오
  • fragColor3 : RGBA16F
    • xyz -> 위치.xyz
    • w -> 1.0

조명 계산

다음으로 조명 계산과 관련된 코드를 살펴보자.
deferred-lighting-pass.ts 파일을 열고 DeferredLightingPass 클래스를 찾습니다.

다음 코드를 찾을 수 있습니다.

passUtils.addRasterPass(width, height, 'deferred-lighting', `LightingShader${
      
      cameraID}`)
    .setViewport(area.x, area.y, width, height)
    .setPassInput(this.lastPass.slotName(camera, 0), 'gbuffer_albedoMap')
    .setPassInput(this.lastPass.slotName(camera, 1), 'gbuffer_normalMap')
    .setPassInput(this.lastPass.slotName(camera, 2), 'gbuffer_emissiveMap')
    .setPassInput(this.lastPass.slotName(camera, 3), 'gbuffer_posMap');

setPassInput은 해당 렌더링 대상을 gbuffer_****Map에 바인딩합니다.

지연된 렌더링 조명을 계산하는 데 사용된 deferred-lighting.effect를 열면 다음 코드를 볼 수 있습니다.

void main(){
    
    
    StandardSurface s;
    vec4 albedoMap = texture(gbuffer_albedoMap,v_uv);
    vec4 normalMap = texture(gbuffer_normalMap,v_uv);
    vec4 emissiveMap = texture(gbuffer_emissiveMap,v_uv);
    vec3 position = texture(gbuffer_posMap, v_uv).xyz;
    s.albedo = albedoMap;
    s.position = position;
    s.roughness = normalMap.z;
    s.normal = oct_to_float32x3(normalMap.xy);
    s.specularIntensity = 0.5;
    s.metallic = normalMap.w;
    s.emissive = emissiveMap.xyz;
    ...
}

이 코드의 역할은 명백합니다. GBuffer에서 재질 매개변수를 가져오고 후속 조명 계산을 위해 StandardSurface 정보를 재구성합니다.

이후 조명 계산 과정은 포워드 렌더링과 동일하므로 여기서는 반복하지 않겠습니다.

반투명 렌더링

deferred-lighting-pass.ts로 돌아가서 파일 끝에서 다음 코드를 찾을 수 있습니다.

// render transparent
if (HrefSetting.transparent) {
    
    
  ...
}

이는 래스터화 기반 그래픽 파이프라인에서 올바른 블렌딩 결과를 보장하기 위해 반투명 객체를 원거리에서 근거리 순으로 그려야 하기 때문입니다.

디퍼드 렌더링 파이프라인에서는 기하도형 드로잉 단계에서 조명 계산을 하지 않고 컬러 버퍼에 그린 효과가 최종 효과가 아니기 때문에 이 단계에서 투명 렌더링을 하면 부정확한 결과를 얻게 된다. 또한 후속 조명 계산을 방해합니다.

따라서 장면에서 반투명 개체를 그리려면 순방향 렌더링을 사용해야 합니다.

위의 코드는 작업을 수행합니다.

메모리, 호환성, GPU 매개변수

3D 렌더링을 처음 접하는 많은 친구들은 렌더링 기술의 장점과 단점을 판단할 방법이 없습니다.

일반적으로 메모리 오버헤드 , 성능 오버헤드호환성 의 세 가지 측면에서 렌더링 기술의 장단점을 판단할 수 있습니다 .

메모리 오버헤드는 상대적으로 간단합니다. 할당해야 하는 리소스를 나열하고 점유된 메모리를 계산하기만 하면 됩니다.

호환성도 비교적 쉬운데, 지원해야 할 기능을 나열하고 해당 플랫폼의 지원률을 세어 평가하면 된다.

성능 오버 헤드는 더 번거롭고 기본 지식과 프로젝트 경험의 조합이 필요합니다.

CPU에서 실행되는 프로그램의 경우 운영 체제 원칙, 컴파일 원칙, 메모리 및 CPU 아키텍처 및 작업 원칙을 숙달하면 가능한 성능 병목 현상을 신속하게 평가할 수 있습니다.

마찬가지로 3D프로그래밍도 마찬가지입니다.컴퓨팅 그래픽스의 원리, 그래픽 파이프라인의 작동 원리, GPU 아키텍처 및 작동 원리를 숙지한다면 비교적 정확한 판단을 내릴 수 있습니다.

다음으로 메모리 소비, 호환성 및 GPU 하드웨어 매개변수 요구 사항 측면에서 지연 렌더링 기술의 장단점에 대해 이야기하겠습니다.

단일 객체에는 장단점이 없습니다!

따라서 장단점에 대한 다음 논의에서 기본값은 참조 표준으로 포워드 렌더링입니다.

메모리 소비

텍스처 메모리 계산 방법

텍스처의 메모리 계산 방법은 메모리 = 너비 x 높이 x 단일 픽셀 메모리 크기로 매우 간단합니다.

1바이트 = 8비트

RGBA8:4 * 8btis = 4바이트

RGBA16F:4 * 16비트 = 8바이트

RGBA32F:4 * 32비트 = 16바이트

D24S8:24비트 + 8비트 = 4바이트

GBuffer 전체 오버헤드

Cocos Cyberpunk는 4개의 RGBA16F와 1개의 D24S8을 사용합니다.

해상도가 1280 x 720일 때 전체 GBuffer가 차지하는 총 메모리는 다음과 같이 계산됩니다.

1280 x 720 x ( 4 * 8 + 4 ) 바이트는 약 31.64MB입니다.

다른 16개에서 9개 해상도에서 GBuffer의 메모리 오버헤드를 비교해 봅시다:

  • (720p)1280 x 720 -> 31.64MB
  • (960p)1706 x 960 -> 56.23MB
  • (1k)1920 x 1080 -> 71.19MB
  • (2k)2560 x 1440 -> 126.56MB
  • (4k)3840 x 2160 -> 284.76MB

해상도가 1k 이상이 되면 메모리 사용량을 과소평가할 수 없음을 알 수 있습니다.

특히 모바일 쪽에서는 렌더링 해상도를 최대한 제어해야 합니다.

메모리보다 GPU에 부담을 주는 GBuffer에 대해 더 걱정해야 합니다.

오늘 이 기회에 Qilinzi는 GPU의 성능과 관련된 몇 가지 중요한 매개변수에 대해 간략하게 설명합니다.

GPU 매개변수 및 성능 병목 현상

GPU 하드웨어 매개변수

  • 코어 주파수(GPU 클록) : CPU와 마찬가지로 GPU의 컴퓨팅 성능을 결정합니다.
  • 논리 연산 단위(ALU) : VS 및 FS에서 벡터 행렬 연산과 같은 일반적인 계산을 처리하는 데 사용됩니다.
  • 광학 삭제 처리 장치(ROPs - Raster Operations Units) : 이 하드웨어 장치는 렌더링 대상에 픽셀 값을 쓰는 일을 주로 담당합니다(심도 테스트, 스텐실 테스트, 투명 혼합).
  • Texture Mapping Units (TMUs - Texture Mapping Units) : 이 하드웨어 장치는 주로 텍스처 명령을 실행합니다.
  • Memory Clock : 수도관의 유속과 같이 비디오 메모리가 전송하는 데이터의 응답속도를 결정
  • 비디오 메모리 버스 폭(Bus Width) : 두께와 상관없이 비디오 메모리의 단일 전송 데이터의 크기 결정

GPU 평가 매개변수

GPU 하드웨어 매개변수를 직접 보고 그래픽 카드의 기능을 이해하는 것은 그리 쉽지 않습니다. 따라서 하드웨어 매개변수를 계산한 후 GPU 품질을 평가하기 위한 다음과 같은 주요 매개변수를 얻을 수 있습니다.

1. 픽셀 필레이트

픽셀 채우기 속도는 GPU가 GPixel/s(기가픽셀/초) 단위로 초당 렌더링할 수 있는 픽셀 수를 나타냅니다.

계산 공식: 픽셀 채우기 속도 = 코어 주파수(GPU 클록) x 래스터 처리 장치(ROP) 수

2. 텍스처 필레이트

텍스처 채우기 속도는 그래픽 카드가 초당 텍스처 맵을 샘플링할 수 있는 횟수를 말하며 단위는 GTexel/s(십억 텍셀/초)입니다.

계산 공식: 텍스처 채우기 속도 = 코어 주파수(GPU 클록) × 텍스처 단위 수(TMU)

3. 메모리 폭

비디오 메모리 대역폭은 비디오 메모리가 초당 전송할 수 있는 데이터의 바이트 수를 GB/s(기가바이트/초) 단위로 나타냅니다.

대역폭 = 메모리 클록 x 버스 폭 / 8

4. 부동 소수점 연산(FLOPS/TFLOPS)

GPU의 컴퓨팅 성능을 측정하는 핵심 지표는 FLOPS, 즉 초당 부동 소수점 연산 수인 Floating-point Operations Per Second입니다.

최신 GPU의 강력한 부동 소수점 컴퓨팅 성능으로 인해 일반적으로 TFLOPS(초당 1조 개의 부동 소수점 연산)로 표현됩니다.

이 값은 ALU와 코어 주파수에 의해 결정되며 제조사의 측정 데이터에 따릅니다.

위의 매개변수를 이해하면 GPU 매개변수를 비교할 때 GPU가 강한 곳과 약한 곳을 빠르게 확인할 수 있습니다.

성능 문제가 발생하면 모델의 병목 현상을 신속하게 찾아 적절한 솔루션을 공식화할 수 있습니다.

지연 파이프라인이 GPU에 미치는 영향

이제 디퍼드 렌더링 파이프라인이 포워드 렌더링과 비교하여 GPU에 어떤 부담을 주는지 살펴보겠습니다.

1. 픽셀 필레이트

포워드 렌더링에서는 하나의 렌더 타겟 + 하나의 깊이 스텐실 버퍼만 필요합니다. 지연 렌더링에서 4개의 렌더링 대상 + 깊이 스텐실 버퍼를 포함하는 GBuffer를 예로 들면 총 5개가 필요합니다.

픽셀 채우기 속도 오버헤드 측면에서 디퍼드 렌더링의 오버헤드는 포워드 렌더링의 2.5배입니다.

2. 텍스처 채우기 비율

모델이 PBR 재질을 사용하는 경우 IBL이 켜져 있을 때 각 픽셀에 대해 IBL 계산이 수행되고 환경 매핑과 관련된 텍스처 작업이 수행됩니다. 그러나 지연 렌더링 프로세스에서는 이러한 계산이 차단된 픽셀에서 수행되지 않습니다.
전반적으로 텍스처 채우기 속도 오버헤드에서 약간의 절감이 있지만 많이는 아닙니다.

3. 메모리 대역폭

포워드 렌더링에서는 RGBA8 x1 + D24S8 x1만 필요합니다.

하지만 디퍼드 렌더링에서는 RGBAF16 x 4 + D24S8 x1이 필요합니다.

비디오 메모리 대역폭에 대한 요구 사항이 4.5배로 증가했습니다 -> (4x8+4)/(4+4)

4. 부동 소수점 연산

PBR의 주요 비용은 조명 단계에 있기 때문에 특히 BRDF와 IBL은 많은 수학 공식 연산을 수행합니다.

그러나 지연 렌더링 프로세스에서는 차단된 픽셀이 이러한 계산을 수행하지 않으며 여기에서 오버헤드를 많이 절약할 수 있습니다.

요약
지연 렌더링은 픽셀 채우기의 양을 2.5배, 비디오 메모리 데이터 액세스의 양을 4.5배 증가시켜 텍스처 채우기 작업의 일부와 많은 수의 논리 연산을 절약할 수 있음을 알 수 있습니다.

그러므로:

  1. 래스터 기능이 부족하고 메모리 대역폭이 부족한 GPU는 성능 문제가 발생합니다.
  2. 전력 소비의 증가는 전력 소비와 발열을 유발할 것이며 모바일 단말기 프로젝트는 특별한 주의가 필요합니다.

일반적인 최적화 방법

지연 렌더링의 최적화 방법은 주로 두 가지 측면에서 시작됩니다.

1. GBuffer에서 렌더링 대상 해상도 제한

이것은 조작이 가장 쉬운 방법으로 그림을 확보하는 경우 렌더링 대상 해상도를 최대한 낮추십시오.

2. GBuffer의 렌더 타겟 수 줄이기

렌더링 대상 수를 줄이려면 압축 알고리즘을 사용하여 데이터가 차지하는 바이트 수를 줄이고 채널에 저장할 수 있습니다.

이것은 정밀도의 손실을 가져오지만 이점은 효과가 보존된다는 것입니다.

다른 하나는 일부 불필요한 매개변수를 제거하는 것으로 일부 효과를 얻을 수 없다는 부작용이 있습니다.

3. RGBA8의 사용 우선 순위
RGBA16F와 비교할 때 RGBA8의 메모리 사용량은 RGBA16F보다 1배 적기 때문에 그래픽 카드 대역폭의 최적화가 크게 향상됩니다. 그러나 부작용은 정밀도의 손실이 있고 일부 효과는 좋지 않다는 것입니다.

Cocos Cyberpunk 프로젝트에서 알베도의 원래 값이 RGBA8이고 정밀도 손실이 없기 때문에 fragColor0이 RGBA8을 사용할 수 있다는 점은 주목할 가치가 있습니다.

호환성

개발자가 특정 플랫폼용으로만 제품을 출시한다면 호환성을 다룰 때 고려해야 할 사항이 거의 없습니다. 예를 들어 Cocos Creator를
사용하여 제품을 개발하고 Nintendo .

해당 스위치를 구입 하고 테스트를 통과하기 만 하면 됩니다 . 다른 문제에 대해 걱정하지 마십시오.

그러나 Cocos Creator는 크로스 플랫폼 엔진이므로 사용자는 IOS, Android, Hongmeng, PC 및 기타 시스템을 고려할 수 있습니다.

또한 같은 시스템에서 네이티브 게임과 미니 게임, 웹의 차이도 고려해야 한다.

다행스럽게도 Nintendo Switch와 같은 독점 플랫폼을 제외 Metal, OpenGL ES, WebGL, Vulkan, WebGPU와 같은 다른 플랫폼용 그래픽 드라이버가 알려져 있습니다.

따라서 기술의 호환성과 친화성을 평가하기 전에 주요 그래픽 기능을 나열하고 이러한 기능을 지원하는 각 그래픽 API의 출시 시간을 찾아야 합니다.

위에서 언급했듯이 잘 작동하는 지연 렌더링을 지원하려면 세 가지 기능이 필요합니다.

  1. 깊이 텍스처 가져오기
  2. 다중 렌더 타겟(MRT)
  3. 부동 소수점 텍스처로 렌더링

위의 세 가지 기능이 공식적으로 지원되며 해당 API는 다음과 같습니다.

데스크탑

  • Direct3D 9.0c,2004-07-26, 100%
  • OpenGL 2.0,2004-09-07, 100%

모바일 네이티브

  • OpenGL ES 3.0, 2012-08-05, 99.5%
  • 금속 1.0, 2014-06-03, 99.5% (iPhone 6/6 Plus)
  • 모바일용 Vulkan, 2016-08-22, Android 7.0

편물

  • WebGL 2.0, 2017-04-11, OpenGL ES 3.0 기반
  • WebGPU 1.0, 2023년 공식 출시 예정

PC 데스크탑과 네이티브엔드에서 지연 렌더링으로 인한 호환성 문제를 걱정할 필요가 없다는 것을 알 수 있습니다.

웹 측면에서 이를 지원하려면 WebGL 2.0 브라우저가 필요합니다.

2022년 2월 14일, Khronos Group은 이제 모든 주요 브라우저가 WebGL 2.0에 대한 지원을 구현했다고 발표했습니다. 두 개의 네일 계정 포함: Safari 및 Edge.

WebGPU가 공식적으로 출시되지는 않았지만 많은 브라우저에서 이에 대한 실험적 지원을 추가했습니다.

그리고 Cocos Creator에서는 상황에 따라 OpenGL ES/Metal/Vulkan/WebGL/WebGPU 중 하나를 선택하여 대상 플랫폼에 게시할 수 있습니다.

Android 및 Windows를 출시할 때 Vulkan/OpenGL ES 3.0/OpenGL ES 2.0을 사용하도록 선택할 수 있습니다.

Web Desktop을 게시할 때 WebGPU를 활성화할지 여부를 선택할 수 있습니다.

iOS/Mac을 출시하면 Apple 제한으로 인해 Metal을 그래픽 렌더링 백엔드로만 사용할 수 있습니다.

일반적으로 현재 데이터로 판단하면 지연 렌더링을 지원하는 플랫폼이 많이 있습니다.

또한 Cocos Creator의 재료 시스템은 상위 계층에 격리되어 있으며 포워드 렌더링 및 디퍼드 렌더링 파이프라인에서 동일한 재료 세트를 정상적으로 렌더링할 수 있습니다.

따라서 호환성 문제는 그리 크지 않으나, 실행이 안되는 환경이 발생하면 포워드 렌더링으로 폴백하여 원활한 게임 진입이 가능하도록 할 수 있습니다.

지연 렌더링 요약

지연 렌더링 기술에는 다음과 같은 많은 이점이 있습니다.

  1. 조명 계산 복잡도를 M*N 에서 M+N 으로 변경하여 조명 계산 오버헤드를 줄일 수 있습니다.
  2. 조명 계산 단계에서는 보이는 픽셀만 계산하여 Overdraw 의 소모를 크게 줄입니다 .
  3. 깊이, 위치, 법선 및 자체 조명 강도와 같은 정보는 GBuffer 에서 직접 얻을 수 있습니다 . Bloom , SSR , SSAO 등과 같은 화면 공간 기반 고급 렌더링 효과를 구현하는 것이 매우 편리합니다 .

동시에 몇 가지 단점도 있습니다.

  1. 추가 메모리 오버헤드
  2. GPU 픽셀 채우기 속도 및 메모리 대역폭에 대한 몇 배 더 높은 요구 사항
  3. 소비전력 증가로 인한 발열과 소비전력이 포워드렌더링보다 높음
  4. 투명 렌더링은 지원되지 않으며 투명 렌더링은 여전히 ​​처리를 위해 포워드 렌더링 파이프라인으로 폴백해야 합니다.
  5. MRT의 특성상 그래픽 카드에 기본 제공되는 MSAA 안티앨리어싱 방식을 사용할 수 없으며 FXAA와 TAA로 처리해야 한다.

모든 상황을 만족시킬 수 있는 단일 기술은 없다는 것을 알 수 있습니다. 이전에 Qilinzi가 언급한 고급, 고급 및 저급 기계의 성능 적응 전략과 결합하여 사용할 수 있는 두 가지 솔루션이 있습니다.

  1. 고급 컴퓨터에서는 지연 렌더링을 사용하고 저사양 컴퓨터에서는 고급 효과를 끄고 포워드 렌더링으로 대체합니다.
  2. 다른 이미지 품질 및 성능 요구 사항에 따라 다른 정밀도로 GBuffer를 공식화하십시오. 예를 들어 압축된 저장 메커니즘을 사용하고 일반, 색상 및 위치를 단일 RGBA16F 렌더링 텍스처에 넣은 다음 RGBA8 또는 RGBA16F를 사용하여 조명 매개변수를 전송합니다.

마지막에 쓰기

모든 프로젝트 기술의 상륙 및 대중화에는 시간이 걸립니다.

지연 렌더링이 출시되기 전에는 고급 컴퓨터에서만 실행할 수 있었지만 이제는 모든 컴퓨터에서 실행할 수 있습니다. 일부 중급에서 고급형 휴대폰도 원활하게 실행될 수 있습니다.

하드웨어의 지속적인 발전으로 디퍼드 렌더링 기술은 모바일에서도 빛을 발할 수 있다고 생각합니다.

인생은 항상 놀라움으로 가득 차 있습니다. 이 기사는 원래 그렇게 많이 쓸 의도가 없었습니다. 하지만 글을 쓰면서 모두가 더 탄탄하게 배울 수 있도록 배경지식을 더할 필요가 있다고 생각합니다.

GPU 매개변수, 그래픽 API 침투, 호환성 결정 및 메모리 예측은 모두 예상치 못한 것입니다.

하지만 글을 쓰고 나면 모든 것이 풀리고, 그렇지 않으면 항상 남에게 빚진 게 있다는 생각이 듭니다.

마지막으로 격려의 말씀을 전하고 싶습니다.

기본 지식과 기본 논리를 통합하는 데 더 많은 시간을 할애해야만 변화하는 동안 안정과 발전을 추구할 수 있습니다.

추천

출처blog.csdn.net/qq_36720848/article/details/129869399