440 likes | 681 Views
Programmable shader. Hanyang University Jungsik Park. Objective. Introduction GLSL language definition Data types Qualifiers Operators Constructor and component selector Flow control and function Vertex shader Fragment shader Example Simple shader Phong shading shader. INTRODUCTION.
E N D
Programmable shader Hanyang University Jungsik Park
Objective • Introduction • GLSL language definition • Data types • Qualifiers • Operators • Constructor and component selector • Flow control and function • Vertex shader • Fragment shader • Example • Simple shader • Phong shading shader
Conventional OpenGL rendering pipeline • 파이프라인의 각 박스는 고정된 기능만을 수행
Conventional OpenGL rendering pipeline • OpenGL에서 지원하는 모든 옵션과 상태 변수를 검사해서 적용 여부를 판단해야 하므로 저사양 하드웨어에서는 비효율적(ex 모바일 플랫폼) • Modified Phong illumination model만을 지원하는 고정된 조명 계산 • 물리적인 현실성은 떨어지지만, 계산이 빠르고 대체로 적절한 이미지 생성 • Gouraud shading만을 지원하는 고정된 음영 처리 • 버텍스 색상을 계산한 후, 버텍스 색상을 보간하여 픽셀 색상을 결정 • 마하 밴드가 나타나거나 픽셀값이 잘못 계산될 수 있다.
Extending OpenGL • 그래픽 하드웨어의 발전에 따라 복잡한 그래픽 기법을 적용하기 위한 기능의 지원 필요 • OpenGL은 새로운 버전에 추가된 기능을 확장 기능으로 지원 • 이전 버전의 API를 수정하지 않음으로써 이전 버전과의 호환성 유지 • 함수나 매크로 상수 이름에 확장 기능을 식별할 수 있도록 접미어를 붙여 명명 • _ARB, _EXT, _NV, _ATI 등등 • 프로그래머블 하드웨어를 지원하기 위한 API를 확장 기능으로 제공 • 고정 파이프라인을 이용하는 대신 사용자가 작성한 코드대로 음영 처리를 할 수 있는 프로그래머블 파이프라인의 이용이 가능
Programmable pipeline • 사용자는 vertex shader, fragment shader를 작성하여 다양한 음영처리 기법을 적용할 수 있다.
Shading languages • 저수준 음영처리 언어 • 초기의 음영처리 언어로 어셈블리 언어와 같은 문법을 가진다. • 고수준 음영처리 언어 • C 언어 기반의 언어로 C 언어의 구문을 대부분 포함하면서, 음영처리 프로그램이 쉽도록 언어의 특징과 자료형 추가(ex. 벡터 자료형, 벡터 연산 등) • GLSL(OpenGL Shading Language) • OpenGL용 음영 처리 언어로 OpenGL 2.0의 한 부분 • Cg • OpenGL 및 DirectX를 모두 지원 • OpenGL과 Cg간의 인터페이스는 GLSL과의 인터페이스에 비해 다소 복잡함 • HLSL(High Level Shading Language) • DirectX용 음영 처리 언어
Data types • 스칼라형 • 벡터형 및 행렬형 • 행렬은 열 우선으로 구성된다. • 배열 • 1차원 배열만 가능하고, 상수 크기로 지정되어야 한다(동적 할당 불가). • 배열 크기를 얻는 방법 • 포인터는 지원하지 않는다. • 구조체 • C 언어 형식의 구조체를 사용할 수 있다.
Qualifiers • 타입 한정자 • 사용 예 • attribute • 버텍스 속성에는 built-in vertex attribute와 user-defined vertex attribute가 있다. • user-defined vertex attribute의 경우 ‘attribute’ 한정자를 사용하여 선언하여야 한다. • uniform • 모든 버텍스 처리에서 동일하게 사용되는 전역 상수 • varying • 버텍스 쉐이더에서 프래그먼트 쉐이더로 전달되는 변수 • user-defined varying variable의 경우 버텍스 쉐이더 및 프래그먼트 쉐이더 두 곳 모두에서 선언되어야 한다.
Operators • 연산자 • C 언어 연산자와 유사하나, 포인터 관련 연산자 및 비트 연산자, 형변환 연산자는 지원하지 않는다.
Constructor • 생성자 • 변수의 초기화는 C++ 형식의 생성자를 통해 이루어진다. • 또한 생성자는 초기화 외에도 식에도 사용될 수 있다. • 벡터에 하나의 스칼라값을 지정하면 벡터의 모든 요소에 할당된다. • 전체 데이터 타입을 초기화할 충분한 요소를 지정한다면 스칼라와 벡터, 행렬을 생성자 내에서 혼합해 사용할 수 있고, 여분의 요소가 있는 경우 버려진다. • 행렬은 열우선으로 구성되고, 단일 스칼라값을 지정하는 경우 대각 행렬이 된다(대각 이외의 요소는 0으로 채워진다.). • 형변환은 생성자를 통해서만 가능하다.
Component selector(swizzling) • 벡터 및 행렬의 요소에 접근하는 방법 • 벡터형의 요소에 접근하기 위한 요소 선택자 • 세 종류의 요소 선택자들 중 어느 것을 사용해도 상관없으나 혼합해서 사용할 수는 없다. • 요소 선택자를 이용하여 재배치 및 복제가 가능하다. • 요소 선택자를 사용하여 벡터의 일부 요소만 수정하는 것이 가능하다. • 벡터형의 요소는 배열 첨자 혹은 요소 선택자를 사용해서 접근 가능 • vec v4 = (1.0, 2.0, 3.0, 4.0); • v4[2], v4.b, v4.z, v4.p는 모두 v4의 세 번째 요소에 접근하는 방법이다. • 행렬 형의 경우 배열 첨자를 이용하여 대응 하는 열의 벡터에 접근하고, 이중 배열 첨자를 사용하면 대응하는 열벡터의 요소에 접근할 수 있다.
Flow control • 흐름 제어 구문 • 반복문 • C/C++과 동일한 방식의 for, while, do/while 반복문이 지원되고, 중첩도 가능하다. • if/else • C/C++과 동일한 방식의 if/else 조건문이 지원되고, 중첩도 가능하다.
Function • C 언어와 마찬가지로 쉐이더도 main()로 시작한다. • void main() { … } • 사용자 정의 함수 • 함수의 리턴 타입으로는 배열을 제외한 모든 타입의 사용이 가능하다. • 함수의 인자로는 배열 및 구조체를 포함한 모든 타입의 사용이 가능하다. • Call by value로만 호출되므로 다음의 한정자를 사용하여 함수 내에서 인자의 값이 변경될 수 있는지 여부를 지정할 수 있다. • 재귀함수(recursive function)은 허용되지 않는다.
Vertex shader • 각 버텍스 단위로 처리되어야 하는 기본적인 사항은 다음과 같다. • 입력 • 버텍스 좌표, 법선 벡터, 버텍스 색상, 텍스처 좌표, 재질속성등의 버텍스 속성과 변환행렬, 그리고 기타 사용자 정의 변수 • 처리 • 버텍스 변환 • 모델 좌표계 상의 버텍스 위치와 법선 벡터를 모델뷰 변환행렬과 투영 변환행렬에 의해 클립 좌표계상의 위치로 변환 • 버텍스 색상 계산 • 법선 벡터, 재질속성, 조명등을 이용하여 조명 효과에 의한 버텍스 색상을 계산한다. • 텍스처 좌표 생성 및 변환 • 출력 • 클립 좌표계 상의 버텍스 위치, 전 ·후면에 대한 버텍스 색상, 텍스처 좌표 등 • 계산된 버텍스 위치로 클리핑을 수행 • 계산된 버텍스 색상 및 텍스처 좌표를 보간하여 폴리곤 내부의 각 픽셀의 색상 및 텍스처 좌표 생성 • 그 외에 프래그먼트 쉐이더에 전달할 값은 varying 변수를 통해 전달
Application • Moving vertices • Morphing • Wave motion • Fractals • Particle systems • Lighting • More realistic lighting models • Cartoon shaders
Built-in vertex shader variables • Built-in attribute input variables • glVertex*(), glNormal*(), glColor*(), glTexCoord*() 등의 함수에 의해 전달되는 버텍스 속성 • 그 외의 다른 속성을 전달하는 경우, user-defined attribute variables로 전달
Built-in vertex shader variables • Special output variables • 버텍스에 대한 출력값 • Varying output variables • 프래그먼트 쉐이더에서 사용되기 위한 변수로 같은 폴리곤을 구성하는 버텍스의 출력들간의 보간된 값이 프래그먼트 쉐이더에 전달된다.
Simple vertex shader • 다음은 버텍스 좌표를 클립 좌표계로 변환하고, glColor*() 함수로 지정된 버텍스 색상을 그대로 버텍스에 할당하는 간단한 버텍스 쉐이더의 예이다. • 여기서 gl_Vertex는 glVertex*() 함수에 의해 지정된 버텍스 좌표이고, gl_ModelViewProjectionMatrix는 모델뷰 행렬과 투영 행렬이 곱해진 행렬로 두 변수를 곱함으로써 버텍스 좌표가 클립 좌표계로 변환된다. • gl_Color는 glColor*()에 의해 지정된 버텍스 색상이고, gl_FrontColor는 버텍스의 전면 색상 출력 변수이다. • “gl_” 접두어가 붙은 변수는 built-in 변수로 따로 선언할 필요가 없다. void main() { gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex; gl_FrontColor = gl_Color; }
Fragment shader • 각 프래그먼트 단위로 처리되어야 하는 기본적인 사항은 다음과 같다. • 입력 • 버텍스 색상을 보간하여 생성된 색상, 보간된 텍스처 좌표, 기타 사용자 정의 변수 및 버텍스 쉐이더에서 전달된 varying 변수 • 처리 • 입력 색상으로부터텍스처 매핑, 블렌딩 등의 과정을 거쳐 픽셀 색상을 출력한다. • 출력 • 픽셀 색상 및깊이값
Application • Per fragment lighting calculations • Texture mapping • Image processing environment mapping bump mapping
Built-in fragment shader variables • Input variables • 버텍스 출력 변수들이 보간되어 전달되는 변수 • Output Variables
Simple fragment shader • 다음은 보간된 색상을 그대로 픽셀 색상으로 적용하는 간단한 프래그먼트 쉐이더의 예이다. • 여기서 gl_FrontColor는 버텍스의 전면 색상을 보간하여 생성된 전면 색상이고, gl_FragColor는 최종적으로 출력되는 픽셀의 색상으로 변수이다. • 버텍스 쉐이더와 마찬가지로 “gl_” 접두어가 붙은 변수는 built-in 변수이다. void main() { gl_FragColor = gl_Color; }
glew library • GLSLshader를 사용하기 위해서는 OpenGL 확장 기능을 이용해야한다. • glew(OpenGL Extension Wrangler) library는 OpenGL 확장 기능을 이용할 수 있도록 해 주는 라이브러리로 • http://glew.sourceforge.net • 또는, 그래픽 하드웨어 제조사에서 제공하는 SDK(ex. nVidia OpenGL SDK)를 통해 얻을 수 있다. • glew.h, glew32.lib, glew.dll를 glut library 설치와 동일한 방법으로 설치한다. • 코드에서 glew.h를 인클루드, 프로젝트 속성에서 glew32.lib을 링크한다. • 쉐이더를 사용하기 전에 glewInit()을 호출하여 확장함수들의 주소를 얻어온다.
Setup Steps • Step 1: Create Shaders • Create handles to shaders • Step 2: Specify Shaders • load strings that contain shader source • Step 3: Compiling Shaders • Actually compile source (check for errors) • Step 4: Creating Program Objects • Program object controls the shaders • Step 5: Attach Shaders to Programs • Attach shaders to program obj via handle • Step 6: Link Shaders to Programs • Another step similar to attach • Step 7: Enable Program • Finally, let GPU know shaders are ready
App Setup GLhandleARB vShader, fShader, prog; // handles to objects // Step 1: Create a vertex & fragment shader object vShader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); fShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); // Step 2: Load source code strings into shaders glShaderSourceARB(vShader, 1, &VS_String, NULL); glShaderSourceARB(fShader, 1, &FS_String, NULL); // Step 3: Compile the vertex, fragment shaders. glCompileShaderARB(vShader); glCompileShaderARB(fShader); // Step 4: Create a program object prog = glCreateProgramObjectARB(); // Step 5: Attach the two compiled shaders glAttachObjectARB(prog, vShader); glAttachObjectARB(prog, fShader); // Step 6: Link the program object glLinkProgramARB(prog); // Step 7: Finally, install program object as part of current state glUseProgramObjectARB(prog); 여기서 VS_String은 버텍스 쉐이더 코드가 저장된 문자형 배열, FS_String은 프래그먼트 쉐이더 코드가 저장된 문자형 배열 버텍스 쉐이더나 프래그먼트 쉐이더 중 어느 하나를 attach하지 않는 경우, 해당 쉐이더 대신 고정 기능 쉐이더가 작동하게 된다. 고정 기능 쉐이더를 사용하고자 하는 경우 인자에 0을 지정
Set attribute/uniform values • 쉐이더가 링크될 때, attribute/uniform 변수 테이블이 생성된다. • 쉐이더 내에 선언된 attribute/uniform 이름으로 변수의 테이블 인덱스를 얻어 온다. • GLint i =glGetAttribLocation(P,”myAttrib”)GLint j =glGetUniformLocation(P,”myUniform”) • Attribute/uniform 변수 인덱스를 통해 해당 변수에 값을 할당 • glVertexAttrib1f(i,value)glUniform1f(j,value) • 포인터를 이용하여 전달하는 경우 • glVertexAttribPointer(i,…) // passing attributes using vertex array
Simple shader • Simple.vert • Simple.frag void main() { gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex; gl_FrontColor = gl_Color; } void main() { gl_FragColor = gl_Color; }
PrepareShader function • 버텍스 쉐이더 혹은 프래그먼트 쉐이더를 로드 및 컴파일 한 후, 프로그램 객체에 부착하여 링크시키는 함수 작성 • 파일 입출력 필요 • 컴파일 및 링크 에러 발생시 에러 내용을 쿼리하여 출력해 주는 부분 필요 // 쉐이더를로드, 컴파일, 프로그램객체에부착후링크 int PrepareShader(GLhandleARB *pProgram, char *filename, GLuint flag) { int ret; GLhandleARB *pShader = (GLhandleARB*)malloc(sizeof(GLhandleARB)); FILE *fShader; if (flag != GL_VERTEX_SHADER_ARB && flag != GL_FRAGMENT_SHADER_ARB) return FALSE; fShader = fopen(filename, "rb"); if (fShader == NULL) return FALSE;
PrepareShader function(cont’d) int leng, logLength, success; char **src, *log = NULL; fseek(fShader, 0, SEEK_END); leng = ftell(fShader); src = (char **)malloc(sizeof(char*)); src[0] = (char *)malloc(sizeof(char) *(leng+1)); fseek(fShader, 0, SEEK_SET); fread(src[0], 1, leng, fShader); src[0][leng] = 0; *pShader = glCreateShaderObjectARB(flag); glShaderSourceARB(*pShader, 1, (const GLcharARB **)src, NULL); free(src[0]); free(src); fclose(fShader); glCompileShaderARB(*pShader); glGetObjectParameterivARB(*pShader, GL_OBJECT_COMPILE_STATUS_ARB, &success); if (!success) { glGetObjectParameterivARB(*pShader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &logLength); log = (char *)malloc(sizeof(char)*logLength); glGetInfoLogARB(*pShader, logLength, NULL, log); fprintf(stderr, "%s : shader compile error.\n", filename); fprintf(stderr, "%s\n", log); free(log); ret = FALSE; } 컴파일 오류 체크 및 오류 내용 출력
PrepareShader function(cont’d) else{ glAttachObjectARB(*pProgram, *pShader); glLinkProgramARB(*pProgram); glGetObjectParameterivARB(*pProgram, GL_OBJECT_LINK_STATUS_ARB, &success); if (!success) { glGetObjectParameterivARB(*pProgram, GL_OBJECT_INFO_LOG_LENGTH_ARB, &logLength); log = (char *)malloc(sizeof(char)*logLength); glGetInfoLogARB(*pProgram, logLength, NULL, log); fprintf(stderr, "program link error.\n"); fprintf(stderr, "%s\n", log); free(log); ret = FALSE; } else{ glValidateProgramARB(*pProgram); glGetObjectParameterivARB(*pProgram, GL_OBJECT_VALIDATE_STATUS_ARB, &success); if (!success){ glGetObjectParameterivARB(*pProgram, GL_OBJECT_INFO_LOG_LENGTH_ARB, &logLength); log = (char*)malloc(sizeof(char)*logLength); glGetInfoLogARB(*pProgram, logLength, NULL, log); fprintf(stderr, "program validate error.\n"); fprintf(stderr, "%s\n", log); free(log); ret = FALSE; } else ret = TRUE; } } free(pShader); return ret; } 링크 오류 체크 및 오류 내용 출력
SetupRC()에서 • glewInit() 실행 • 프로그램 객체 생성 및 PrepareShader() 실행 • 쉐이더가 올바르게 준비되었으면 glUseProgramARB()로 해당 프로그램 객체 사용 // OpenGL 확장기능을사용할수있도록초기화 glewInit(); // 프로그램객체(vert+frag) 생성 simpleProgram = glCreateProgramObjectARB(); // 쉐이더를로드하여컴파일및링크후프로그램객체에부착 int ret = PrepareShader(&simpleProgram, "simple.vert", GL_VERTEX_SHADER_ARB); ret |= PrepareShader(&simpleProgram, "simple.frag", GL_FRAGMENT_SHADER_ARB); // 에러가없는경우프로그램객체사용 if (ret) glUseProgramObjectARB(simpleProgram);
프로그램 객체를 전역 변수로 선언 • 프로그램 객체 및 쉐이더 객체는 GLhandleARB 형을 갖는다. • Main() 함수에서 • glutMainLoop()가 끝난 후 • 프로그램 객체 제거 GLhandleARB simpleProgram; // 프로그램객체제거 if (simpleProgram) glDeleteProgramsARB(1, &simpleProgram);
Result • SimpleShader 프로젝트를 빌드 후 실행
Shader code • Phong_shading.vert varying vec3 N; varying vec3 L; varying vec3 E; void main() { gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex; // 시점좌표계상에서조명효과를계산하기위해 // 버텍스좌표를시점좌표계로변환 vec4 eyePosition = gl_ModelViewMatrix*gl_Vertex; // 광원좌표는자동으로시점좌표계로변환되어 // built-in 구조체에저장되어있다. vec4 eyeLightPos = gl_LightSource[0].position; // homogeneous 좌표계형태의법선벡터, 광원벡터, 시점벡터를 // 3차원유클리드 좌표 형태로 varying 변수에저장 N = normalize(gl_NormalMatrix*gl_Normal); L = eyeLightPos.xyz - eyePosition.xyz; E = -eyePosition.xyz; }
Shader code • Phong_shading.frag varying vec3 N; varying vec3 L; varying vec3 E; void main() { vec3 Normal = normalize(N); vec3 Light = normalize(L); vec3 Eye = normalize(E); vec3 Half = normalize(Eye+Light); float f = 1.0; // diffuse 및specular 반사에서vector 내적에의한요소계산 // max() 함수는내적결과가음수인경우0.0으로만들기위함. float Kd = max(dot(Normal,Light), 0.0); float Ks = pow(max(dot(Half,Normal), 0.0), gl_FrontMaterial.shininess); // diffuse, specular, ambient 반사성분계산 vec4 diffuse = Kd*gl_FrontLightProduct[0].diffuse; if (dot(Normal, Light)<0.0) f = 0.0; vec4 specular = f*Ks*gl_FrontLightProduct[0].specular; vec4 ambient = gl_FrontLightProduct[0].ambient; gl_FragColor = ambient + diffuse + specular; }
Result • Gouraud shading • Phong shading