제 16 장 고수준 셰이딩 언어 소개

Download Report

Transcript 제 16 장 고수준 셰이딩 언어 소개

제 16 장
고수준 셰이딩 언어 소개
고수준 셰이딩 언어 소개


고수준 셰이딩 언어(HLSL : High-Level Shading Language)란, 버
텍스와 픽셀 셰이더를 프로그래밍 하는데 이용
버텍스와 픽셀 셰이더
• 고정 기능 파이프라인을 대체하는 작은 커스텀 프로그램이며
• 그래픽 카드의 GPU에서 실행
• 고정 기능 파이프 라인을 우리가 직접 작성한 커스텀 셰이더 프
로그램으로 대체함으로서 구현 가능한 그래픽 효과의 범위가 엄
청 넓어짐
2009-1학기
컴퓨터게임(DirectX)
2

HLSL을 이용하는 데 따르는 이점
• 생산성 향상 – 저수준 언어보다는 고수준 언어를 이용해 프로그램을 작
성하는 것이 훨씬 쉬움. 따라서 코딩 자체보다는 알고리즘에 더욱 많은
시간을 투자할 수 있음
• 가독성 향상 – 고수준 언어로 작성된 프로그램은 읽고 이해하기가 쉬움.
즉, 고수준 언어로 작성된 프로그램은 디버그와 관리에도 이점이 있음
• 컴파일러는 종종 프로그래머가 직접 작성한 어셈블리 코드보다 효율적
인 코드를 만들어냄
• HLSL 컴파일을 이용해 다른 셰이더 버전을 위한 코드를 만들 수 있음.
2009-1학기
컴퓨터게임(DirectX)
3


버텍스 셰이더와 픽셸 셰이더를 지원하지 않는 그래픽 카드의 경우
에는 REF 장치 이용
이
•
•
•
장의 내용
HLSL 셰이더 프로그램을 작성하고 컴파일하는 방법
어플리케이션과 셰이더 프로그램간의 데이터를 교환하는 방법
HLSL 의 구문, 형, 내장 함수
2009-1학기
컴퓨터게임(DirectX)
4
HLSL 셰이더 작성하기
• 애플리케이션 소스 파일 내에서 하나의 긴 문자열로 HLSL코드를 포함
하는 것도 가능하지만
• 모듈화나 편리함의 측면에서는 애플리케이션의 코드와 셰이더 코드를
분리하는 것이 바람직함
 메모장 등과 같은 텍스트 편집기를 이용해 셰이더를 작성하고
 일반 ASCII 텍스트파일로 저장한 다음
 D3DXCompileShaderFromFile 함수를 이용해 셰이더를 컴파일
2009-1학기
컴퓨터게임(DirectX)
5
버텍스 셰이더의 예(Transform.txt)
• 결합된 뷰와 투영 행렬로 버텍스를 변환하고 버텍스의 난반사 컬러 성분을
파란색으로 지정
//
//
//
//
Globals
Global variable to store a combined view and projection
transformation matrix. We initialize this variable
from the application.
matrix ViewProjMatrix;
// Initialize a global blue color vector.
vector Blue = {0.0f, 0.0f, 1.0f, 1.0f};
2009-1학기
컴퓨터게임(DirectX)
6
2009-1학기
// Structures
// Input structure describes the vertex that is input
// into the shader. Here the input vertex contains
// a position component only.
struct VS_INPUT
{
vector position : POSITION;
};
// Output structure describes the vertex that is
// output from the shader. Here the output
// vertex contains a position and color component.
struct VS_OUTPUT
{
vector position : POSITION;
vector diffuse : COLOR;
};
컴퓨터게임(DirectX)
7
// Main Entry Point, observe the main function
// receives a copy of the input vertex through
// its parameter and returns a copy of the output
// vertex it computes.
//
VS_OUTPUT Main(VS_INPUT input)
{
// zero out members of output
VS_OUTPUT output = (VS_OUTPUT)0;
// transform to view space and project
output.position = mul(input.position, ViewProjMatrix);
2009-1학기
컴퓨터게임(DirectX)
8
// set vertex diffuse color to blue
output.diffuse = Blue;
return output;
}
2009-1학기
컴퓨터게임(DirectX)
9
전역
• 먼저 두 개의 전역 변수 인스턴스를 만듦
matrix ViewProjMatrix;
vector Blue={0.0f, 0.0f, 1.0f, 1.0f};
• 첫번째 변수인 ViewProjMatrix는 HLSL에 내장된 4X4 행렬 형.
 결합된 뷰와 투영 행렬을 보관하며
 두 가지의 변환을 하나의 행렬로 해결하기 위한 것.즉, 두 번
의 벡터-행렬 곱을 하나의 작업으로 해결할 수 있음
• 두번째 변수인 Blue는 내장된 벡터 형이며 4D 벡터임.
 이 변수를 RGBA 컬러 벡터로 취급하여 파란색으로 해당하는
컬러 성분을 초기화
2009-1학기
컴퓨터게임(DirectX)
10
입력과 출력 구조체
• 전역 변수를 선언한 뒤에는 입력 구조체와 출력 구조체로 불리는 두 개
의 특별한 구조체를 정의.
• 버텍스 셰이더의 경우에 이 구조체들은 셰이더가 입력하고 출력하는 버
텍스 데이터를 의미
struct VS_INPUT
{
vector position : POSITION;
};
struct VS_OUTPUT
{
vector position : POSITION;
vector diffuse : COLOR;
};
2009-1학기
컴퓨터게임(DirectX)
11

특수한 콜론 구문은 변수의 이용법을 지정하는 의미를 표기.
• 버텍스 구조체의 유연한 버텍스 포맷(FVF)과 매우 비슷. 예를 들어,
VS_INPUT 의 멤버 중

vector position : POSITION;
• “: POSITION” 구문은 입력 버텍스의 위치를 나타내는데
벡터 position을 이용할 것임을 지정
• VS_OUT 의 멤버 중
 vector diffuse : COLOR;
• “: COLOR” 구문은 출력 버텍스의 컬러를 나타내는데 벡터
diffuse 를 이용할 것임을 지정
2009-1학기
컴퓨터게임(DirectX)
12
진입점 함수





C++과 마찬가지로 모든 HLSL 프로그램은 진입점을 가짐
이 예제에서는 진입점 함수의 이름은 Main으로 지정했지만,
함수의 이름은 고정된 것이 아니므로 형식이 올바르다면 어떤 것이
나 될 수 있음
진입점 함수는 반드시 셰이더로 입력 버텍스를 전달하는 입력 구조
체 인자를 가져야 하며,
출력 구조체 인스턴스를 리턴하며, 이는 셰이더에서 만들어낸 버텍
스를 외부로 전달하는 역할을 함

2009-1학기
VS_OUTPUT Main(VS_INPUT input)
{
컴퓨터게임(DirectX)
13

입력과 출력 구조체는 강제적인 것이 아니라, 다음 구문도 가능
• float4 Main(in float2 base : TEXCOORD0,
in float2 spot : TEXCOORD1,
in float2 text : TEXCOORD2) : COLOR
{
…
}



2009-1학기
이 인자들은 셰이더로 입력되며, 예에서는 세 개의 텍스처 좌표를
입력하고 있음.
이 셰이더는 또한 : COLOR 구문으로 표기된 하나의 컬러를 출력으
로 리턴
다음의 선언과 같은 효과
컴퓨터게임(DirectX)
14
struct INPUT
{
float2 base : TEXCOORD0;
float2 spot : TEXCOORD1;
float2 text : TEXCOORD2;
};
struct OUTPUT
{
float4 c : COLOR;
}
OUTPUT Main(INPUT input)
{
…
}
2009-1학기
컴퓨터게임(DirectX)
15





진입점 함수의 본체는 주어진 입력 버텍스를 이용해 출력 버텍스를 계산하
는 역할을 담당
이 예제의 셰이더는 단순히 입력 버텍스를 뷰 스페이스와 투영 스페이스로
변환하고 버텍스의 컬러를 파란색으로 지정한 다음 결과 버텍스를 리턴
먼저, VS_OUTPUT 인스턴스를 만들고 모든 멤버를 0으로 지정
• VS_OUTPUT output=(VS_OUTPUT)0; //출력 멤버를 0으로 초기화
이어 벡터-행렬 곱과 행렬-행렬 곱을 모두 수행할 수 있는 내장 함수 mul을
이용해 입력 버텍스 위치를 ViewProjMatrix 변수로 변환.
결과로 얻어진 변환된 벡터는 output 인스턴스의 position 멤버에 저장
• output.position = mul(input.position, ViewProjMatrix);
2009-1학기
컴퓨터게임(DirectX)
16


다음 output 멤버의 diffuse 컬러 멤버를 Blue로 지정
• output.diffuse = Blue;
마지막으로 결과 버텍스를 리턴
• return output; }
2009-1학기
컴퓨터게임(DirectX)
17
HLSL 셰이더의 컴파일

상수 테이블
• 모든 셰이더는 내부의 변수를 보관하기 위한 상수 테이블을 가지
고 있으며,
• D3DX라이브러리는 애플리케이션이 셰이더의 상수 테이블에 접
근할 수 있도록 하는 ID3DXConstantTable 인터페이스를 제공.
• 즉, 이 인터페이스를 이용하면 애플리케이션 코드에서 셰이더 소
스 코드 내의 변수 값을 지정할 수 있음
2009-1학기
컴퓨터게임(DirectX)
18
상수로의 핸들 얻기
애플리케이션 코드에서 셰이더의 특정 변수를 지정하기 위해서는 먼
저 변수를 참조하는 방법이 필요

이를 위해, D3DXHANDLE이 이용.

다음 메서드는 셰이더의 지정된 이름의 변수로 통하는 D3DXHANDLE
를 리턴
D3DXHANDLE ID3DXConstantTable::GetConstantByName(
D3DXHANDLE hConstant, // 상수의 유효 범위
LPCSTR pName // 상수의 이름
);
 hConstant – 우리가 원하는 변수가 존재하는 부모 구조체를 식
별하기 위한 D3DXHANDLE. 0을 지정하면 최상위 변수로의 핸
들을 의미.
 pName – 핸들을 얻고자 하는 셰이더 소스 코드 내의 변수 이
름
2009-1학기
19

컴퓨터게임(DirectX)
• 예를 들어, 원하는 셰이더의 변수 이름이 ViewProjMatrix이고, 이
것이 최상위 레벨 인자라면 다음과 같은 코드를 이용
 D3DXHANDLE h0;
h0=ConstTable->GetConstantByName(0,”ViewProjMatrix”);
2009-1학기
컴퓨터게임(DirectX)
20
상수 값 설정하기
• 셰이더 코드 내의 변수를 연결하는 D3DXHANDLE을 얻은 다음에는
• ID3DXConstantTable::SetXXX 메서드를 이용해 애플리케이션에서 셰
이더의 변수 값을 지정할 수 있음.
 XXX는 지정하려는 변수의 형을 의미하는 형 이름으로 대체
• 예를 들어, 지정하려는 변수가 벡터 배열이라면 메서드의 이름은
SetVectorArray가 됨.
• ID3DXConstantTable::SetXXX 메서드의 일반적인 형식:

2009-1학기
HRESULT ID3DXConstantTable::SetXXX(
LPDIRECT3DDEVICE9 pDevice,
D3DXHANDLE hConstant,
XXX value
);
컴퓨터게임(DirectX)
21



2009-1학기
pDevice – 상수 테이블과 연결된 장치로의 포인터
hConstant – 지정하려는 변수를 참조하는 핸들
value – 지정하려는 변수의 값, XXX는 지정하려는 변수의 형
으로 대체. 일부 형(부울, 정수, 부동 소수)의 경우에는 변수
의 복사본을 전달하며, 다른 형(벡터, 행렬, 구조체)의 경우에
는 값으로의 포인터를 전달
컴퓨터게임(DirectX)
22
• 배열의 값을 지정하는 경우 SetXXX 메서드는 배열 내 요소의 수를
지정하는 부가적인 네 번째 인자를 받음.
• 예를 들어, 4D 벡터의 배열 값을 지정하는 메서드는 다음과 같은
프로토타입을 가짐

2009-1학기
HRESULT ID3DXConstantTable:SetVectorArray(
LPDIRECT3DDEVICE9 pDevice, //연결된 장치
D3DXHANDLE hConstant, // 셰이더 변수로의 핸들
CONST D3DXVECTOR4* pVector, //배열로의 포인터
UNIT Count //배열 내 요소의 수
);
컴퓨터게임(DirectX)
23
ID3DXConstantTable 인터페이스로 지정할
수 있는 형
•
•
•
•
•
•
•
•
•
•
•
•
2009-1학기
SetBool – 부울 값을 지정함
SetBoolArray – 부울 배열의 값을 지정
SetFloat – 부동 소수 값을 지정
SetFloatArray – 부동 소수 배열의 값을 지정
SetInt – 정수 값을 지정
SetIntArray – 정수 배열의 값을 지정
SetMatrix – 4X4 행렬의 값을 지정
SetMatrixArray – 4X4 행렬 배열의 값을 지정
SetMatrixPointerArray – 4X4 행렬 포인터의 배열 값을 지정
SetMatrixTranspose – 전치 4X4 행렬의 값을 지정
SetMatrixTransposeArray – 전치 4X4 행렬의 배열 값을 지정
SetMatrixTransposePointerArray – 4X4 전체 행렬의 포인터 배
열 값을 지정
컴퓨터게임(DirectX)
24
• SetVector – D3DXVECTOR4 형 변수의 값을 지정
• SetVectorArray – 벡터 배열의 변수 값을 지정
• SetValue – 구조체와 같이 임의의 값을 가진 형의 값을 지정하는
데 이용
2009-1학기
컴퓨터게임(DirectX)
25
상수의 디폴트 값 지정
• 다음의 메서드는 상수가 선언될 때 초기화되는 값인 디폴트 값으
로 상수 값을 지정함.
• 애플리케이션 셋업 과정에서 한 번만 호출
 HRESULT ID3DXConstantTable::SetDefaults(
LPDIRECT3DDEVICE9 pDevice
);
 pDevice – 상수 테이블과 연결된 장치로의 포인터
2009-1학기
컴퓨터게임(DirectX)
26
HLSL 셰이더 컴파일

다음의 함수를 이용해 텍스트 파일에 저장된 셰이더를 컴파일할 수
있음
 HRESULT D3DXCompileShaderFromFile(
LPCSTR pSrcFile,
CONST D3DXMACRO* pDefines,
LPD3DXINCLUDE pInclude,
LPCSTR pFunctionName,
LPCSTR pTarget,
DWORD Flags,
LPD3DXBUFFER* ppShader,
LPD3DXBUFFER* ppErrorMsgs,
LPD3DXCONSTANTTABLE* ppConstantTable
);
2009-1학기
컴퓨터게임(DirectX)
27






2009-1학기
pSrcFile – 컴파일하려는 셰이더 소스 코드를 포함하는 텍스트 파일
의 이름
pDefines – 이 인자는 선택 사항이며, 이 책에서는 null로 지정
pInclude – ID3DXIclude 인터페이스의 포인터. 이 인터페이스는 애
플리케이션에서 구현하여 디폴트 포함 동작을 오버라이드할 수 있
도록 디자인
pFunctionName – 진입점 함수의 이름을 지정하는 문자열
pTarget – HLSL 소스 코드를 컴파일할 셰이더 버전을 지정하는 문
자열. 예를 들어 버전 2.0 의 버텍스 쉐이더로 컴파일할 때는 이 인
자에 vs_2_0 전달.
Flags – 선택적인 컴파일링 플래그; 0을 지정하여 플래그를 지정하
지 않거나 다음과 같은 선택적 플래그들을 사용
• D3DXSHADER_DEBUG – 컴파일러가 디버그 정보를 생성
• D3DXSHADER_SKIPVALIDATION – 컴파일러가 코드 검증을
수행하지 않도록 함
컴퓨터게임(DirectX)
28



2009-1학기
• D3DXSHADER_SKIPOPTIMIZATION – 컴파일러가 코드
최적화를 수행하지 않도록 함
ppShader – 컴파일된 셰이더 코드를 포함하는 ID3DXBuffer
로의 포인터를 리턴
ppErrorMsgs – 오류 코드와 메시지 문자열을 포함하는
ID3DXBuffer로의 포인터를 리턴
ppConstantTable – 셰이더의 상수 테이블 데이터를 포함하
는 ID3DXConstantTable로의 포인터를 리턴
컴퓨터게임(DirectX)
29
D3DXCompileShaderFromFile 호
출의 예

// 셰이더 컴파일
ID3DXConstantTable* TransformConstantTable = 0;
ID3DXBuffer* shader
= 0;
ID3DXBuffer* errorBuffer = 0;
hr = D3DXCompileShaderFromFile(
"transform.txt",
0,
0,
"Main", // entry point function name
"vs_1_1",// shader version to compile to
D3DXSHADER_DEBUG,
&shader,
&errorBuffer,
&TransformConstantTable);
2009-1학기
컴퓨터게임(DirectX)
30
// output any error messages
if( errorBuffer )
{
::MessageBox(0, (char*)errorBuffer>GetBufferPointer(), 0, 0);
d3d::Release<ID3DXBuffer*>(errorBuffer);
}
if(FAILED(hr))
{
::MessageBox(0, "D3DXCreateEffectFromFile() FAILED", 0, 0);
return false;
}
2009-1학기
컴퓨터게임(DirectX)
31
변수 형

스칼라 형
• bool – True 혹은 False 값. HLSL은 True와 False 키워드를 제
공
• int – 32비트 부호 정수
• half – 16비트 부동 소수점 수
• float – 32비트 부동 소수점 수
• double – 64비트 부동 소수점 수
2009-1학기
컴퓨터게임(DirectX)
32

벡터 형
• vector – float 성분을 가지는 4D 벡터
• vector<T,n> - n차원의 벡터, 각각의 성분은 T형의 스칼라. 차원
n은 반드시 1에서 4 내에 있어야 함. 다음은 2D double 벡터의
예.
 vector<double,2> vec2;
• 벡터의 성분에 접근하는 데는 배열 첨자 구문을 이용할 수 있음.
• 예를 들어 벡터 vec의 i번째 성분 값을 지정하기 위해서는 다음
과 같은 코드를 이용
 vec[i]=2.0f;
2009-1학기
컴퓨터게임(DirectX)
33
• 부가적으로 구조체의 멤버에 접근하듯이 벡터 vec의 성분에 접
근하는 방법도 있음
 vec.x=vec.r=1.0f;
vec.y=vec.g=1.0f;
vec.z=vec.b=3.0f;
vec.w=vec.a=4.0f;
 이름 r, g, b, a는 이름 x, y, z, w와 정확하게 같은 성분을 의
미.
 컬러를 나타내는 벡터를 이용할 때는 RGBA 표기법을 이용해
벡터가 컬러를 나타내고 있다는 사실을 확실히 하는 것이 바
람직함
2009-1학기
컴퓨터게임(DirectX)
34
• 이외에도 각각 2D, 3D, 4D 벡터를 나타내는 다음과 같은 미리
정의된 형을 이용할 수도 있음
float2 vec2;
float3 vec3;
float4 vec4;
• 벡터 u=(ux,uy,uz,uw)를 가지고 있고 이 벡터의 성분을 벡터 v에
복사하고자 한다고 가정해보면 가장 쉽게 생각할 수 있는 방법은
개별적으로 u의 성분을 v로 복사하는 것
• HLSL은 성분의 순서에 구애받지 않고 복사를 수행하는 특수한
구문을 가지고 있음
vector u={1.0f, 2.0f, 3.0f, 4.0f};
vector v={0.0f, 0.0f, 5.0f, 6.0f};
v=u.xyyw; // v={1.0f, 2.0f, 2.0f, 4.0f}
2009-1학기
컴퓨터게임(DirectX)
35
• 벡터를 복사할 때 모든 성분을 복사할 필요는 없음.
• 예를 들어 다음과 같은 코드 형식을 이용해 x-와 y- 성분만을 복사할 수
도 있음
vector u={1.0f, 2.0f, 3.0f, 4.0f};
vector v={0.0f, 0.0f, 5.0f, 6.0f};
v=u.xy; // v={1.0f, 2.0f, 5.0f, 6.0f}
2009-1학기
컴퓨터게임(DirectX)
36

행렬 형
• HLSL의 내장 행렬 형
 matrix – 4X4 행렬, 각 항목은 float임
 matrix<T,m,n> - mXn 행렬, 각 항목은 스칼라 형 T임.
 행렬의 차원인 m과 n은 반드시 1에서 4 내에 있어야 함.
 다음은 2X2 정수 행렬의 예
• matrix<int, 2, 2> m2x2;
2009-1학기
컴퓨터게임(DirectX)
37
• 선택적으로 다음과 같은 구문을 이용해 m X n 행렬을 만들 수 있음
 floatmxn matmxn;
 예)
• float2x2 mat2x2;
• float3x3 mat3x3;
• float4x4 mat4x4;
• float2x4 mat2x4;
• int2x2 i2x2;
• int2x2 i3x3;
• int2x2 i2x4;
• 이중 배열 첨자 구문을 이용해 행렬의 항목에 접근할 수 있음.
• 예를 들어, 행렬 M의 ij번째 항모의 값을 지정하고자 한다면 다음과 같은
형식을 이용
 M[i][j]=value;
2009-1학기
컴퓨터게임(DirectX)
38
• 부가적으로 구조체의 멤버에 접근하듯이 행렬 M의 항목을 참조
하는 것도 가능
• 다음과 같은 항목 이름이 정의되어 있음


2009-1학기
1-기반:
• M._11=M._12=M._13=M._14=0.0f;
• M._21=M._22=M._23=M._24=0.0f;
• M._31=M._32=M._33=M._34=0.0f;
• M._31=M._42=M._43=M._44=0.0f;
0-기반:
• M._m00=M._m01=M._m02=M._m03=0.0f;
• M._m10=M._m11=M._m12=M._m13=0.0f;
• M._m20=M._m21=M._m22=M._m23=0.0f;
• M._m30=M._m31=M._m32=M._m33=0.0f;
컴퓨터게임(DirectX)
39
• 때로는 행렬 내의 특정 행 벡터를 참조할 필요가 있으며, 이럴 때
는 단일 배열 첨자 구문을 이용.
• 예를 들어, 행렬 M의 i번째 행 벡터를 참조하고자 한다면 다음과
같은 코드를 이용
 vector ithRow = M[i]; //M내의 i번째 행 벡터를 얻는다
2009-1학기
컴퓨터게임(DirectX)
40


배열
• C++과 비슷한 구문을 이용해 특정한 형의 배열을 선언할 수 있
음
 float M[4][4];
half p[4];
vector v[12];
구조체
• 구조체는 C++에서와 동일한 방법으로 정의할 수 있음.
• 차이점은 HLSL의 구조체는 멤버 함수를 가질 수 없다는 것.
• 다음은 HLSL에서 구조체를 정의하는 예를 보여줌
2009-1학기
컴퓨터게임(DirectX)
41
struct MyStruct
{
matrix T;
vector n;
float f;
int x;
bool b;
};
MyStruct s; //인스턴스화
s.f=5.0f; //멤버접근
2009-1학기
컴퓨터게임(DirectX)
42

typedef 키워드
• HLSL의 typedef 키워드는 C++에서와 정확하게 같은 일을 함.
• 예를 들어 다음과 같은 구문을 이용해 vector<float,3>형에 point라는
이름을 부여
 typedef vector<float,3> point;
• 이제는 다음과 같은 코드 대신에,
 vector<float,3> myPoint;
• 다음과 같은 코드를 이용할 수 있음
 point myPoint;
• 다음은 상수 형과 배열에 typedef 키워드를 이용하는 예
 typedef const float CFLOAT;
 typedef float point2[2];
2009-1학기
컴퓨터게임(DirectX)
43

변수 접두어
 static –셰이더 외부에서 변수에 접근할 수 없음을 지정함. 다
른 말로 하면 셰이더 내의 로컬 변수로 이용
• static int x=5;
• 함수가 실행될 때 한번만 초기화되며 나머지 함수가 호출
되는 동안 값을 유지한다.
 uniform –변수가 셰이더 외부, 예를 들어 C++ 애플리케이션
에서 초기화되어 셰이더에 입력됨을 의미
 extern –셰이더 외부에서 변수에 접근할 수 있음을 의미. 전
역 변수만이 extern 키워드를 가짐
 shared –이펙트 프레임웍(19장에서 다루어짐)에게 변수가
다수의 효과에 공유될 것임을 알려줌. 전역 변수만이 shared
키워드를 가질 수 있음
2009-1학기
컴퓨터게임(DirectX)
44


2009-1학기
volatile –이펙트 프레임웍에게 변수가 자주 수정될 것임을 알
려줌. 전역변수만이 volatile 키워드를 가짐
const –C++에서와 같은 의미를 가짐. 즉, const 키워드를 가
진 변수는 상수이며 변경되지 않을 것임을 지정
• const float pi=3.14f;
컴퓨터게임(DirectX)
45
키워드, 문, 형 변환

키워드
• HLSL이 정의하는 키워드 목록
asm
bool
compile
const
decl
do
double
else
extern
false
float
for
half
if
in
inline
inout
int
matrix
out
pass
pixelshader
return
sampler
shared
static
string
struct
techniqu
texture
true
typedef
unform
vector
vertexshade
void
volatile
while
2009-1학기
컴퓨터게임(DirectX)
46
예약된 키워드
auto
break
const_cast continue
case
catch
char
class
default
delete
dynamic_cast
enum
explicit
friend
goto
long
mutable
namespace
new
operator
private
protected
public
register
reinterpret
_cast
short
signed
sizeof
static_cast
switch
template
this
throw
try
typename
union
unsigned
using
virtual
2009-1학기
컴퓨터게임(DirectX)
47
기본적인 프로그램 흐름
• HLSL의 선택, 반복, 일반 프로그램 흐름의 문은 C++의 문과 매
우 비슷
• Return 문:
 return (식);
• If와 If…Else 문:
 if(조건)
{
구문(들);
}
2009-1학기
컴퓨터게임(DirectX)
48
if(조건)
{
구문(들);
}
else
{
구문(들);
}
• for 문:
 for(초기;조건;증감)
{
구문(들);
}
2009-1학기
컴퓨터게임(DirectX)
49
• while문:
 while(조건)
{
구문(들);
}
• do…while문:
 do
{
구문(들);
}while(조건);
2009-1학기
컴퓨터게임(DirectX)
50
형 변환
• HLSL은 매우 유연한 형 변환 체제를 가지고 있음. HLSL의 형변환 구문
은 C 프로그래밍 언어의 구문과 동일
• 예를 들어, float을 matrix로 변환하고자 한다면 다음과 같은 코드를 이용
할 수 있음

2009-1학기
float f = 5.0f;
matrix m = (matrix)f;
컴퓨터게임(DirectX)
51
연산자
• HLSL의 연산자 체계는 C++과 매우 비슷. 다음은 HLSL의 연산
자 목록임
[]
.
>
<
<=
>=
!=
==
!
&&
++
?:
+
+=
-
-=
*
*=
/
/=
%
%=
++
-
=
()
,
2009-1학기
컴퓨터게임(DirectX)
52
• 연산자의 동작이 C++과 매우 비슷하기는 하지만 몇 가지 차이가 존재
 나머지(%) 연산자를 정수와 부동 소수점 형 모두에 이용할 수 있음.
단, 왼쪽과 오른쪽값이 같은 부호를 가져야 함
 HLSL 연산자의 상당수가 각 성분에 대해서 작동. 이것은 벡터와 행
렬이 언어에 내장되어 있고 이들 형이 여러 개의 성분을 가질 수 있
기 때문
• 성분 레벨에서 연산자를 이용할 수 있다는 것은 스칼라 형에 이
용하던 것과 동일한 연산자를 이용해 벡터/행렬 더하기, 벡터/
행렬 빼기, 벡터/행렬 동등 테스트 등을 수행할 수 있음을 의미
• vector u={1.0f, 0.0f, -3.0f, 1.0f);
vector v={-4.0f, 2.0f, 1.0f, 0.0f);
//대응하는 성분을 더함
vector sum=u+v; //sum={-3.0f, 2.0f, -2.0f, 1.0f)
2009-1학기
컴퓨터게임(DirectX)
53






2009-1학기
벡터의 증가는 각 성분의 증가로 나타냄
//증가전: sum={-3.0f, 2.0f, -2.0f, 1.0f)
sum++; //증가후: sum={-2.0f,3.0f, -1.0f, 2.0f)
벡터곱은 각 성분 단위로 수행
vector u={1.0f, 0.0f, -3.0f, 1.0f);
vector v={-4.0f, 2.0f, 1.0f, 0.0f);
//대응되는 성분끼리의 곱
vector sum=u*v;//product = (-4.0f, 0.0f, -3.0f, 0.0f)
비교연산자 또한 성분 단위로 수행하며 부울 형의 성분을 갖는
벡터나 행렬을 결과로 리턴. 다음은 bool벡터가 비교한 각 성
분의 결과를 포함
vector u={1.0f, 0.0f, -3.0f, 1.0f);
vector v={-4.0f, 0.0f, 1.0f, 1.0f);
vector b=(u==v); //b=(false, true, false, true)
컴퓨터게임(DirectX)
54
• 이항 연산에 따르는 변수 승급
 이항 연산에 있어 왼쪽과 오른쪽의 피연산자 크기가 다를 경우,
작은 크기를 가진 피연산자가 큰 크기를 가진 피연산자와 같은
크기가 되도록 승급(형 변환)됨.
 예를 들어, x가 float형이고 y가 float3형일 때, (x+y) 식을 수행한
다면 변수 x는 float3으로 승급되고 float3형의 값으로 식이 계산
됨.
 승급은 정의 형 변환으로 수행. 이 예에서 우리는 스칼라-벡터
형 변환을 수행하는 것이므로 승급된 후의 x는 스칼라-벡터 형
변환 정의에 따라 x=(x, x, x)가 됨. 형 변환이 정의되지 않은 경
우에는 승급 역시 정의되지 않음. 예를 들어, float2에서 float3으
로의 승급은 정의되지 않으므로 불가능
2009-1학기
컴퓨터게임(DirectX)
55


2009-1학기
이항 연산에 있어 왼쪽과 오른쪽의 피연산자가 형이 다를 경
우, 낮은 형 해상도를 가진 피연산자가 높은 형 해상도를 가
진 피연산자와 같은 해상도를 가지도록 승급(형 변환)됨.
예를 들어, x가 int형이고 y가 half형일 때, (x+y)식을 수행한
다면 변수 x는 half로 승급되고 half 형의 값으로 식이 계산
• 4바이트 정수형과 2바이트 부동소수점 수 형
컴퓨터게임(DirectX)
56
사용자 정의 함수
• HLSL의 함수들은 다음과 같은 특성을 가짐
 함수의 구문은 C++ 구문과 비슷
 인자는 항상 값으로 전달
 재귀는 지원되지 않음
 함수는 항상 인라인으로 쓰여짐
• 부가적인 키워드를 이용해 작성한 함수의 예
 bool foo(in const bool b, //입력 bool
out int r1, //출력 int
inout float r2) //입력/출력 float
{
if(b)
{
r1=5;
}
2009-1학기
컴퓨터게임(DirectX)
57
else
{
r1=1;
}
// r2는 inout으로 선언되었으므로 값 입력이나
//출력 양쪽을 이용할 수 있음
r2=r2*r2*r2;
return true;

2009-1학기
}
in, out, inout 키워드를 제외하고는 c++ 함수와 거의 동일함
컴퓨터게임(DirectX)
58
• in – 함수가 시작되기 전에 인수를 인자로 복사할 것임을 지정.
인자는 디폴트로 in이므로 직접 in을 지정할 필요는 없음. 다음의
두 함수 선언은 동일함
float square(in float x)
{
return x*x;
}
 다음은 직접 in을 지정하지 않은 선언임
 float square(float x)
{
return x*x;
}
2009-1학기
컴퓨터게임(DirectX)
59
• out




2009-1학기
함수가 리턴할 때 인자를 인수에 복사할 것임을 지정.
인자를 통해 값을 리턴하려는 경우에 유용.
HLSL은 참조를 통한 전달이나 포인터 전달을 지원하지 않으므로
out 키워드는 필수적이라 할 수 있음.
인자가 out으로 표시되었더라도 함수가 시작되기 전에 인수를 인자
에 복사하는 것은 아님. 다른 말로 하면, out 인자는 데이터 출력에
만 이용할 수 있음
컴퓨터게임(DirectX)
60
void square(in float x, out float y)
{
y=x*x;
}
 이 함수는 x를 통해 받은 수의 제곱을 y를 통해 리턴하였음

• inout – 인자가 in과 out 모두로 이용할 수 있음을 표기한다. 입
력과 출력 용도 모두에 인자를 이용하려는 경우 inout을 이용
 void square(inout float x)
{
x=x*x;
}
2009-1학기
컴퓨터게임(DirectX)
61
내장 함수들
• HLSL은 3D 그래픽에 유용한 내장 함수들을 풍부하게 제공. 다음의 표는
이들 함수의 일부를 요약
수정
2009-1학기
abs(x)
|x|를 리턴함
ceil(x)
x보다 작지 않은 가장 큰 정수
clamp(x, a, b)
[a, b] 범위로 x를 제한하고 그 결과를 리턴
cos(x)
x의 코사인을 리턴
cross(u, v)
uXv를 리턴
degrees(x)
라디안에서 각도로 x를 변환
determinant(M)
행렬식 det(M)을 리턴
distance(u, v)
포인트 u와 v사이의 거리 ||v-u||를 리턴
dot(u, v)
u·v를 리턴
floor(u, v, t)
X보다 크지 않은 가장 큰 정수
컴퓨터게임(DirectX)
62
length(v)
||v||를 리턴
lerp(u, v, t)
인자 t∈[0, 1]을 기반으로 u와 v사이를 선형적으로 보간
log(x)
ln(x)를 리턴
log10(x)
log10(x)를 리턴
log2(x)
log2(x)를 리턴
max(x, y)
x≥y일 경우 x를 리턴하고 그렇지 않으면 y를 리턴
min(x, y)
x≤y일 경우 x를 리턴하고 그렇지 않으면 y를 리턴
mul(M, N)
행렬 곱 MN을 리턴. 행렬 곱 MN이 반드시 정의될 수 있어야 함
normalize(v)
v/||v||를 리턴
pow(b, n)
bn을 리턴
radians(x)
각도에서 라디안으로 x를 변환
reflect(v, n)
주어진 입사 벡터 v와 표면 법선 n으로 반사 벡터를 계산
refract(v, n, eta)
주어진 입사 벡터 v와 표면 법선 n, 두 물체 굴절의 두 인덱스
비율 eta를 이용해 굴절 벡터를 계산
rsqrt(x)
1√x를 리턴
saturate(x)
clamp(x, 0.0, 1.0)을 리턴
2009-1학기
컴퓨터게임(DirectX)
63
sin(x)
x의 사인 값을 리턴
sincos(in x, out s, out c)
x의 사인 값과 코사인 값을 리턴
sqrt(x)
√x를 리턴
tan(x)
x의 탄젠트 값을 리턴
transpose(M)
전치 M을 리턴
2009-1학기
컴퓨터게임(DirectX)
64
• 대부분의 함수들은 내장된 형들과 작업할 수 있도록 오버로드 됨.
• 예를 들어, abs함수는 모든 스칼라 형에 의미가 있으므로 모든
스칼라 형에 대해 오버로드 되며,
• 외적은 3D벡터에 의미가 있으므로 모든 형(예, int, float, double
등의 3D 벡터)의 3D 벡터에 오버로드 됨.
• 반면에 선형 보간이나 lerp 함수들은 스칼라, 2D, 3D, 4D 벡터
등에 모두 의미가 있으므로 모든 형에 오버로드 됨
• 다음의 코드는 몇 가지 내장 함수의 이용 예를 보여줌
 float x=sin(1.0f); //1.0f 라디안의 사인
float y=sqrt(4.0f); //4의 제곱근
2009-1학기
vector u={1.0f, 2.0f, -3.0f, 0.0f};
vector v={3.0f, -1.0f, 0.0f, 2.0f};
float s=dot(u,v); //u와
v의 내적을 계산
컴퓨터게임(DirectX)
65
float3 i={1.0f, 0.0f, 0.0f};
float3 j={0.0f, 1.0f, 0.0f};
float3 k=cross(I,j); //I, j의 외적을 계산
matrix<float, 2, 2> M={1.0f, 2.0f, 3.0f, 4.0f);
matrix<float, 2, 2> transpose(M); //전치 계산
2009-1학기
컴퓨터게임(DirectX)
66
2009-1학기
컴퓨터게임(DirectX)
67
예제 프로그램
#include "d3dUtility.h"
IDirect3DDevice9* Device = 0;
const int Width = 640;
const int Height = 480;
IDirect3DVertexShader9* TransformShader = 0;
ID3DXConstantTable* TransformConstantTable = 0;
ID3DXMesh* Teapot = 0;
D3DXHANDLE TransformViewProjHandle = 0;
D3DXMATRIX ProjMatrix;
// Framework functions
2009-1학기
컴퓨터게임(DirectX)
68
bool Setup()
{
HRESULT hr = 0;
// Create geometry.
D3DXCreateTeapot(Device, &Teapot, 0);
// Compile shader.
ID3DXBuffer* shader
= 0;
ID3DXBuffer* errorBuffer = 0;
hr = D3DXCompileShaderFromFile(
"transform.txt",
0,
0,
"Main", // entry point function name
"vs_1_1",// shader version to compile to
2009-1학기
컴퓨터게임(DirectX)
69
D3DXSHADER_DEBUG,
&shader,
&errorBuffer,
&TransformConstantTable);
// output any error messages
if( errorBuffer )
{
::MessageBox(0, (char*)errorBuffer->GetBufferPointer(), 0,
0);
d3d::Release<ID3DXBuffer*>(errorBuffer);
}
2009-1학기
컴퓨터게임(DirectX)
70
if(FAILED(hr))
{
::MessageBox(0, "D3DXCreateEffectFromFile() - FAILED", 0, 0);
return false;
}
hr = Device->CreateVertexShader(
(DWORD*)shader->GetBufferPointer(),
&TransformShader);
if(FAILED(hr))
{
::MessageBox(0, "CreateVertexShader - FAILED", 0, 0);
return false;
}
2009-1학기
컴퓨터게임(DirectX)
71
d3d::Release<ID3DXBuffer*>(shader);
// Get Handles.
TransformViewProjHandle = TransformConstantTable>GetConstantByName(0, "ViewProjMatrix");
// Set shader constants:
TransformConstantTable->SetDefaults(Device);
// Set Projection Matrix.
D3DXMatrixPerspectiveFovLH(
&ProjMatrix, D3DX_PI * 0.25f,
(float)Width / (float)Height, 1.0f, 1000.0f);
// Set Misc. States.
Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
2009-1학기
컴퓨터게임(DirectX)
72
return true;
}
void Cleanup()
{
d3d::Release<ID3DXMesh*>(Teapot);
d3d::Release<IDirect3DVertexShader9*>(TransformShader);
d3d::Release<ID3DXConstantTable*>(TransformConstantTable);
}
bool Display(float timeDelta)
{
if( Device )
{
2009-1학기
컴퓨터게임(DirectX)
73
// Update the scene: Allow user to rotate around scene.
static float angle = (3.0f * D3DX_PI) / 2.0f;
static float height = 5.0f;
if( ::GetAsyncKeyState(VK_LEFT) & 0x8000f )
angle -= 0.5f * timeDelta;
if( ::GetAsyncKeyState(VK_RIGHT) & 0x8000f )
angle += 0.5f * timeDelta;
if( ::GetAsyncKeyState(VK_UP) & 0x8000f )
height += 5.0f * timeDelta;
if( ::GetAsyncKeyState(VK_DOWN) & 0x8000f )
height -= 5.0f * timeDelta;
2009-1학기
컴퓨터게임(DirectX)
74
D3DXVECTOR3 position( cosf(angle) * 10.0f, height, sinf(angle) *10.0f );
D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
D3DXMATRIX V;
D3DXMatrixLookAtLH(&V, &position, &target, &up);
// combine view and projection transformations
D3DXMATRIX ViewProj = V * ProjMatrix;
TransformConstantTable->SetMatrix(
Device,
TransformViewProjHandle,
&ViewProj);
// Render
Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
0xffffffff, 1.0f, 0);
2009-1학기
컴퓨터게임(DirectX)
75
Device->BeginScene();
Device->SetVertexShader(TransformShader);
Teapot->DrawSubset(0);
Device->EndScene();
Device->Present(0, 0, 0, 0);
}
return true;
}
// WndProc
2009-1학기
컴퓨터게임(DirectX)
76
LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM
wParam, LPARAM lParam)
{
switch( msg )
{
case WM_DESTROY:
::PostQuitMessage(0);
break;
case WM_KEYDOWN:
if( wParam == VK_ESCAPE )
::DestroyWindow(hwnd);
break;
}
return ::DefWindowProc(hwnd, msg, wParam, lParam);
}
2009-1학기
컴퓨터게임(DirectX)
77
// WinMain
int WINAPI WinMain(HINSTANCE hinstance,
HINSTANCE prevInstance,
PSTR cmdLine,
int showCmd)
{
if(!d3d::InitD3D(hinstance,
Width, Height, true, D3DDEVTYPE_HAL, &Device))
{
::MessageBox(0, "InitD3D() - FAILED", 0, 0);
return 0;
}
if(!Setup())
{
::MessageBox(0, "Setup() - FAILED", 0, 0);
return 0;
2009-1학기
컴퓨터게임(DirectX)
}
78
d3d::EnterMsgLoop( Display );
Cleanup();
Device->Release();
return 0;
}
2009-1학기
컴퓨터게임(DirectX)
79