1 Getting started 5 Shaders - JJhuk/LearnOpenGL GitHub Wiki
url: https://learnopengl.com/Getting-started/Shaders μμ±μΌ: 2020λ 12μ 25μΌ μ€ν 2:25
μ Hello Triangle μ±ν°μμ μΈκΈνλ―μ΄, μ °μ΄λλ GPUμ μλ μμ νλ‘κ·Έλ¨μ λλ€. μ΄λ¬ν νλ‘κ·Έλ¨μ κ·Έλν½ νμ΄ν λΌμΈμ κ° νΉμ μΉμ μ λν΄ μ€νλ©λλ€. κΈ°λ³Έμ μΌλ‘ μ °μ΄λλ μ λ ₯μ μΆλ ₯μΌλ‘ λ³ννλ νλ‘κ·Έλ¨μ λλ€. μ °μ΄λλ λν μλ‘ ν΅μ ν μ μλ€λ μ μμ λ§€μ° κ³ λ¦½ λ νλ‘κ·Έλ¨μ λλ€. κ·Έλ€μ΄ κ°μ§κ³ μλ μ μΌν μμ¬ μν΅μ μ λ ₯κ³Ό μΆλ ₯μ ν΅ν΄μμ λλ€.
μ΄μ μ₯μμ μ°λ¦¬λ μ °μ΄λμ νλ©΄κ³Ό κ·Έκ²λ€μ μ μ νκ² μ¬μ©νλ λ°©λ²μ λν΄ κ°λ¨ν λ€λ£¨μμ΅λλ€. μ΄μ μ °μ΄λ, νΉν OpenGL μ °μ΄λ© μΈμ΄μ λν΄ μ’ λ μΌλ°μ μΈ λ°©μμΌλ‘ μ€λͺ νκ² μ΅λλ€.
μ °μ΄λλ Cμ μ μ¬ν μΈμ΄ GLSLλ‘ μμ±λ©λλ€. GLSLμ κ·Έλν½κ³Ό ν¨κ» μ¬μ©νλλ‘ λ§μΆ€νλμμΌλ©° νΉλ³ν λ²‘ν° λ° νλ ¬ μ°μ°μ λμμΌλ‘νλ μ μ©ν κΈ°λ₯μ ν¬ν¨ν©λλ€.
μ °μ΄λλ νμ λ²μ μ μΈμΌλ‘ μμνκ³ μ λ ₯ λ° μΆλ ₯ λ³μ, μ λνΌ λ° λ©μΈ ν¨μλ‘ μ΄μ΄μ§λλ€. κ° μ °μ΄λμ μ§μ μ μ μ λ ₯ λ³μλ₯Ό μ²λ¦¬νκ³ κ²°κ³Όλ₯Ό μΆλ ₯ λ³μμ μΆλ ₯νλ λ©μΈ ν¨μμ μμ΅λλ€. μ λνΌμ΄ λμ§ λͺ¨λ₯΄λλΌλ κ±±μ νμ§ λ§μΈμ. 곧 μλ €λλ¦¬κ² μ΅λλ€.
μ °μ΄λλ μΌλ°μ μΌλ‘ λ€μ ꡬ쑰λ₯Ό κ°μ΅λλ€.
#version version_number
in type in_variable_name;
in type in_variable_name;
out type out_variable_name;
uniform type uniform_name;
void main()
{
// μ
λ ₯(λ€)μ μ²λ¦¬νκ³ μ΄μν κ·Έλν½ μμ
μ μ²λ¦¬ν©λλ€.
...
// μ²λ¦¬λ κ²λ€μ μΆλ ₯ λ³μλ‘ μΆλ ₯ν©λλ€.
out_variable_name = weird_stuff_we_processed;
}
νΉν λ²ν
μ€ μ
°μ΄λμ λν΄ μ΄μΌκΈ° ν λ κ° μ
λ ₯ λ³μλ λ²ν
μ€ μμ±μ΄λΌκ³ λ ν©λλ€. νλμ¨μ΄μ μν΄ μ νμ μΌλ‘ μ μΈ ν μ μλ λ²ν
μ€ μμ±μ μ΅λ κ°μκ° μμ΅λλ€. OpenGLμ νμ μ΅μ 16κ° μ΄μμ 4κ° κ΅¬μ± μμ(vec4 * 16κ°) λ²ν
μ€ μμ±μ μ¬μ©ν μ μμμ 보μ₯νμ§λ§ μΌλΆ νλμ¨μ΄μμλ GL_MAX_VERTEX_ATTRIBS
λ₯Ό 쿼리νμ¬ κ²μ ν μ μλ λ λ§μ μμ±μ νμ©νκΈ°λ ν©λλ€.
int nrAttributes;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes);
std::cout << "Maximum nr of vertex attributes supported: " << nrAttributes << std::endl;
μ΄κ²μ λλΆλΆμ λͺ©μ μ μΆ©λΆν μμΈ μ΅μ 16
μ λ°νν©λλ€.
GLSL has, like any other programming language, data types for specifying what kind of variable we want to work with. GLSL has most of the default basic types we know from languages like C: int
, float
, double
, uint
and bool
. GLSL also features two container types that we'll be using a lot, namely vectors
and matrices
. We'll discuss matrices in a later chapter.
GLSLμ λ€λ₯Έ νλ‘κ·Έλλ° μΈμ΄μ λ§μ°¬κ°μ§λ‘ μ΄λ€ λ³μλ₯Ό μ¬μ©ν μ§ μ§μ νκΈ° μν λ°μ΄ν° μ νμ κ°μ§κ³ μμ΅λλ€. GLSLμ μ°λ¦¬κ° Cμ κ°μ μΈμ΄μμ μκ³ μλ λλΆλΆμ κΈ°λ³Έμ μΈ νμ
λ€μ κ°μ§κ³ μμ΅λλ€ : int
, float
, double
, uint
, bool
. GLSLμ λν μ°λ¦¬κ° λ§μ΄ μ¬μ©ν λ κ°μ§ 컨ν
μ΄λ μ νμΈ λ²‘ν°μ νλ ¬μ μ 곡ν©λλ€. μ΄ν μ₯μμ νλ ¬μ λν΄ λ
Όμν κ²μ
λλ€.
GLSLμ 벑ν°λ λ°©κΈ μΈκΈ ν κΈ°λ³Έ νμ
μ λν 1,2,3 λλ 4κ°μ κ΅¬μ± μμ 컨ν
μ΄λμ
λλ€. λ€μκ³Ό κ°μ νμμ μ·¨ν μ μμ΅λλ€. (n
μ κ΅¬μ± μμμ μλ₯Ό λνλ
λλ€.)
-
vecn
:n
κ°μ floatλ₯Ό κ°μ§λ κΈ°λ³Έ λ²‘ν° -
bvecn
:n
κ°μ booleanμ κ°μ§λ λ²‘ν° -
ivecn
:n
κ°μ μ μλ₯Ό κ°μ§λ λ²‘ν° -
uvecn
:n
κ°μ λΆνΈμλ μ μλ₯Ό κ°μ§λ λ²‘ν° -
dvecn
:n
κ°μ doubleμ κ°μ§λ 벑ν°
λλΆλΆμ λͺ©μ μλ floatκ° μΆ©λΆνλ―λ‘ λλΆλΆμ κ²½μ° κΈ°λ³Έ vecn
μ μ¬μ©ν©λλ€.
벑ν°μ κ΅¬μ± μμλ vec.x
λ₯Ό ν΅ν΄ μ‘μΈμ€ ν μ μμ΅λλ€. μ¬κΈ°μ x
λ 벑ν°μ 첫 λ²μ§Έ κ΅¬μ± μμμ
λλ€. x
, y
, z
λ° w
λ₯Ό μ¬μ©νμ¬ κ°κ° 첫 λ²μ§Έ, λ λ²μ§Έ, μΈ λ²μ§Έ λ° λ€ λ²μ§Έ κ΅¬μ± μμμ μ κ·Όν μ μμ΅λλ€. GLSLμ μ¬μ©νλ©΄ μμμ rgba
λ₯Ό μ¬μ©νκ±°λ ν
μ€μ³ μ’νμ stpq
λ₯Ό μ¬μ©νμ¬ λμΌν κ΅¬μ± μμμ μ κ·Όν μ μμ΅λλ€.
λ²‘ν° λ°μ΄ν° μ νμ μ¬μ©νλ©΄ μ€μμ¦λ§μ΄λΌκ³ νλ ν₯λ―Έλ‘κ³ μ μ°ν κ΅¬μ± μμλ₯Ό μ νν μ μμ΅λλ€. μ€μμ¦λ§μ μ¬μ©νλ©΄ λ€μκ³Ό κ°μ ꡬ문μ μ¬μ©ν μ μμ΅λλ€.
vec2 someVec;
vec4 differentVec = someVec.xyxx;
vec3 anotherVec = differentVec.zyw;
vec4 otherVec = someVec.xxxx + anotherVec.yxzy;
μλ 벑ν°μ ν΄λΉ κ΅¬μ± μμκ° μλ ν μ΅λ 4κ°μ λ¬Έμ μ‘°ν©μ μ¬μ©νμ¬ λμΌν μ νμ μ 벑ν°λ₯Ό μ¬μ©ν μ μμ΅λλ€. μλ₯Ό λ€μ΄ vec2
μ .z
κ΅¬μ± μμμ μ κ·Όν μ μμ΅λλ€. λν 벑ν°λ₯Ό λ€λ₯Έ λ²‘ν° μμ±μ νΈμΆμ μΈμλ‘ μ λ¬νμ¬ νμν μΈμ μλ₯Ό μ€μΌ μ μμ΅λλ€.
vec2 vect = vec2(0.5, 0.7);
vec4 result = vec4(vect, 0.0, 0.0);
vec4 otherResult = vec4(result.xyz, 1.0);
λ°λΌμ 벑ν°λ λͺ¨λ μ’ λ₯μ μ λ ₯ λ° μΆλ ₯μ μ¬μ©ν μ μλ μ μ°ν λ°μ΄ν° μ νμ λλ€. μ΄ μ± μ 체μμ 벑ν°λ₯Ό μ°½μμ μΌλ‘ κ΄λ¦¬ ν μ μλ λ°©λ²μ λν λ§μ μλ₯Ό λ³Ό μ μμ κ²μ λλ€.
μ °μ΄λλ κ·Έ μμ²΄λ‘ λ©μ§ μμ νλ‘κ·Έλ¨μ΄μ§λ§ μ 체μ μΌλΆμ΄λ―λ‘ κ°λ³ μ °μ΄λμ μ λ ₯ λ° μΆλ ₯μ κ°μ Έ μμ μ¬λ£λ₯Ό μ΄λν μ μλλ‘ ν©λλ€.
GLSLμ κ·Έλ¬ν λͺ©μ μ μν΄ in
κ³Ό out
ν€μλλ₯Ό μ μνμ΅λλ€. κ° μ
°μ΄λλ ν΄λΉ ν€μλλ₯Ό μ¬μ©νμ¬ μ
λ ₯ λ° μΆλ ₯μ μ§μ ν μ μμΌλ©° μΆλ ₯ λ³μκ° μ λ¬λλ λ€μ μ
°μ΄λ λ¨κ³μ μ
λ ₯ λ³μμ μΌμΉνλ μμΉλ₯Ό μ§μ ν μ μμ΅λλ€. νμ§λ§ λ²ν
μ€ λ° νλ κ·Έλ¨ΌνΈ μ
°μ΄λλ μ½κ° λ€λ¦
λλ€.
λ²ν
μ€ μ
°μ΄λλ μ΄λ ν ννμ μ
λ ₯μ λ°λμ λ°μμΌ ν©λλ€. κ·Έλ μ§ μμΌλ©΄ λΉν¨μ¨μ μ
λλ€. λ²ν
μ€ μ
°μ΄λλ λ²ν
μ€ λ°μ΄ν°μμ μ§μ μ
λ ₯μ λ°λλ€λ μ μμ μ
λ ₯μ΄ λ€λ¦
λλ€. λ²ν
μ€ λ°μ΄ν°κ° ꡬμ±λλ λ°©μμ μ μνκΈ° μν΄ μμ§ λ©ν λ°μ΄ν°λ‘ μ
λ ₯ λ³μλ₯Ό μ§μ νμ¬ CPUμμ λ²ν
μ€ μμ±μ ꡬμ±ν μ μμ΅λλ€. μ΄μ μ₯μμ μ΄κ²μ layout (location = 0)
μΌλ‘ 보μμ΅λλ€. λ°λΌμ λ²ν
μ€ μ
°μ΄λλ μ
λ ₯μ λν μΆκ° λ μ΄μμ μ¬μμ΄ νμνλ―λ‘ λ²ν
μ€ λ°μ΄ν°μ μ°κ²°ν μ μμ΅λλ€.
layout (location = 0)
μ§μ μλ₯Ό μλ΅νκ³ glGetAttribLocationμ ν΅ν΄ OpenGL μ½λμ μμ± μμΉλ₯Ό 쿼리 ν μλ μμ§λ§ λ²ν
μ€ μ
°μ΄λμμ μ€μ νλ κ²μ μ νΈν©λλ€. κ·Έκ²μ΄ λ μ΄ν΄νκΈ° μ½κ³ λμ(κ·Έλ¦¬κ³ OpenGLλ) μμ
μ μ μ½μμΌ μ£ΌκΈ° λλ¬Έμ
λλ€.
λ€λ₯Έ μμΈλ νλ κ·Έλ¨ΌνΈ μ
°μ΄λκ° μ΅μ’
μΆλ ₯ μμμ μμ±ν΄μΌ νλ―λ‘ νλ κ·Έλ¨ΌνΈ μ
°μ΄λμ vec4
μμ μΆλ ₯ λ³μκ° νμνλ€λ μ μ
λλ€. νλκ·Έλ¨ΌνΈ μ
°μ΄λμμ μΆλ ₯ μμμ μ§μ νμ§ μμΌλ©΄ ν΄λΉ νλκ·Έλ¨ΌνΈμ λν μμ λ²νΌ μΆλ ₯μ΄ μ μλμ§ μμ΅λλ€. (μΌλ°μ μΌλ‘ OpenGLμ΄ κ²μμ λλ ν°μμΌλ‘ λλλ§ νλκ²μ λ»ν¨)
λ°λΌμ ν μ °μ΄λμμ λ€λ₯Έ μ °μ΄λλ‘ λ°μ΄ν°λ₯Ό 보λ΄λ €λ©΄ 보λ΄λ μ °μ΄λμμ μΆλ ₯μ μ μΈνκ³ μμ μ °μ΄λμμ μ μ¬ν μ λ ₯μ μ μΈν΄μΌ ν©λλ€. μ νκ³Ό μ΄λ¦μ΄ μμͺ½μμ λμΌνλ©΄ OpenGLμ ν΄λΉ λ³μλ₯Ό ν¨κ» μ°κ²° ν λ€μ μ °μ΄λ κ°μ λ°μ΄ν°λ₯Ό λ³΄λΌ μ μμ΅λλ€. (νλ‘κ·Έλ¨ κ°μ²΄λ₯Ό linkingν λ μνλ©λλ€.) μ΄κ²μ΄ μ€μ λ‘ μ΄λ»κ² μλνλμ§ λ³΄μ¬μ£ΌκΈ° μν΄ μ΄μ μ₯μ μ °μ΄λλ₯Ό λ³κ²½νμ¬ λ²ν μ€ μ °μ΄λκ° νλ κ·Έλ¨ΌνΈ μ °μ΄λλ₯Ό κ²°μ νλλ‘ ν κ²μ λλ€.
Vertex shader
#version 330 core
layout (location = 0) in vec3 aPos; // μμΉ λ³μλ μμ± μμΉ 0μ κ°μ§λλ€.
out vec4 vertexColor; // νλ κ·Έλ¨ΌνΈ μ
°μ΄λμ μμ μΆλ ₯ μ§μ
void main()
{
gl_Position = vec4(aPos, 1.0); // vec3μ vec4μ μμ±μμ μ§μ μ 곡νλ λ°©λ²
vertexColor = vec4(0.5, 0.0, 0.0, 1.0); // μΆλ ₯ λ³μλ₯Ό μ§ν λΉ¨κ°μΌλ‘ μ§μ
}
Fragment shader
#version 330 core
out vec4 FragColor;
in vec4 vertexColor; // λ²ν
μ€ μ
°μ΄λμμ μ¨ μ
λ ₯ λ³μ (κ°μ μ΄λ¦κ³Ό νμ
)
void main()
{
FragColor = vertexColor;
}
vertexColor λ³μλ₯Ό λ²ν
μ€ μ
°μ΄λμμ μ€μ ν vec4
μΆλ ₯μΌλ‘ μ μΈνκ³ , νλ κ·Έλ¨ΌνΈ μ
°μ΄λμμ λΉμ·ν vertexColor μ
λ ₯μ μ μΈ ν κ²μ λ³Ό μ μμ΅λλ€. λ λ€ λμΌν μ νκ³Ό μ΄λ¦μ κ°κΈ° λλ¬Έμ νλκ·Έλ¨ΌνΈ μ
°μ΄λμ vertexColorλ λ²ν
μ€ μ
°μ΄λμ vertexColorμ μ°κ²°λ©λλ€. λ²ν
μ€ μ
°μ΄λμμ μμμ μ§ν λΉ¨κ° μμΌλ‘ μ€μ νμΌλ―λ‘ νλ κ·Έλ¨ΌνΈμ κ²°κ³Όλ μ§ν λΉ¨κ°μμ΄μ΄μΌ ν©λλ€. λ€μ μ΄λ―Έμ§λ κ²°κ³Όλ₯Ό 보μ¬μ€λλ€
μ κ°λλ€! λ²ν μ€ μ °μ΄λμμ νλ κ·Έλ¨ΌνΈ μ °μ΄λλ‘ κ°μ λ³΄λΌ μ μμμ΅λλ€. μ‘°κΈ λ λ©μ§κ² κΎΈλ―Έκ³ μμ© νλ‘κ·Έλ¨μμ νλ κ·Έλ¨ΌνΈ μ °μ΄λλ‘ μμμ λ³΄λΌ μ μλμ§ μ΄ν΄λ³΄κ² μ΅λλ€
Uniformμ CPUμ μ ν리μΌμ΄μ μμ GPUμ μ °μ΄λλ‘ λ°μ΄ν°λ₯Ό μ λ¬νλ λ λ€λ₯Έ λ°©λ²μ λλ€. κ·Έλ¬λ μ λνΌμ λ²ν μ€ μμ±μ λΉν΄ μ½κ° λ€λ¦ λλ€. μ°μ μ λνΌμ μ μμ λλ€. λ¬΄μ¨ λ»μ΄λλ©΄ μ λνΌ λ³μλ μ °μ΄λ νλ‘κ·Έλ¨ κ°μ²΄λ§λ€ κ³ μ νλ©° μ °μ΄λ νλ‘κ·Έλ¨μ λͺ¨λ λ¨κ³μμ λͺ¨λ μ °μ΄λκ° μ‘μΈμ€ ν μ μμμ μλ―Έν©λλ€. λλ²μ§Έλ‘, μ λνΌμ κ°μ μ€μ νλ κ²κ³Ό μκ΄μμ΄ μ λνΌμ μ¬μ€μ λκ±°λ μ λ°μ΄νΈ λ λκΉμ§ κ°μ μ μ§ν©λλ€.
GLSLμμ μ λνΌμ μ μΈνλ €λ©΄ μ΄λ¦μ΄ μλ μ
°μ΄λμ uniform
μ΄λΌλ ν€μλλ₯Ό μΆκ° νκΈ°λ§νλ©΄ λ©λλ€. κ·Έ μμ λΆν° μ
°μ΄λμμ μλ‘ μ μΈλ μ λνΌμ μ¬μ©ν μ μμ΅λλ€. μ΄λ²μλ μ λνΌμ ν΅ν΄ μΌκ°νμ μμμ μ€μ ν μ μλμ§ μ΄ν΄ λ³΄κ² μ΅λλ€.
#version 330 core
out vec4 FragColor;
uniform vec4 ourColor; // OpenGL μ½λμμ μ΄ λ³μλ₯Ό μ€μ ν©λλ€.
void main()
{
FragColor = ourColor;
}
νλ κ·Έλ¨ΌνΈ μ
°μ΄λμμ μ λνΌ vec4
OurColorλ₯Ό μ μΈνκ³ νλκ·Έλ¨ΌνΈμ μΆλ ₯ μμμ μ λνΌκ°μΌλ‘ μ€μ νμ΅λλ€. μ λνΌμ μ μ λ³μμ΄λ―λ‘ μνλ μ
°μ΄λ λ¨κ³μμ μ μν μ μμΌλ―λ‘ νλκ·Έλ¨Όν μΌμ΄λμ λκ°λ₯Ό κ°μ Έ μ€κΈ° μν΄ λ€μ λ²ν
μ€ μ
°μ΄λλ₯Ό κ±°μΉ νμκ° μμ΅λλ€. λ²ν
μ€ μ
°μ΄λμμ μ΄ μ λνΌμ μ¬μ©νμ§ μμΌλ―λ‘ κ±°κΈ°μμ μ μ ν νμκ° μμ΅λλ€.
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 ν¨μλ₯Ό μ¬μ©νμ¬ μ λνΌμ κ°μ μ€μ ν μ μμ΅λλ€. μ λνΌμ μμΉλ₯Ό μ°Ύλ λ° μ
°μ΄λ νλ‘κ·Έλ¨μ λ¨Όμ μ¬μ©ν νμλ μμ§λ§ μ λνΌ μ
λ°μ΄νΈ λ νμ¬ νμ±ν λ μ
°μ΄λ νλ‘κ·Έλ¨μμ uniformμ μ€μ νλ―λ‘ λ¨Όμ νλ‘κ·Έλ¨μ μ¬μ©ν΄μΌ ν©λλ€ (glUseProgramνΈμΆ)
OpenGLμ ν΅μ¬μ CλΌμ΄λΈλ¬λ¦¬μ μκΈ° λλ¬Έμ ν¨μ μ€λ²λ‘λ©μ λν κΈ°λ³Έ μ§μμ΄ μμΌλ―λ‘ λ€λ₯Έ μ νμΌλ‘ ν¨μλ₯Ό νΈμΆ ν μ μλ κ³³μ΄λ©΄ μ΄λμμλ OpenGLμ νμν κ° μ νμ λν΄ μ ν¨μλ₯Ό μ μν©λλ€.
glUniformμ΄ μ΄μ λν μλ²½ν μμ λλ€. μ΄ κΈ°λ₯μ μ€μ νλ €λ μ λνΌμ νμ λν νΉμ μ λ―Έμ¬κ° νμν©λλ€. κ°λ₯ν μ λ―Έμ¬ μ€ λͺ κ°μ§λ λ€μκ³Ό κ°μ΅λλ€.
-
f
: ν¨μκ° κ°μ΄float
λΌκ³ μμν©λλ€. -
i
: ν¨μκ° κ°μ΄int
λΌκ³ μμν©λλ€. -
ui
: ν¨μκ° κ°μ΄unsigned int
λΌκ³ μμν©λλ€. -
3f
: ν¨μλ κ°μ΄ 3κ°μfloat
λΌκ³ μκ°ν©λλ€. -
fv
: ν¨μλ κ°μ΄float
λ°±ν°/λ°°μ΄μ΄λΌκ³ μκ°ν©λλ€.
OpenGL μ΅μ
μ κ΅¬μ± ν λλ§λ€ μ νμ ν΄λΉνλ μ€λ²λ‘λ λ κΈ°λ₯μ μ ννκΈ°λ§ νλ©΄ λ©λλ€. μ°λ¦¬μ κ²½μ° glUniform4fλ₯Ό ν΅ν΄ λ°μ΄ν°λ₯Ό μ μ λ¬νκΈ° μν΄ uniformμ 4κ°μ floatλ₯Ό κ°λ³μ μΌλ‘ μ€μ νλ €κ³ ν©λλ€. (fv
λ²μ λ μ¬μ©ν μ μμ).
μ΄μ κ· μΌ λ³μμ κ°μ μ€μ νλ λ°©λ²μ μμμΌλ―λ‘ λ λλ§μ μ¬μ©ν μ μμ΅λλ€. μμμ μ μ§μ μΌλ‘ λ³κ²½νλ €λ©΄ 맀 νλ μλ§λ€ μ΄ μ λνΌμ μ λ°μ΄νΈ ν΄μΌ ν©λλ€. κ·Έλ μ§ μμΌλ©΄ μΌκ°νμ ν λ²λ§ μ€μ νλ©΄ λ¨μμ μ μ§ν©λλ€. λ°λΌμ μ°λ¦¬λ greenValueλ₯Ό κ³μ°νκ³ κ° λ λλ§ λ°λ³΅λ§λ€ uniformμ μ λ°μ΄νΈν©λλ€.
while(!glfwWindowShouldClose(window))
{
// μ
λ ₯
processInput(window);
// λ λ
// μ»¬λ¬ λ²νΌ ν΄λ¦¬μ΄
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// μ
°μ΄λλ₯Ό νμ±νν΄μΌ ν©λλ€.
glUseProgram(shaderProgram);
// 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);
// μΌκ°νμ λ λλ§ν©λλ€.
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
// λ²νΌ μ€μ λ° IO μ΄λ²€νΈ ν΄λ§
glfwSwapBuffers(window);
glfwPollEvents();
}
μ΄ μ½λλ μ΄μ μ½λλ₯Ό λΉκ΅μ κ°λ¨νκ² μμ ν κ²μ λλ€. μ΄λ²μλ μΌκ°νμ 그리기 μ μ κ° νλ μλ§λ€ κ· μΌν κ°μ μ λ°μ΄νΈ ν©λλ€. μ λνΌμ μ¬λ°λ₯΄κ² μ λ°μ΄νΈ νλ©΄ μΌκ°νμ μμμ΄ μ μ°¨ λ Ήμμμ κ²μμμΌλ‘, λ€μ λ ΉμμΌλ‘ λ³νλ κ²μ λ³Ό μ μμ΅λλ€.
λ¬Έμ κ° μλ κ²½μ° μ¬κΈ°μμ μμ€μ½λλ₯Ό νμΈνμΈμ.
보μλ€μνΌ μ λνΌμ λͺ¨λ νλ μμ λ³κ²½ν μ μλ μμ±μ μ€μ νκ±°λ μ ν리μΌμ΄μ κ³Ό μ °μ΄λ κ°μ λ°μ΄ν°λ₯Ό κ΅ννλ λ° μ μ©ν λꡬμ λλ€.νμ§λ§ κ° λ²ν μ€μ λν μμμ μ€μ νλ €λ©΄ μ΄λ»κ² ν΄μΌ ν κΉμ? μ΄ κ²½μ°μλ μ°λ¦¬κ° κ°μ§ λ²ν μ€λ§νΌμ uniformμ μ μΈν΄μΌ ν©λλ€. λ λμ ν΄κ²°μ± μ λ²ν μ€ μμ±μ λ λ§μ λ°μ΄ν°λ₯Ό ν¬ν¨νλ κ²μ λλ€.
μ΄μ μ₯μμ VBOλ₯Ό μ±μ°κ³ , λ²ν
μ€ μμ± ν¬μΈν°λ₯Ό ꡬμ±νκ³ , λͺ¨λ κ²μ VAOμ μ μ₯νλ λ°©λ²μ 보μμ΅λλ€. μ΄λ²μλ λ²ν
μ€ λ°μ΄ν°μ μμ λ°μ΄ν°λ μΆκ°νλ €κ³ ν©λλ€. μμ λ°μ΄ν°λ₯Ό vertices λ°°μ΄μ 3κ°μ float
λ₯Ό μΆκ°ν κ²μ
λλ€. μΌκ°νμ κ° λͺ¨μ리μ λΉ¨κ°μ, μ΄λ‘μ λ° νλμμ κ°κ° ν λΉν©λλ€.
float vertices[] = {
// μμΉ // μμ
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // μ€λ₯Έμͺ½ νλ¨
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // μΌμͺ½ νλ¨
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // μλ¨
};
μ΄μ λ²ν μ€ μ °μ΄λλ‘ λ³΄λΌ λ λ§μ λ°μ΄ν°κ° μμΌλ―λ‘ λ²ν μ€ μμ± μ λ ₯μΌλ‘ μμ κ°λ μμ νλλ‘ λ²ν μ€ μ °μ΄λλ μ‘°μ ν΄μΌ ν©λλ€. aColor μμ±μ λ μ΄μμ μ§μ μλ₯Ό μ¬μ©νμ¬ μμΉλ₯Ό 1λ‘ μ€μ νμ΅λλ€.
#version 330 core
layout (location = 0) in vec3 aPos; // μμΉ λ³μλ μμ± μμΉ 0μ κ°μ§λλ€.
layout (location = 1) in vec3 aColor; // μμ λ³μλ μμ± μμΉ 1μ κ°μ§λλ€.
out vec3 ourColor; // μΆλ ₯ μμμ νλ κ·Έλ¨ΌνΈ μ
°μ΄λλ‘ κ°λλ€.
void main()
{
gl_Position = vec4(aPos, 1.0);
ourColor = aColor; // ourColorλ₯Ό λ²ν
μ€ λ°μ΄ν°μμ μ»μ μ
λ ₯ μμμΌλ‘ μ€μ ν©λλ€
}
νλ κ·Έλ¨ΌνΈ μμμ λ μ΄μ uniformμ μ¬μ©νμ§λ μμ§λ§, μ΄μ ourColor μΆλ ₯ λ³μλ₯Ό μ¬μ©νλ―λ‘ νλ κ·Έλ¨ΌνΈ μ °μ΄λλ λ³κ²½ν΄μΌ ν©λλ€.
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
void main()
{
FragColor = vec4(ourColor, 1.0);
}
λ€λ₯Έ λ²ν μ€ μμ±μ μΆκ°νκ³ VBOμ λ©λͺ¨λ¦¬λ₯Ό μ λ°μ΄νΈ νκΈ° λλ¬Έμ λ²ν μ€ μμ± ν¬μΈν°λ₯Ό λ€μ ꡬμ±ν΄μΌ ν©λλ€. VBO λ©λͺ¨λ¦¬μ μ λ°μ΄νΈ λ λ°μ΄ν°λ μ΄μ λ€μκ³Ό κ°μ΄ 보μ λλ€.
νμ¬ λ μ΄μμμ μλ©΄ glVertexAttribPointerλ‘ λ²ν μ€ νμμ μ λ°μ΄νΈ ν μ μμ΅λλ€.
// μμΉ μμ±
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// μμ μμ±
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3* sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointerμ μμ μλ λͺκ°μ μΈμλ λΉκ΅μ κ°λ¨ν©λλ€. μ΄λ²μλ μμ± μμΉ 1
μ vertex μμ±μ ꡬμ±ν©λλ€. μμ κ°μ ν¬κΈ°λ float
3
μ΄λ©° κ°μ μ κ·ν νμ§ μμ΅λλ€
μ΄μ λ κ°μ λ²ν
μ€ μμ±μ΄ μμΌλ―λ‘ stride
κ°μ λ€μ κ³μ°ν΄μΌ ν©λλ€. λ°μ΄ν° λ°°μ΄μμ λ€μ μμ± κ° (μ : μμΉ λ²‘ν°μ λ€μ x
κ΅¬μ± μμ)μ μ»μΌλ €λ©΄ 6
float
μ μ€λ₯Έμͺ½μΌλ‘, 3κ°λ μμΉ κ°μΌλ‘, 3κ°λ μμ κ°μΌλ‘ μ΄λν΄μΌ ν©λλ€. μ΄κ²μ μ°λ¦¬μκ² float
ν¬κΈ° (= 24
λ°μ΄νΈ)μ 6λ°°μ stride
κ°μ μ 곡ν©λλ€.
λν μ΄λ²μλ μ€νμ
μ μ§μ ν΄μΌ ν©λλ€. κ° λ²ν
μ€μ μμΉ λ²ν
μ€ μμ±μ΄ λ¨Όμ μ΄λ―λ‘ μ€νμ
0
μ μ μΈν©λλ€. color μμ±μ μμΉ λ°μ΄ν° λ€μμ μμνλ―λ‘ μ€νμ
μ λ°μ΄νΈ λ¨μμ 3 * sizeof (float)
(= 12
λ°μ΄νΈ) μ
λλ€.
μ ν리μΌμ΄μ μ λ€μ μμνλ©΄ λ€μ μ΄λ―Έμ§κ° νμλ©λλ€.
λ¬Έμ κ° μλ κ²½μ° μ¬κΈ°μμ μμ€ μ½λλ₯Ό νμΈνμΈμ.
νμ¬ λ³΄κ³ μλ μ΄λ―Έμ§λ κ±°λν μμ νλ νΈκ° μλ 3κ°μ§ μμλ§ μ 곡νκΈ° λλ¬Έμ μ΄λ―Έμ§κ° μμν κ²κ³Ό μ νν μΌμΉνμ§ μμ μ μμ΅λλ€. μ΄κ²μ λͺ¨λ νλ κ·Έλ¨ΌνΈ μ °μ΄λμμ νλ κ·Έλ¨ΌνΈ λ³΄κ°(interpolation)μ΄λΌκ³ νλ κ²μ κ²°κ³Όμ λλ€. μΌκ°νμ λ λλ§ ν λ λ μ€ν°ν λ¨κ³λ μΌλ°μ μΌλ‘ μλ μ§μ λ λ²ν μ€λ³΄λ€ ν¨μ¬ λ§μ νλ κ·Έλ¨ΌνΈλ₯Ό μμ±ν©λλ€. κ·Έλ° λ€μ λ μ€ν°λΌμ΄μ λ μΌκ°ν λͺ¨μμ μμΉμ λ°λΌ κ° νλ κ·Έλ¨ΌνΈ μμΉλ₯Ό κ²°μ ν©λλ€.
μ΄λ¬ν μμΉλ₯Ό κΈ°λ°μΌλ‘ λͺ¨λ νλ κ·Έλ¨ΌνΈ μ
°μ΄λμ μ
λ ₯ λ³μλ₯Ό 보κ°ν©λλ€. μλ₯Ό λ€μ΄ μμͺ½ μ μ΄ λ
Ήμμ΄κ³ μλμͺ½ μ μ΄ νλμμΈ μ μ΄ μλ€κ³ κ°μ ν©λλ€. νλκ·Έλ¨ΌνΈ μ
°μ΄λκ° λΌμΈμ 70%
μμΉ μ£Όλ³μ μλ νλκ·Έλ¨ΌνΈμ£ γ
μ€νλλ κ²½μ° κ²°κ³Ό μμμ μ
λ ₯ μμ±μ λ
Ήμκ³Ό νλμμ μ ν μ‘°ν©μ΄ λ©λλ€. λ μ ννκ² λ§νλ©΄ 30%
μ νλμκ³Ό 70%
μ λ
Ήμμ
λλ€.
μ΄κ²μ΄ λ°λ‘ μΌκ°νμμ μΌμ΄λλ μΌμ λλ€. μ°λ¦¬λ 3κ°μ κΌμ§μ κ³Ό 3κ°μ μμμ κ°μ§κ³ μμΌλ©° μΌκ°νμ ν½μ λ‘ λ³Ό λ λλ΅ 50000κ°μ νλ κ·Έλ¨ΌνΈλ₯Ό ν¬ν¨νκ³ μμ κ²μ λλ€ .μμμ μ μ΄ν΄λ³΄λ©΄ λͺ¨λ κ²μ΄ μλ―Έκ° μμμ μ μ μμ΅λλ€. λΉ¨κ°μμμ νλμμΌλ‘ λ¨Όμ 보λΌμμ΄ λκ³ νλμμΌλ‘ λ°λλλ€. νλκ·Έλ¨ΌνΈ λ³΄κ°μ λͺ¨λ νλκ·Έλ¨ΌνΈ μ °μ΄λμ μ λ ₯ μμ±μ μ μ©λ©λλ€.
μ °μ΄λ μμ±, μ»΄νμΌ λ° κ΄λ¦¬λ λ§€μ° λ²κ±°λ‘μΈ μ μμ΅λλ€. μ °μ΄λ μ£Όμ μ λν λ§μ§λ§ μμ μΌλ‘μ, μ°λ¦¬λ μ °μ΄λλ₯Ό λμ€ν¬μμ μ½κ³ , μ»΄νμΌ νκ³ , μ°κ²°νκ³ , μ€λ₯λ₯Ό νμΈνκ³ , μ¬μ©νκΈ° μ¬μ΄ μ °μ΄λ ν΄λμ€λ₯Ό λ§λ€μ΄ μ°λ¦¬μ μΆμ μ’ λ μ½κ² λ§λ€ κ²μ λλ€. μ΄κ²μ λν μ°λ¦¬κ° μ§κΈκΉμ§ λ°°μ΄ μ§μμ μΌλΆλ₯Ό μ μ©ν μΆμμ μΈ λ¬Όμ²΄μ μ΄λ»κ² μΊ‘μνν μ μλμ§μ λν μμ΄λμ΄λ₯Ό μ 곡ν©λλ€.
μ °μ΄λ ν΄λμ€λ μ£Όλ‘ νμ΅ λͺ©μ κ³Ό ν΄λμ±μ μν΄ ν€λ νμΌλ‘ μμ±νκ² μ΅λλ€. λ¨Όμ νμν μΈν΄λ£¨λ νλͺ©μ μΆκ°νκ³ ν΄λμ€ κ΅¬μ‘°λ₯Ό μ μνμΈμ.
#ifndef SHADER_H
#define SHADER_H
#include <glad/glad.h> // νμν OpenGL ν€λλ₯Ό λͺ¨λ κ°μ Έμ¬ μ μλ gladλ₯Ό ν¬ν¨ν©λλ€.
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
class Shader
{
public:
// νλ‘κ·Έλ¨ ID
unsigned int ID;
// μμ±μκ° μ
°μ΄λλ₯Ό μ½κ³ μμ±ν©λλ€.
Shader(const char* vertexPath, const char* fragmentPath);
// μ
°μ΄λλ₯Ό μ¬μ©/νμ±νν©λλ€.
void use();
// μ λνΌ ν¨μ μ νΈλ¦¬ν°
void setBool(const std::string &name, bool value) const;
void setInt(const std::string &name, int value) const;
void setFloat(const std::string &name, float value) const;
};
#endif
ν€λ νμΌ λ§¨ μμ λͺ κ°μ§ μ μ²λ¦¬κΈ° μ§μλ¬Έμ μ¬μ©νμ΅λλ€. μ΄λ° 짧μ μ½λλ₯Ό μ¬μ©νλ©΄ μ¬λ¬ νμΌμ μ °μ΄λ ν€λκ° ν¬ν¨λμ΄ μλλΌλ μμ§ ν¬ν¨λμ§ μμ κ²½μ°μλ§ μ΄ ν€λ νμΌμ ν¬ν¨νκ³ μ»΄νμΌνλλ‘ μ»΄νμΌλ¬μ μ립λλ€. μ΄κ²μ μ°κ²° μΆ©λμ λ°©μ§ν©λλ€.
μ
°μ΄λ ν΄λμ€λ μ
°μ΄λ νλ‘κ·Έλ¨μ IDλ₯Ό 보μ ν©λλ€. μμ±μλ λμ€ν¬μ κ°λ¨ν ν
μ€νΈ νμΌλ‘ μ μ₯ν μ μλ λ²ν
μ€ λ° νλ κ·Έλ¨ΌνΈ μ
°μ΄λμ μμ€ μ½λ νμΌ κ²½λ‘λ₯Ό κ°κ° νμλ‘ ν©λλ€. μ½κ°μ μΆκ° κΈ°λ₯μ μΆκ°νκΈ° μν΄ λͺ κ°μ§ μ νΈλ¦¬ν° ν¨μλ₯Ό μΆκ°νμ¬ μ‘°κΈ λ νΈλ¦¬νκ² ν©λλ€. use
λ μ
°μ΄λ νλ‘κ·Έλ¨μ νμ±ν νκ³ λͺ¨λ set
μΌλ‘ μμνλ ν¨μλ κ· μΌν μμΉλ₯Ό 쿼리νκ³ κ°μ μ€μ ν©λλ€.
C++ νμΌ μ€νΈλ¦Όμ μ¬μ©νμ¬ νμΌμ λ΄μ©μ μ¬λ¬ string
κ°μ²΄λ‘ μ½μ΅λλ€.
Shader(const char* vertexPath, const char* fragmentPath)
{
// 1. filePathμμ λ²ν
μ€/νλ κ·Έλ¨ΌνΈ μμ€μ½λ κ²μ
std::string vertexCode;
std::string fragmentCode;
std::ifstream vShaderFile;
std::ifstream fShaderFile;
// ifstream κ°μ²΄κ° μμΈλ₯Ό throwν μ μλμ§ νμΈν©λλ€.
vShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
fShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
try
{
// νμΌ μ΄κΈ°
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath);
std::stringstream vShaderStream, fShaderStream;
// νμΌμ λ²νΌ λ΄μ©μ μ€νΈλ¦ΌμΌλ‘ μ½μ΅λλ€
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// νμΌ ν¨λ€λ¬λ₯Ό λ«μ΅λλ€
vShaderFile.close();
fShaderFile.close();
// μ€νΈλ¦Όμ μ€νΈλ§μΌλ‘ λ³κ²½ν©λλ€
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
}
catch(std::ifstream::failure e)
{
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
}
const char* vShaderCode = vertexCode.c_str();
const char* fShaderCode = fragmentCode.c_str();
[...]
λ€μμΌλ‘ μ °μ΄λλ₯Ό μ»΄νμΌνκ³ μ°κ²°ν΄μΌν©λλ€. λν μ»΄νμΌ/ λ§ν¬ μ€ν¨ μ¬λΆλ₯Ό κ²ν νκ³ μλ κ²½μ°μλ μ»΄νμΌ νμ μ€λ₯λ₯Ό μΆλ ₯ν©λλ€. μ΄κ²μ λλ²κΉ ν λ μ μ©ν©λλ€ (μ΄λ¬ν μ€λ₯ λ‘κ·Έκ° νμν©λλ€.
// 2. μ
°μ΄λ μ»΄νμΌ
unsigned int vertex, fragment;
int success;
char infoLog[512];
// λ²ν
μ€ μ
°μ΄λ
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
// μ΄λ ν μ»΄νμΌ μλ¬κ° μμΌλ©΄ μΆλ ₯ν©λλ€.
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if(!success)
{
glGetShaderInfoLog(vertex, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
};
// νλ κ·Έλ¨ΌνΈ μ
°μ΄λλ λΉμ·ν©λλ€.
[...]
// μ
°μ΄λ νλ‘κ·Έλ¨
ID = glCreateProgram();
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
glLinkProgram(ID);
// λ§νΉ μλ¬κ° μμ κ²½μ° μΆλ ₯ν©λλ€.
glGetProgramiv(ID, GL_LINK_STATUS, &success);
if(!success)
{
glGetProgramInfoLog(ID, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
// μ
°μ΄λκ° μ§κΈ νλ‘κ·Έλ¨μ μ°κ²°λμ΄ μκ³ λμ΄μ νμνμ§ μμΌλ μμ
glDeleteShader(vertex);
glDeleteShader(fragment);
use ν¨μλ κ°λ¨ν©λλ€.
void use()
{
glUseProgram(ID);
}
Uniform setter ν¨μλ€μ λ€ λΉμ·ν©λλ€.
void setBool(const std::string &name, bool value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
}
void setInt(const std::string &name, int value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}
void setFloat(const std::string &name, float value) const
{
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
}
κ·ΈλΌ μμ± λ μ °μ΄λ ν΄λμ€κ° μμ΅λλ€. μ °μ΄λ ν΄λμ€λ₯Ό μ¬μ©νλ κ²μ λ§€μ° μ½μ΅λλ€. μ °μ΄λ κ°μ²΄λ₯Ό ν λ² λ§λ€κ³ κ·Έ μμ λΆν° μ¬μ©μ μμνλ©΄ λ©λλ€.
Shader ourShader("path/to/shaders/shader.vs", "path/to/shaders/shader.fs");
[...]
while(...)
{
ourShader.use();
ourShader.setFloat("someUniform", 1.0f);
DrawStuff();
}
μ¬κΈ°μλ shader.vs
μ shader.fs
λΌλ λ νμΌμ λ²ν
μ€ λ° νλ κ·Έλ¨ΌνΈ μ
°μ΄λ μμ€ μ½λλ₯Ό μ μ₯νμ΅λλ€. μνλλλ‘ μ
°μ΄λ νμΌμ μ΄λ¦μ μμ λ‘κ² μ§μ ν μ μμ΅λλ€. κ°μΈμ μΌλ‘ .vs
μ .fs
νμ₯μκ° λ§€μ° μ§κ΄μ μ΄λΌκ³ μκ°ν©λλ€.
μλ‘ μμ±λ μ °μ΄λ ν΄λμ€λ₯Ό μ¬μ©νμ¬ μ¬κΈ°μμ μμ€ μ½λλ₯Ό μ°Ύμ μ μμ΅λλ€. μ °μ΄λ νμΌ κ²½λ‘λ₯Ό ν΄λ¦νμ¬ μ °μ΄λμ μμ€ μ½λλ₯Ό μ°Ύμ μ μμ΅λλ€.
- μΌκ°νμ΄ κ±°κΎΈλ‘ λλλ‘ λ²ν μ€ μ °μ΄λλ₯Ό μ‘°μ ν©λλ€: μ λ΅
- uniformμ ν΅ν΄ μν μ€νμ μ μ μ₯νκ³ , μ΄ μ€νμ κ°μ μ¬μ©νμ¬ λ²ν μ€ μ °μ΄λμμ νλ©΄ μ€λ₯Έμͺ½μΌλ‘ μΌκ°νμ μ΄λν©λλ€.: μ λ΅
-
out
ν€μλλ₯Ό μ¬μ©νμ¬ κΌμ§μ μμΉλ₯Ό νλ κ·Έλ¨ΌνΈ μ °μ΄λλ‘ λκ²¨μ£Όκ³ νλ κ·Έλ¨ΌνΈμ μμμ κΌμ§μ μμΉμ λμΌνκ² μ€μ ν©λλ€ (λ²ν μ€ μμΉ κ°μ΄ μΌκ°νμ κ°λ‘μ§λ¬ 보κ°λλ λ°©μ μ°Έκ³ ). μ΄λ κ²νλ©΄ μ μΌκ°νμ μΌμͺ½ μλ λΆλΆμ΄ κ²μμμΌκΉμ? : μ λ΅