λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
😸 OpenGL

[Learn OpenGL] Shaders - 2

by HOENDEV 2023. 11. 18.

Uniforms

μœ λ‹ˆνΌμ€ CPU에 μžˆλŠ” 우리의 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ GPU의 μ‰μ΄λ”λ‘œ 데이터λ₯Ό μ „λ‹¬ν•˜λŠ” 또 λ‹€λ₯Έ λ°©λ²•μž…λ‹ˆλ‹€.

 

ν•˜μ§€λ§Œ μœ λ‹ˆνΌμ€ 정점 μ†μ„±κ³ΌλŠ” μ•½κ°„ λ‹€λ¦…λ‹ˆλ‹€. λ¨Όμ €, μœ λ‹ˆνΌμ€ μ „μ—­μ μž…λ‹ˆλ‹€. μ „μ—­μ μ΄λΌλŠ” 것은 μœ λ‹ˆνΌ λ³€μˆ˜κ°€ 쉐이더 ν”„λ‘œκ·Έλž¨ κ°μ²΄λ§ˆλ‹€ κ³ μœ ν•˜λ©°, 쉐이더 ν”„λ‘œκ·Έλž¨μ˜ μ–΄λ–€ λ‹¨κ³„μ—μ„œλ“  μ–΄λ–€ μ‰μ΄λ”μ—μ„œλ“  μ ‘κ·Όν•  수 μžˆλ‹€λŠ” λœ»μž…λ‹ˆλ‹€.

 

λ‘˜μ§Έ, μ–΄λ–€ 값을 μœ λ‹ˆνΌ κ°’μœΌλ‘œ μ„€μ •ν•˜λ“ , μœ λ‹ˆνΌμ€ λ¦¬μ…‹λ˜κ±°λ‚˜ μ—…λ°μ΄νŠΈλ  λ•ŒκΉŒμ§€ κ·Έ 값을 μœ μ§€ν•©λ‹ˆλ‹€.

 

GLSLμ—μ„œ μœ λ‹ˆνΌμ„ μ„ μ–Έν•˜λ €λ©΄ νƒ€μž…κ³Ό 이름이 μžˆλŠ” 쉐이더에 μœ λ‹ˆνΌ ν‚€μ›Œλ“œλ₯Ό κ°„λ‹¨νžˆ μΆ”κ°€ν•©λ‹ˆλ‹€.

 

κ·Έ ν›„λ‘œλŠ” μ‰μ΄λ”μ—μ„œ μƒˆλ‘œ μ„ μ–Έλœ μœ λ‹ˆνΌμ„ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λ²ˆμ—λŠ” μ‚Όκ°ν˜•μ˜ 색상을 μœ λ‹ˆνΌμ„ 톡해 μ„€μ •ν•΄ λ³΄κ² μŠ΅λ‹ˆλ‹€.

 

#version 330 core
out vec4 FragColor;
  
uniform vec4 ourColor; // μš°λ¦¬λŠ” 이 λ³€μˆ˜λ₯Ό OpenGL μ½”λ“œμ—μ„œ μ„€μ •ν•©λ‹ˆλ‹€.

void main()
{
    FragColor = ourColor;
}

 

μš°λ¦¬λŠ” fragment 쉐이더에 vec4 μœ λ‹ˆνΌ ourColorλ₯Ό μ„ μ–Έν•˜κ³  쑰각의 좜λ ₯ 색상을 이 μœ λ‹ˆνΌ κ°’μ˜ λ‚΄μš©μœΌλ‘œ μ„€μ •ν–ˆμŠ΅λ‹ˆλ‹€.

 

μœ λ‹ˆνΌμ€ μ „μ—­ λ³€μˆ˜μ΄λ―€λ‘œ, μš°λ¦¬κ°€ μ›ν•˜λŠ” 쉐이더 단계 μ–΄λ””μ—μ„œλ“  μ •μ˜ν•  수 μžˆμœΌλ―€λ‘œ 정점 쉐이더λ₯Ό λ‹€μ‹œ 거쳐 fragment μ‰μ΄λ”λ‘œ 무언가λ₯Ό κ°€μ Έκ°ˆ ν•„μš”κ°€ μ—†μŠ΅λ‹ˆλ‹€.

 

μš°λ¦¬λŠ” 이 μœ λ‹ˆνΌμ„ 정점 μ‰μ΄λ”μ—μ„œ μ‚¬μš©ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ κ·Έκ³³μ—μ„œ μ •μ˜ν•  ν•„μš”κ°€ μ—†μŠ΅λ‹ˆλ‹€.

 

GLSL μ½”λ“œμ—μ„œ 어디에도 μ‚¬μš©λ˜μ§€ μ•ŠλŠ” μœ λ‹ˆνΌμ„ μ„ μ–Έν•˜λ©΄ μ»΄νŒŒμΌλŸ¬λŠ” 컴파일된 λ²„μ „μ—μ„œ λ³€μˆ˜λ₯Ό 쑰용히 μ œκ±°ν•˜λŠ”λ°, 이것이 μ—¬λŸ¬ λ‹΅λ‹΅ν•œ 였λ₯˜μ˜ 원인이 λ©λ‹ˆλ‹€; 이 점을 λͺ…μ‹¬ν•˜μ„Έμš”!

 

ν˜„μž¬ μœ λ‹ˆνΌμ€ λΉ„μ–΄ μžˆμŠ΅λ‹ˆλ‹€; 아직 μœ λ‹ˆνΌμ— μ–΄λ–€ 데이터도 μΆ”κ°€ν•˜μ§€ μ•Šμ•˜μœΌλ―€λ‘œ 이제 그것을 μ‹œλ„ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

 

λ¨Όμ € 우리의 μ‰μ΄λ”μ—μ„œ μœ λ‹ˆνΌ μ†μ„±μ˜ 인덱슀/μœ„μΉ˜λ₯Ό μ°Ύμ•„μ•Ό ν•©λ‹ˆλ‹€.

 

μœ λ‹ˆνΌμ˜ 인덱슀/μœ„μΉ˜λ₯Ό μ•Œκ²Œ 되면, κ·Έ 값듀을 μ—…λ°μ΄νŠΈν•  수 μžˆμŠ΅λ‹ˆλ‹€.

 

쑰각 쉐이더에 단일 색상을 μ „λ‹¬ν•˜λŠ” λŒ€μ‹ , μ‹œκ°„μ΄ 지남에 따라 점차 색상이 λ³€ν•˜λ„λ‘ 일을 더 ν₯미둭게 λ§Œλ“€μ–΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

 

float timeValue = glfwGetTime();
float greenValue = (sin(timeValue) / 2.0f) + 0.5f;
int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
glUseProgram(shaderProgram);
glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);

 

λ¨Όμ € glfwGetTime()을 톡해 μ‹€ν–‰ 쀑인 μ‹œκ°„μ„ 초 λ‹¨μœ„λ‘œ κ²€μƒ‰ν•©λ‹ˆλ‹€.

 

그런 λ‹€μŒ sin ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ 0.0 - 1.0 λ²”μœ„μ—μ„œ 색상을 λ³€ν™”μ‹œν‚€κ³  κ·Έ κ²°κ³Όλ₯Ό greenValue에 μ €μž₯ν•©λ‹ˆλ‹€.

 

그런 λ‹€μŒ glGetUniformLocation을 μ‚¬μš©ν•˜μ—¬ ourColor μœ λ‹ˆνΌμ˜ μœ„μΉ˜λ₯Ό μ‘°νšŒν•©λ‹ˆλ‹€.

 

쿼리 ν•¨μˆ˜μ— 쉐이더 ν”„λ‘œκ·Έλž¨κ³Ό μœ λ‹ˆνΌμ˜ 이름(μœ„μΉ˜λ₯Ό κ²€μƒ‰ν•˜λ €λŠ”)을 μ œκ³΅ν•©λ‹ˆλ‹€.

 

glGetUniformLocation이 -1을 λ°˜ν™˜ν•˜λ©΄ μœ„μΉ˜λ₯Ό 찾을 수 μ—†λŠ” κ²ƒμž…λ‹ˆλ‹€.

 

λ§ˆμ§€λ§‰μœΌλ‘œ glUniform4f ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ μœ λ‹ˆνΌ 값을 μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

 

μœ λ‹ˆνΌ μœ„μΉ˜λ₯Ό μ°ΎλŠ” 데 쉐이더 ν”„λ‘œκ·Έλž¨μ„ λ¨Όμ € μ‚¬μš©ν•  ν•„μš”λŠ” μ—†μ§€λ§Œ,

 

μœ λ‹ˆνΌμ„ μ—…λ°μ΄νŠΈν•˜λ €λ©΄ λ¨Όμ € ν”„λ‘œκ·Έλž¨μ„ μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€(glUseProgram을 ν˜ΈμΆœν•¨μœΌλ‘œμ¨),

 

μ™œλƒν•˜λ©΄ 이것은 ν˜„μž¬ ν™œμ„±ν™”λœ 쉐이더 ν”„λ‘œκ·Έλž¨μ— μœ λ‹ˆνΌμ„ μ„€μ •ν•˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.

 

OpenGL은 ν•΅μ‹¬μ μœΌλ‘œ C 라이브러리이기 λ•Œλ¬Έμ— ν•¨μˆ˜ μ˜€λ²„λ‘œλ”©μ— λŒ€ν•œ κΈ°λ³Έ 지원이 μ—†μœΌλ©°, λ‹€λ₯Έ νƒ€μž…μœΌλ‘œ 호좜될 수 μžˆλŠ” ν•¨μˆ˜λŠ” OpenGL이 ν•„μš”ν•œ 각 νƒ€μž…μ— λŒ€ν•œ μƒˆλ‘œμš΄ ν•¨μˆ˜λ₯Ό μ •μ˜ν•©λ‹ˆλ‹€.

 

glUniform은 μ΄λŸ¬ν•œ μ™„λ²½ν•œ μ˜ˆμž…λ‹ˆλ‹€. 이 ν•¨μˆ˜λŠ” μ„€μ •ν•˜λ €λŠ” μœ λ‹ˆνΌμ˜ νƒ€μž…μ— 따라 νŠΉμ • 접미사λ₯Ό μš”κ΅¬ν•©λ‹ˆλ‹€.

 

κ°€λŠ₯ν•œ λͺ‡ κ°€μ§€ μ ‘λ―Έμ‚¬λŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

 

  • f: ν•¨μˆ˜λŠ” float 값을 μ˜ˆμƒν•©λ‹ˆλ‹€.
  • i: ν•¨μˆ˜λŠ” int 값을 μ˜ˆμƒν•©λ‹ˆλ‹€.
  • ui: ν•¨μˆ˜λŠ” unsigned int 값을 μ˜ˆμƒν•©λ‹ˆλ‹€.
  • 3f: ν•¨μˆ˜λŠ” 3개의 float 값을 μ˜ˆμƒν•©λ‹ˆλ‹€.
  • fv: ν•¨μˆ˜λŠ” float 벑터/λ°°μ—΄ 값을 μ˜ˆμƒν•©λ‹ˆλ‹€.

OpenGL의 μ˜΅μ…˜μ„ κ΅¬μ„±ν•˜λ €λ©΄ ν•΄λ‹Ή νƒ€μž…μ— ν•΄λ‹Ήν•˜λŠ” μ˜€λ²„λ‘œλ“œλœ ν•¨μˆ˜λ₯Ό μ„ νƒν•˜κΈ°λ§Œ ν•˜λ©΄ λ©λ‹ˆλ‹€.

 

우리의 κ²½μš°μ—λŠ” μœ λ‹ˆνΌμ˜ 4개 float을 κ°œλ³„μ μœΌλ‘œ μ„€μ •ν•˜λ €κ³  ν•˜λ―€λ‘œ glUniform4fλ₯Ό 톡해 데이터λ₯Ό μ „λ‹¬ν•©λ‹ˆλ‹€(fv 버전을 μ‚¬μš©ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€).

 

이제 μœ λ‹ˆνΌ λ³€μˆ˜μ˜ 값을 μ„€μ •ν•˜λŠ” 방법을 μ•Œμ•˜μœΌλ―€λ‘œ, λ Œλ”λ§μ— 그것을 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

 

색상이 μ μ§„μ μœΌλ‘œ λ³€ν•˜κΈ°λ₯Ό μ›ν•œλ‹€λ©΄, μš°λ¦¬λŠ” λ§€ ν”„λ ˆμž„λ§ˆλ‹€ 이 μœ λ‹ˆνΌμ„ μ—…λ°μ΄νŠΈν•˜λ €κ³  ν•©λ‹ˆλ‹€.

 

κ·Έλ ‡μ§€ μ•ŠμœΌλ©΄ ν•œ 번만 μ„€μ •ν•˜λ©΄ μ‚Όκ°ν˜•μ΄ 단일 고체 색을 μœ μ§€ν•˜κ²Œ λ©λ‹ˆλ‹€. κ·Έλž˜μ„œ μš°λ¦¬λŠ” greenValueλ₯Ό κ³„μ‚°ν•˜κ³  각 λ Œλ”λ§ λ°˜λ³΅μ—μ„œ μœ λ‹ˆνΌμ„ μ—…λ°μ΄νŠΈν•©λ‹ˆλ‹€.

 

while(!glfwWindowShouldClose(window))
{
    // input
    processInput(window);

    // render
    // clear the colorbuffer
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    // be sure to activate the shader
    glUseProgram(shaderProgram);
  
    // update the uniform color
    float timeValue = glfwGetTime();
    float greenValue = sin(timeValue) / 2.0f + 0.5f;
    int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
    glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);

    // now render the triangle
    glBindVertexArray(VAO);
    glDrawArrays(GL_TRIANGLES, 0, 3);
  
    // swap buffers and poll IO events
    glfwSwapBuffers(window);
    glfwPollEvents();
}

 

 

 

λ³΄μ‹œλ‹€μ‹œν”Ό, μœ λ‹ˆνΌμ€ λ§€ ν”„λ ˆμž„λ§ˆλ‹€ 변경될 수 μžˆλŠ” 속성을 μ„€μ •ν•˜κ±°λ‚˜ μ• ν”Œλ¦¬μΌ€μ΄μ…˜κ³Ό 쉐이더 μ‚¬μ΄μ—μ„œ 데이터λ₯Ό κ΅ν™˜ν•˜λŠ” 데 μœ μš©ν•œ λ„κ΅¬μž…λ‹ˆλ‹€.

 

ν•˜μ§€λ§Œ 각 μ •μ λ§ˆλ‹€ 색상을 μ„€μ •ν•˜κ³  μ‹Άλ‹€λ©΄ μ–΄λ–¨κΉŒμš”? κ·Έ κ²½μš°μ—λŠ” 정점 수만큼 λ§Žμ€ μœ λ‹ˆνΌμ„ μ„ μ–Έν•΄μ•Ό ν•©λ‹ˆλ‹€.

 

더 λ‚˜μ€ 해결책은 정점 속성에 더 λ§Žμ€ 데이터λ₯Ό ν¬ν•¨μ‹œν‚€λŠ” 것이며, 이제 μš°λ¦¬κ°€ ν•  μΌμž…λ‹ˆλ‹€.

 

'😸 OpenGL' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

OpenGL μš©μ–΄ 정리  (0) 2023.11.19
[Learn OpenGL] Shaders - 3  (0) 2023.11.18
[Learn OpenGL] Shaders - 1  (1) 2023.11.18
[Learn OpenGL] Hello Triangle - 4  (0) 2023.11.18
[Learn OpenGL] Hello Triangle - 3  (0) 2023.11.17