glUniform3f(x, y, z)
programming for state machine
Normalized device coordinate (NDC) system
Initialization
event callbacks 등록
(Infinite) Event loop
for (fram = 0; !glfwWindowShouldClose(window); frame++)
{
glfwPollEvents();
update();
render();
}
Termination
Vertex definition
void update()
{
// update global simulation parameter
t = float(glfwGetTime())*0.4f;
// tricky aspect correction matrix for non-square window
float aspect = window_size.x/float(window_size.y);
mat4 aspect_matrix =
{
std::min(1/aspect,1.0f), 0, 0, 0,
0, std::min(aspect,1.0f), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
};
// update common uniform variables in vertex/fragment shaders
GLint uloc;
uloc = glGetUniformLocation( program, "b_solid_color" ); if(uloc>-1) glUniform1i( uloc, b_solid_color );
uloc = glGetUniformLocation( program, "aspect_matrix" ); if(uloc>-1) glUniformMatrix4fv( uloc, 1, GL_TRUE, aspect_matrix );
// update vertex buffer by the pressed keys
void update_tess(); // forward declaration
if(b) update_tess();
}
We may put more simulations and transformations here
Uniform variables
Update uniform variables
void render()
{
// clear screen (with background color) and clear depth buffer
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
// notify GL that we use our own program
glUseProgram( program );
// bind vertex array object
glBindVertexArray( vertex_array );
// render two circles: trigger shader program to process vertex data
for( auto& c : circles )
{
// per-circle update
c.update(t);
// update per-circle uniforms
GLint uloc;
uloc = glGetUniformLocation( program, "solid_color" ); if(uloc>-1) glUniform4fv( uloc, 1, c.color ); // pointer version
uloc = glGetUniformLocation( program, "model_matrix" ); if(uloc>-1) glUniformMatrix4fv( uloc, 1, GL_TRUE, c.model_matrix );
// per-circle draw calls
if(b_index_buffer) glDrawElements( GL_TRIANGLES, NUM_TESS*3, GL_UNSIGNED_INT, nullptr );
else glDrawArrays( GL_TRIANGLES, 0, NUM_TESS*3 ); // NUM_TESS = N
}
// swap front and back buffers, and display to screen
glfwSwapBuffers( window );
}
Major actions happen in Shaders
vertex 별로 shader가 따로 병렬로 돌아감
-> vertex buffer로 input 받음
// input attributes of vertices
layout(location=0) in vec3 position;
layout(location=1) in vec3 normal;
layout(location=2) in vec2 texcoord;
// outputs of vertex shader = input to fragment shader
// out vec4 gl_Position: a built-in output variable that should be written in main()
out vec3 norm; // the second output: not used yet
out vec2 tc; // the third output: not used yet
// uniform variables
uniform mat4 model_matrix; // 4x4 transformation matrix: explained later in the lecture
uniform mat4 aspect_matrix; // tricky 4x4 aspect-correction matrix
void main()
{
gl_Position = aspect_matrix*model_matrix*vec4(position,1);
// other outputs to rasterizer/fragment shader
norm = normal;
tc = texcoord;
}
input -> output -> uniform -> main 구조
#ifdef GL_ES
#ifndef GL_FRAGMENT_PRECISION_HIGH // highp may not be defined
#define highp mediump
#endif
precision highp float; // default precision needs to be defined
#endif
// inputs from vertex shader
in vec2 tc; // used for texture coordinate visualization
// output of the fragment shader
out vec4 fragColor;
// shader's global variables, called the uniform variables
uniform bool b_solid_color;
uniform vec4 solid_color;
void main()
{
fragColor = b_solid_color ? solid_color : vec4(tc.xy,0,1);
}
똑같이 input -> output -> uniform -> main 구조
Data Types
Variable Qualifiers
components에 접근하는 방법이 4개가 있음
swizzle operators: select or rearrange components
e.g., vec3 v3 = v.rgb; vec4 v4 = v.zzyx;
안보이는 부분은 안그림
glEnable(); //face culling 가능하게함
glCullFace( GL_Back); //back face를 cull
glFrontface (GL_CCW); //counter-clockwise
-> by default
void keyboard( GLFWwindow* window, int key, int scancode, int action, int mods )
{
...
else if(key==GLFW_KEY_W)
{
b_wireframe = !b_wireframe;
glPolygonMode( GL_FRONT_AND_BACK, b_wireframe ? GL_LINE:GL_FILL );
printf( "> using %s mode\n", b_wireframe ? "wireframe" : "solid" );
}
...
}
사실상 상관은 없는데,
OpenGL이 초기화되고, rendering loop에 들어가기 전! -> geometric objects를 only once 생성함
//usually called after base GL stuffs are initialized
void user_init()
{
... // create objects here ...
{
arrays for vertices를 정의
8각형 예시. vertex index는 총 10개 (origin이랑 시작점, 끝점 따로 처리해서 10개임)
std::vector<vertex> create_circle_vertices( uint N )
{
std::vector<vertex> v = {{ vec3(0), vec3(0,0,-1.0f), vec2(0.5f) }}; // origin
for( uint k=0; k <= N; k++ )
{
float t=PI*2.0f*k/float(N), c=cos(t), s=sin(t);
v.push_back( { vec3(c,s,0), vec3(0,0,-1.0f), vec2(c,s)*0.5f+0.5f } );
}
return v;
}
float t는 각도
circle_t (구조체)
일단 object의 구조체를 정의
struct circle_t
{
vec2 center=vec2(0); // 2D position for translation
float radius=1.0f; // radius
float theta=0.0f; // rotation angle
vec4 color; // RGBA color in [0,1]
mat4 model_matrix; // modeling transformation
// public functions
void update( float t );
};
-> model_matrix는 한번에 보내기 위해 선언함
-> void update(float t)는 circle이 매 frame 변화하기 때문에 render에서 이 update()를 부를거임
create_circles()
여기선 두 개의 circle objects가 instantiated됨
inline std::vector<circle_t> create_circles()
{
std::vector<circle_t> circles;
circle_t c;
c = {vec2(-0.5f,0),1.0f,0.0f,vec4(1.0f,0.5f,0.5f,1.0f)};
circles.emplace_back(c);
c = {vec2(+0.5f,0),1.0f,0.0f,vec4(0.5f,1.0f,1.0f,1.0f)};
circles.emplace_back(c);
return circles;
}
-> 여기선 random이 아니라 수동으로 집어넣음
circle_t::update()
transformation matrix를 build함
inline void circle_t::update( float t )
{
radius = 0.35f+cos(t)*0.1f; // simple animation
theta = t;
float c = cos(theta), s=sin(theta);
// these transformations will be explained in later transformation lecture
mat4 scale_matrix =
mat4 rotation_matrix =
mat4 translate_matrix =
model_matrix = translate_matrix*rotation_matrix*scale_matrix;
}
render()
void render()
{
...
// render two circles: trigger shader program to process vertex data
for( auto& c : circles )
{
// per-circle update
c.update(t);
// update per-circle uniforms
GLint uloc;
uloc = glGetUniformLocation( program, "solid_color" ); if(uloc>-1) glUniform4fv( uloc, 1, c.color ); // pointer version
uloc = glGetUniformLocation( program, "model_matrix" ); if(uloc>-1) glUniformMatrix4fv( uloc, 1, GL_TRUE, c.model_matrix );
// per-circle draw calls
if(b_index_buffer) glDrawElements( GL_TRIANGLES, NUM_TESS*3, GL_UNSIGNED_INT, nullptr );
else glDrawArrays( GL_TRIANGLES, 0, NUM_TESS*3 ); // NUM_TESS = N
}
// swap front and back buffers, and display to screen
glfwSwapBuffers( window );
}