OpenGL 정리 대충

ewillwin·2022년 10월 4일
0

Computer Graphics

목록 보기
1/2
post-thumbnail
post-custom-banner

OpenGL API: Function format

glUniform3f(x, y, z)

  • 보통 앞에 set이 빠졌다고 생각하고 해석하면 됨
  • gl은 그냥 GL library에 속해 있다 뭐 이런 뜻
  • Uniform이 function name임
  • 3은 dimensions
  • f는 x, y, z가 float 라는 뜻
  • 만약 glUniform3fv(p)라면, p는 an array의 pointer임



Event-Driven Programming

  • OpenGL rendering은 event-driven way로 수행됨
  • 초기화가 된 후, program은 무한 루프를 돎
  • GLFW (OpenGL과 함께 사용하기 위한 경랑 유틸리티 라이브러리)가 callback functions들을 등록함
  • event에 응답하여, GLFW가 등록된 callback function을 call함



Rendering Modes for OpenGL

  • 이번 수업에서는 Retained Mode (modern style)로 programming 해야함
    -> array (e.g., vertex buffers)를 send over하고, GPU에 저장함
    -> 그리고 이 array를 multiple rendering에 다시 사용함



OpenGL Pipeline in Retained Mode

  • Vertex Specification의 출력인 input attributes가, Vertex Shader의 입력으로 들어감
  • Vertex Shader의 출력인 gl_Position이, Fragment Shader의 입력으로 들어감



OpenGL as State Machine

programming for state machine

  • 특정 function을 사용하기 전에, 전형적으로 states를 bind 해주어야함
    -> e.g., glBufferData()를 이용해 vertex buffer를 update할 때, glBindBuffer()를 호출해야함
    -> e.g., a program을 사용할 때, glUseProgram()을 호출해야함



Coordinate Systems in OpenGL

Normalized device coordinate (NDC) system

  • 2D (2D는 projection이 없음) 또는 projection 후, object는 NDC system에 위치함
  • left handed coordinates임
    -> 엄지랑 검지가 각각 x축, y축이고 중지가 향하는 방향이 눈에서 나가는 방향임



Common Headers

  • cgmath.h는 교수님의 math library
  • cgut.h는 교수님의 OpenGL utility library
    -> data structures들이 정의되어있음 (e.g., struct vertex; struct mesh;)
    -> utility functions들이 including 되어있음 (e.g., cg_create_window(); cg_init_extensions(); cg_create_program(); cg_destroy_window();)



main()

Initialization

  • cg_create_window()를 통해 window 생성
  • cg_init_extensions()을 통해 OpenGL extensions 초기화
  • cg_create_program(vert_shader_path, frag_shader_path)을 통해 vertex shader와 fragment shader를 compile하고 single GLSL program에 link함
  • user_init()을 통해 user 초기화

event callbacks 등록

  • glfwSet(*)Callback function은 window events와 관련됨
  • (*)는 event type

(Infinite) Event loop

for (fram = 0; !glfwWindowShouldClose(window); frame++)
{
	glfwPollEvents();
    update();
    render();
}
  • glfwPollEvents()는 event를 polling & processing 함
  • 사용자가 정의한 update(), render()는 per frame으로 동작함

Termination

  • user_finalize()는 user-defined된 clean-up
  • cg_destroy_window()는 glfwTerminate()를 호출함



user_init()

  • application의 usage 출력
  • basic GL states 초기화
  • host-side (host는 CPU) vertex attributes 정의
  • vertex buffers, vertex array objects 생성

Vertex definition

  • vertex array 생성 (on host (CPU) side)
  • vertex buffers 생성
    -> OpenGL에서 buffer objects는 많은 양의 data를 GPU로 보낼 때 사용됨
    -> vertex buffers는 vertex shader의 input임
    -> 오직 buffer ID (e.g., vertex_buffer)를 통해 접근할 수 있음



update()

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

  • Read-only global variables in GPU program, which can be accessed when processing any vertices and fragments

Update uniform variables

  • vertex shader와 fragment shader안에 있는 uniform varialbes 를 update함
  • glUniform*()는 CPU variables를 GPU의 uniform variable objects로 복사함



render()

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 );
}
  • framebuffer (screen)을 clear color로 clear함
  • GL에게 우리의 program과 vertex array를 사용할 것을 notify함
  • glDrawArrays()을 호출함으로써 GPU program을 trigger함
  • glfwSwapBuffers()를 이용해 front buffer와 back buffer를 swap하여 monitor에 보이게 함















Shader based OpenGL

Major actions happen in Shaders

  • vertices의 위치와 속성들을 계산
  • pixels의 illumination을 계산

vertex 별로 shader가 따로 병렬로 돌아감

-> vertex buffer로 input 받음



Vertex shader in GLSL

// 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 구조

  • vertex shader의 outputs은 single input vertex의 위치
  • Outputs은 다음 shaders의 inputs (programer 입장에선 이 output이 fragment shader의 input)

Fragment shader in GLSL

#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 구조

  • fragment shader의 outputs는 single input fragment의 color
  • fragColor는 [0, 1]의 값을 가짐 (나중에 [0, 255]로 mapping 됨)



OpenGL Shading Language (GLSL)

  • 모든 shaders는 하나의 main function을 가짐
  • pointer와 동적할당 없음
  • call stack (회귀함수) 없음
  • string, char, double, short, long 없음
  • file I/O, console I/O (e.g., printf) 없음

Data Types

  • void, float, int, uint, bool
  • vec2, vec3, vec4: float vector types
  • ivec2, ivec3, ivec4: int vector types
  • uvec2, uvec3, uvec4: uint vector types
  • bvec2, bvec3, bvec4: bool vector types
  • mat2, mat3, mat4: 2x2, 3x3, 4x4 matrix (non-square matrix -> e.g., mat2x3)
  • sampler1D, sampler2D, sampler3D, samplerCube, ...

Variable Qualifiers

  • 모든 global variables는 qualifiers를 가짐
  • in -> layout을 통해 명시적으로 binding 해줘야함
    e.g., layout(location = 0) in vec3 position; //vertex buffer의 첫번째 원소를 vec3 position에 넣어라
  • output
  • uniform
  • vertex shader의 output은 fragment shader의 input임
  • outputs의 개수는 user-defined지만, 3~4개 이내로 (shader는 vertex 수만큼 돌아가기 때문)
  • uniform은 vertex shader, fragment shader에서 같음/ host program에서 specified됨 (update(), render())



More on GLSL Vector Types

components에 접근하는 방법이 4개가 있음

  • position/direction: .x, .y, .z, .w
  • color: .r, .g, .b, .a
  • texture coordinates: .s, .t, .p, .q
  • array indexing: [0], [1], [2], [3]

swizzle operators: select or rearrange components
e.g., vec3 v3 = v.rgb; vec4 v4 = v.zzyx;















Vertex Ordering for a Triangle

  • triangle은 not double sided임 (앞면, 뒷면이 구분됨)
  • 우린 앞면만 그림 -> counter-clockwise, normal vector가 나를 보도록

Back-Face Culling

안보이는 부분은 안그림

glEnable(); //face culling 가능하게함
glCullFace( GL_Back); //back face를 cull
glFrontface (GL_CCW); //counter-clockwise

-> by default

Wireframe mode rendering

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" );
		}
	...
}
  • GL_LINE은 wireframe mode, GL_FILL은 solid mode
  • glLineWidth()로 line width 바꿀 수 있음

Where you make a geametry

사실상 상관은 없는데,
OpenGL이 초기화되고, rendering loop에 들어가기 전! -> geometric objects를 only once 생성함

//usually called after base GL stuffs are initialized
void user_init()
{
	... // create objects here ...
{

Circle Definition

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는 각도

Instancing

  • modeling을 할 때, 주로 object가 origin에 있고, 방향을 갖고 standard size를 갖은 채로 시작함
    -> instance transformation을 통해 vertices를 scale, orient, and locate 시킴
    -> 각 shader에서 보면, vertex buffer는 1개임/ 각 shader를 통해 transformation을 함 (uniform을 통해 얼마나 scaling, orienting, locating 할 지 보냄)
  • instancing의 개념을 깨닫기 위해, a unit vertex buffer를 사용함
    -> unit-sized이고 located at the origin인 single vertex buffer을 생성함
    -> render()안에서 loop을 돌며 multiple object를 render함
    -> loop 안에서 각각의 circle의 size, position을 바꾸고 vertex shader, fragment shader 안에 있는 uniform variables를 통해 pass함

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()

  • per-circle parameters와 matrices를 update함 (update를 아예 render function으로 가져옴)
    -> 여기선 각 circle마다 color와 matrix를 바꿈
    -> glDrawElements를 호출함으로써 circle을 그림
    -> shader는 각 uniform에 기반하여 각각 다르게 그릴거임
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 );
}


vertex shader

  • vertex shader에서, transformation과 attributes에 기반하여 vertices를 location 시킴

fragment shader

  • texture coordinates를 visualize 함
profile
💼 Software Engineer @ LG Electronics | 🎓 SungKyunKwan Univ. CSE
post-custom-banner

0개의 댓글