WebGL Varing 변수의 역할과 보간 과정, 그리고 Varing 실행에 관련된 그래픽 어셈블리, 래스터화, 색상 보간, 프래그먼트 셰이더 실행 메커니즘 등에 대한 자세한 설명을 제공합니다.

목차

머리말

WebGL 또는 OpenGL에서 "가변"은 정점 셰이더와 조각 셰이더 간에 데이터를 전달하는 데 사용되는 특수한 유형의 변수입니다. 이를 통해 정점 셰이더에서 데이터를 처리한 다음 추가 계산을 위해 조각 셰이더에서 사용할 수 있습니다. 

점 3개 색상 

편집하다

다채로운 점 3개 샘플 코드

다양한 변수 사용 사양 

채색 삼각형

기하학의 조립 및 래스터화

빨간색 삼각형 샘플 코드

정점 좌표 --> 그래픽 어셈블리 --> 래스터화 --> 조각 셰이더 실행

요소 조립 공정

래스터화 프로세스

버텍스 쉐이더와 프래그먼트 쉐이더 간의 그래픽 조립 및 래스터화 과정에 대한 자세한 설명

1단계: 정점 셰이더를 실행하면 버퍼 개체의 첫 번째 좌표(0.0, 0.5)가 속성 변수 a_Position에 전달됩니다. 정점의 좌표가 gl_Position에 할당되면 그래픽 어셈블리 영역으로 들어가 임시로 저장됩니다. a_Position에는 x 구성 요소와 y 구성 요소만 명시적으로 할당했기 때문에 z 구성 요소와 w 구성 요소에는 기본값이 할당되었다는 점을 기억해야 합니다. 그래픽 어셈블리 영역에 들어가는 좌표는 실제로 (0.0, 0.5, 0.0, 1.0)입니다.

2단계: 정점 셰이더를 다시 실행하고 마찬가지로 두 번째 좌표(-0.5, -0.5, 0.0, 1.0)를 전달하고 어셈블리 영역에 저장합니다.

3단계: 세 번째로 정점 셰이더를 실행하고 세 번째 좌표(0.5, -0.5, 0.0, 1.0)를 전달하여 어셈블리 영역에 저장합니다. 이제 정점 셰이더의 실행이 완료되었으며 세 정점 좌표가 모두 어셈블리 영역에 있습니다.

4단계: 그래픽 조립을 시작합니다. 들어오는 점 좌표를 사용하여 gl.drawArrays()의 첫 번째 매개변수 정보(gl.TRIANGLES)를 기반으로 조립 방법을 결정합니다. 이 예에서는 세 개의 꼭지점을 사용하여 삼각형을 조립합니다.

5단계: 화면에 표시되는 삼각형은 조각(픽셀)으로 구성되어 있으므로 그래픽도 조각으로 변환해야 하는데, 이 과정을 래스터화라고 합니다. 래스터화 후에 우리는 이 삼각형을 구성하는 모든 조각을 얻습니다. 위 이미지의 마지막 단계에서는 래스터화 후 삼각형을 형성하는 조각을 볼 수 있습니다.

프래그먼트 셰이더 호출

실험을 해보세요: 위치에 따라 조각의 색상을 결정하세요

gl.드로잉버퍼Width / gl.드로잉버퍼 높이

디스플레이 효과

다양한 변수의 역할과 보간 과정

다양한 변수의 동작

​다양한 변수의 보간 편집편집

색상 값 보간

요약하다 


머리말

WebGL 또는 OpenGL에서 "가변"은 정점 셰이더와 조각 셰이더 간에 데이터를 전달하는 데 사용되는 특수한 유형의 변수입니다. 이를 통해 정점 셰이더에서 데이터를 처리한 다음 추가 계산을 위해 조각 셰이더에서 사용할 수 있습니다. 

점 3개 색상 

다채로운 점 3개 샘플 코드

// 顶点着色器
var VSHADER_SOURCE =
  'attribute vec4 a_Position;\n' +
  'attribute vec4 a_Color;\n' +
  'varying vec4 v_Color;\n' + // varying 变量
  'void main() {\n' +
  '  gl_Position = a_Position;\n' +
  '  gl_PointSize = 10.0;\n' +
  '  v_Color = a_Color;\n' +  // 将数据传给片元着色器
  '}\n';

// 片元着色器
var FSHADER_SOURCE =
  'precision mediump float;\n' + // 设置varing精度
  'varying vec4 v_Color;\n' +    // 从顶点着色器接受数据
  'void main() {\n' +
  '  gl_FragColor = v_Color;\n' +
  '}\n';

function main() {
  var canvas = document.getElementById('webgl');
  var gl = getWebGLContext(canvas);
  // 设置顶点的坐标和颜色
  var n = initVertexBuffers(gl);
  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  gl.clear(gl.COLOR_BUFFER_BIT);
  gl.drawArrays(gl.POINTS, 0, n);
}

function initVertexBuffers(gl) {
  var verticesColors = new Float32Array([
    // 顶点坐标和颜色
     0.0,  0.5,  1.0,  0.0,  0.0, 
    -0.5, -0.5,  0.0,  1.0,  0.0, 
     0.5, -0.5,  0.0,  0.0,  1.0, 
  ]);
  var n = 3; // 顶点数量

  // 创建缓冲区对象
  var vertexColorBuffer = gl.createBuffer();  
  if (!vertexColorBuffer) {
    console.log('Failed to create the buffer object');
    return false;
  }

  // 将顶点坐标和颜色写入缓冲区对象
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);

  var FSIZE = verticesColors.BYTES_PER_ELEMENT;
  // 获取a_Position的存储位置,分配缓冲区并开启
  var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
  gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 5, 0);
  gl.enableVertexAttribArray(a_Position);  // 开启变量

  // 获取a_Color的存储位置,分配缓冲区并开启
  var a_Color = gl.getAttribLocation(gl.program, 'a_Color');
  gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 5, FSIZE * 2);
  gl.enableVertexAttribArray(a_Color);  // 开启缓冲区分配

  return n;
}

다양한 변수 사용 사양 

 정점 셰이더에서는 색상 데이터를 수신하기 위해 속성 변수 a_Color를 선언하고(라인 4), 색상 값을 프래그먼트 셰이더에 전달하는 역할을 담당하는 새로운 가변 변수 v_Color를 선언합니다(라인 5). 가변 변수는 float 유형(및 관련 vec2, vec3, vec4, mat2, mat3 및 mat4)만 될 수 있습니다.

a_Color 변수의 값을 이전에 선언된 v_Color 변수(9행)에 직접 할당합니다. 

그렇다면 프래그먼트 셰이더는 이 변수를 어떻게 수신합니까? 대답은 간단합니다. 프래그먼트 셰이더에서 가변 변수(정점 셰이더의 가변 변수와 동일한 이름)를 선언하기만 하면 됩니다.

WebGL에서 정점 셰이더와 조각 셰이더에 동일한 유형과 이름의 가변 변수가 있는 경우 정점 셰이더에서 변수에 할당한 값은 다음 그림과 같이 자동으로 조각 셰이더에 전달됩니다. 

그래서 Vertex Shader에서 v_Color 변수에 할당한 값(9행)이 Fragment Shader의 v_Color 변수에 전달되고, 이후 Fragment Shader는 v_Color를 gl_FragColor에 할당하여 각 정점의 색상이 수정됩니다( line 17). 

verticesColor 배열에는 두 가지 유형의 데이터(좌표 및 색상)가 있습니다. 현재 색상에는 3개의 구성요소 값이 있으므로 각 정점이 차지하는 바이트 수는 FSIZE*5입니다. 해당 gl.vertexAttribPointer() 함수의 stride 매개변수와 offset 매개변수를 수정해야 합니다(53행 및 58행).

마지막으로 그리기 명령(27행)이 실행되고 빨간색, 파란색, 녹색 세 점이 브라우저에 그려집니다.

채색 삼각형

gl.drawArrays() 함수의 첫 번째 매개변수를 gl.TRIANGLES로 변경하면 어떤 일이 발생하는지 살펴보겠습니다 (27행).

프로그램의 결과는 아래 그림과 같으며, 색상의 부드러운 전환과 빨강, 녹색, 파랑의 세 모서리가 있는 삼각형을 그립니다.

우리는 하나의 매개변수만 변경했고, 프로그램 결과는 서로 다른 색상의 세 개의 분리된 점에서 색상이 부드럽게 전환되는 삼각형으로 변경되었습니다. 결국 무슨 일이 일어났나요?

기하학의 조립 및 래스터화

단순화를 위해 빨간색 삼각형으로 설명하는 코드는 다음과 같습니다.

빨간색 삼각형 샘플 코드

 initVertexBuffers() 함수(라인 50 및 52)에서 버퍼 객체에 정점 좌표를 쓴 다음 버퍼 객체를 a_Position 변수(라인 74)에 할당합니다. 마지막으로 gl.drawArrays()가 정점 셰이더를 실행하기 위해 호출됩니다(라인 46). Vertex Shader가 실행되면 버퍼에 있는 3개의 정점 좌표가 a_Position 변수(line 4)에 전달된 후 gl_Position(line 6)에 할당되므로 WebGL 시스템은 정점 좌표에 따라 그릴 수 있습니다. Fragment Shader에서는 빨간색 RGBA 값(1.0, 0.0, 0.0, 1.0)을 gl_FragColor에 할당하여 빨간색 삼각형을 그립니다.

하지만 지금까지 이것이 어떻게 이루어지는지 아직도 이해하지 못하시나요? gl_Position에 삼각형의 세 정점 좌표를 제공할 때 조각 셰이더는 어떻게 소위 조각별 작업을 수행할 수 있습니까?

다음 그림은 문제를 보여줍니다. 프로그램은 gl_Position에 세 정점의 좌표를 제공합니다. 누가 이 세 점이 삼각형의 세 정점인지 결정할 것입니까? 궁극적으로 삼각형의 내부를 채우기 위해 어떤 픽셀을 색칠해야 하는지는 누가 결정합니까? 프래그먼트 셰이더 호출을 담당하는 사람은 누구이며, 프래그먼트 셰이더는 각 프래그먼트를 어떻게 처리합니까?

정점 좌표 --> 그래픽 어셈블리 --> 래스터화 --> 조각 셰이더 실행

 정점 셰이더와 조각 셰이더에는 두 단계가 있습니다.

  • 요소 조립 공정

  이 단계의 작업은 격리된 꼭지점 좌표를 기하학적 모양으로 조립하는 것입니다. 기하학의 범주는 gl.drawArrays() 함수의 첫 번째 매개변수에 의해 결정됩니다.

  • 래스터화 프로세스

  이 단계의 임무는 조립된 형상을 조각으로 변환하는 것입니다.

위 그림과 같이 gl_Position은 실제로 기하학적 형상 조립 단계의 입력 데이터입니다. 조립된 기본 그래픽(점, 선 및 표면)을 기본 요소라고도 부르기 때문에 기하학적 도형 조립 프로세스를 기본 어셈블리 프로세스 라고도 합니다

버텍스 쉐이더와 프래그먼트 쉐이더 간의 그래픽 조립 및 래스터화 과정에 대한 자세한 설명

1단계: 정점 셰이더를 실행하면 버퍼 개체의 첫 번째 좌표(0.0, 0.5)가 속성 변수 a_Position에 전달됩니다. 정점의 좌표가 gl_Position에 할당되면 그래픽 어셈블리 영역으로 들어가 임시로 저장됩니다. a_Position에는 x 구성 요소와 y 구성 요소만 명시적으로 할당했기 때문에 z 구성 요소와 w 구성 요소에는 기본값이 할당되었다는 점을 기억해야 합니다. 그래픽 어셈블리 영역에 들어가는 좌표는 실제로 (0.0, 0.5, 0.0, 1.0)입니다.

2단계: 정점 셰이더를 다시 실행하고 마찬가지로 두 번째 좌표(-0.5, -0.5, 0.0, 1.0)를 전달하고 어셈블리 영역에 저장합니다.

3단계: 세 번째로 정점 셰이더를 실행하고 세 번째 좌표(0.5, -0.5, 0.0, 1.0)를 전달하여 어셈블리 영역에 저장합니다. 이제 정점 셰이더의 실행이 완료되었으며 세 정점 좌표가 모두 어셈블리 영역에 있습니다.

4단계: 그래픽 조립을 시작합니다. 들어오는 점 좌표를 사용하여 gl.drawArrays()의 첫 번째 매개변수 정보(gl.TRIANGLES)를 기반으로 조립 방법을 결정합니다. 이 예에서는 세 개의 꼭지점을 사용하여 삼각형을 조립합니다.

5단계: 화면에 표시되는 삼각형은 조각(픽셀)으로 구성되어 있으므로 그래픽도 조각으로 변환해야 하는데, 이 과정을 래스터화라고 합니다. 래스터화 후에 우리는 이 삼각형을 구성하는 모든 조각을 얻습니다. 위 이미지의 마지막 단계에서는 래스터화 후 삼각형을 형성하는 조각을 볼 수 있습니다.

위의 그림은 설명을 위해 10개의 조각만 보여줍니다. 실제로 조각 수는 화면에서 삼각형이 최종적으로 덮는 픽셀 수입니다. gl.drawArrays()의 첫 번째 매개변수가 수정되면 4단계의 그래픽 어셈블리와 5단계의 조각 수 및 위치가 그에 따라 변경됩니다. 예를 들어, 이 매개변수가 gl.LINE인 경우 프로그램은 처음 두 점을 사용하여 선분을 조립하고 세 번째 점을 삭제합니다. gl.LINE_LOOP인 경우 프로그램은 세 점을 끝 부분에 연결된 접힌 점으로 조립합니다. 끝. 선분을 생성하고 속이 빈 삼각형을 래스터화합니다(중간 픽셀을 생성하지 않음).

프래그먼트 셰이더 호출

래스터화 프로세스가 완료되면 프로그램은 조각별로 조각 셰이더를 호출하기 시작합니다. 아래 그림에서는 프래그먼트 셰이더가 10번 호출되고, 호출될 때마다 하나의 프래그먼트가 처리됩니다(다음 그림에서는 깔끔함을 위해 중간 단계를 생략합니다). 각 조각에 대해 조각 셰이더는 조각의 색상을 계산하여 색상 버퍼에 씁니다. 15단계에서 마지막 조각이 처리될 때까지 브라우저는 최종 결과를 표시합니다.

빨간색 삼각형 코드의 조각 셰이더는 아래와 같이 각 조각의 색상을 빨간색으로 할당합니다. 따라서 브라우저는 빨간색 삼각형을 그립니다.

실험을 해보세요: 위치에 따라 조각의 색상을 결정하세요

이는 조각 셰이더가 각 조각에 대해 한 번 실행된다는 것을 증명합니다. 래스터화 과정을 통해 생성된 프래그먼트는 모두 좌표 정보를 갖고 있으며, 프래그먼트 셰이더가 호출되면 좌표 정보도 프래그먼트와 함께 전달되는데, 프래그먼트 셰이더에 내장된 변수를 통해 프래그먼트의 좌표에 접근할 수 있다. 아래 표와 같습니다). 

 조각 셰이더가 조각별로 실행된다는 것을 증명하기 위해 아래와 같이 원래 빨간색 삼각형 프로그램(gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0))의 라인 12를 수정했습니다.

프래그먼트 셰이더의 프로그램 코드를 보면 삼각형 안의 각 프래그먼트의 색상, 빨간색 구성요소, 파란색 구성요소가 프래그먼트의 위치를 ​​기준으로 계산되는 것을 볼 수 있습니다. 참고로 캔버스의 Y축 방향은 WebGL 시스템의 Y축 방향과 반대이고 WebGL의 색상 구성 요소 값 범위는 0.0~1.0이므로 Y축 좌표를 < 높이로 나누어야 합니다. canvas> 요소(400픽셀)를 사용하여 0.0에서 1.0 사이로 압축합니다. gl.드로잉버퍼Width(컬러 버퍼의 너비)gl.rawlBufferHeight(컬러 버퍼의 높이) 값을 균일 변수 u_Width 및 u_Height에 전달합니다 . 아래의 색상이 지정된 삼각형은 프로그램 결과를 보여줍니다. 삼각형, 픽셀 색상은 픽셀의 위치에 따라 결정되며 왼쪽 위에서 오른쪽 아래로 그라데이션 효과를 보여줍니다. 

gl.드로잉버퍼Width / gl.드로잉버퍼 높이

  gl.uniform1f(u_Width, gl.drawingBufferWidth); // 颜色缓冲区的宽度,下面同理 高度
  gl.uniform1f(u_Height, gl.drawingBufferHeight);

디스플레이 효과

조각의 색상은 좌표 위치에 따라 달라지므로 조각의 위치에 따라 조각의 색상이 점차 변하는 것이 당연하며 삼각형은 부드러운 색상 그라데이션 효과를 나타냅니다.

다양한 변수의 역할과 보간 과정

이제 우리는 버텍스 셰이더와 프래그먼트 셰이더 사이의 지오메트리 어셈블리 및 래스터화 프로세스를 이해했으며 WebGL 시스템이 프래그먼트별로 프래그먼트 셰이더를 실행하는 방법을 이해했습니다.

위의 색칠된 삼각형 프로그램으로 돌아가면, 이 프로그램은 우리가 방금 배운 지식을 사용하여 왜 정점 셰이더에서 각 정점의 색상만 지정하고 마지막으로 그라데이션 색상 효과가 있는 삼각형을 얻을 수 있는지 설명할 수 있습니다. 실제로 정점 셰이더의 가변 변수 v_Color에 정점의 색상을 할당하고 그 값은 프래그먼트 셰이더의 동일한 이름과 유형의 변수(즉, 프래그먼트 셰이더의 가변 변수 v_Color)에 전달됩니다. ).아래 그림과 같습니다. 그러나 더 정확하게 말하면 버텍스 셰이더의 v_Color 변수는 프래그먼트 셰이더에 전달되기 전에 보간됩니다. 따라서 프래그먼트 셰이더의 v_Color 변수와 정점 셰이더의 v_Color 변수는 실제로 동일한 것이 아닙니다. 이것이 바로 이러한 유형의 변수를 "가변" 변수라고 부르는 이유입니다.

다양한 변수의 동작

다양한 변수의 보간

 보다 정확하게는 빨간색 삼각형에서 다양한 변수에 삼각형의 서로 다른 3개의 꼭지점에 대해 3개의 서로 다른 색상을 지정했으며 삼각형 표면에 있는 이러한 조각의 색상 값은 WebGL 시스템에서 사용되는 색상입니다. 이 3개의 정점이 보간됩니다.

예를 들어, 두 끝점이 서로 다른 색상인 선분을 생각해 보세요. 한 끝점은 빨간색(1.0, 0.0, 0.0)으로 표시되고 다른 끝점은 파란색(0.0, 0.0, 1.0)으로 표시됩니다. 이 두 가지 색상(빨간색과 파란색)을 정점 셰이더의 가변 변수 v_Color에 할당하면 WebGL은 선분에 있는 모든 점(조각)의 색상을 자동으로 계산하여 조각 셰이더에 할당합니다 . 아래 그림과 같이).

색상 값 보간

이 예에서 RGBA의 R 값은 1.0에서 0.0으로 감소하고 B 값은 0.0에서 1.0으로 증가합니다. 선분에 있는 모든 조각의 색상 값이 적절하게 계산됩니다. 이 프로세스를 보간 보간 프로세스라고 합니다 . 두 점 사이의 각 조각에 대한 새 색상이 이러한 방식으로 계산되면 조각 셰이더의 v_Color 변수에 전달됩니다. 

빨간색 삼각형 에 대한 프로그램 코드를 살펴보겠습니다 . 정점 셰이더에서 삼각형의 세 정점 색상을 가변 변수 v_Color(라인 9)에 할당한 다음 조각 셰이더의 가변 변수 v_Color가 보간된 조각 색상을 받습니다. Fragment Shader에서는 Fragment의 색상을 gl_FragColor 변수(19행)에 할당하여 색상이 지정된 삼각형을 그립니다. 마찬가지로 각 가변 변수는 이러한 보간 프로세스를칩니다 .

요약하다 

버텍스 셰이더와 프래그먼트 셰이더 사이의 프로세스는 매우 중요합니다. 래스터화 역시 3차원 그래픽의 핵심 기술 중 하나로, 벡터 기하학을 래스터화된 조각(픽셀)으로 변환하는 역할을 합니다. 그래픽이 조각으로 변환된 후에는 각 조각에 서로 다른 색상을 할당하는 등 조각 셰이더 내에서 더 많은 작업을 수행할 수 있습니다. 색상은 프로그래밍 방식으로 보간되거나 지정될 수 있습니다. 

추천

출처blog.csdn.net/dabaooooq/article/details/132611118