| |
|
|
|
|
|
| GLSL 예제 : Texture(MultiTexture) - 3/3 원문 : http://www.lighthouse3d.com/opengl/glsl/index.php?textureMulti
멀티 텍스쳐링은 GLSL에서는 정말 쉽다. 해야할 것은 두개의 텍스쳐에 접근하는 일이 전부다. 그리고 이 장에서는 동일한 텍스쳐 좌표를 사용할 것이기 때문에 버텍스 쉐이더를 재작성하지 않고 이전 강좌의 것을 그대로 사용한다. 프레그먼트 쉐이더 또한 두개의 텍스쳐 색상을 추가하는 최소한의 변화만 있다.
varying vec3 lightDir,normal;
uniform sampler2D tex,l3d;
void main()
{
vec3 ct,cf;
vec4 texel;
float intensity,at,af;
intensity = max(dot(lightDir,normalize(normal)),0.0);
cf = intensity * (gl_FrontMaterial.diffuse).rgb +
gl_FrontMaterial.ambient.rgb;
af = gl_FrontMaterial.diffuse.a;
texel = texture2D(tex,gl_TexCoord[0].st)+
texture2D(l3d,gl_TexCoord[0].st);
ct = texel.rgb;
at = texel.a;
gl_FragColor = vec4(ct * cf, at * af);
} 그리고 이제, 약간 다른 특별한 것을 해보자: Glow in the Drak Effect. 이 특별한 효과는 두번째 텍스쳐를 어둠속에서 타오르는듯하게 보이는 것이다. 예를들어, 완전이 밝아졌다가 어두워지는 듯한 효과.
두 단계로 최종 색상을 다시 계산해야 하는데, 먼저 첫번째 텍스쳐를 프레그먼트 색상으로 조정된 상태의 색상을 계산하고, 이후에 두번째 텍스쳐 유닛을 강도에 기반해서 추가하는 것이다.
intensity가 0이라면, 두번째 텍스쳐가 전체적으로 완전하게 표시된다. 반대로 intensity가 1이라면, 두번째 텍스쳐를 10% 정도만 표시되도록 한다. 이런 표시를 위해 smoothStep라는 함수를 통해 구현할 것이다. 이 함수의 시그니쳐는 다음과 같다.
genType smoothStep(genType edge0, genType edge1, genType x); 만약 x<=edge0이면 결과는 0이고, x>=edge1이면 1 그리고 edge0< x <edge1이면 Hermit 보간 연산이 수행된다. 우리의 경우 다음 함수를 호출한다.
coef = smoothStep(1.0, 0.2, intensity); 다음은 프레그먼트 쉐이더 코드이다.
varying vec3 lightDir,normal;
uniform sampler2D tex,l3d;
void main()
{
vec3 ct,cf,c;
vec4 texel;
float intensity,at,af,a;
intensity = max(dot(lightDir,normalize(normal)),0.0);
cf = intensity * (gl_FrontMaterial.diffuse).rgb +
gl_FrontMaterial.ambient.rgb;
af = gl_FrontMaterial.diffuse.a;
texel = texture2D(tex,gl_TexCoord[0].st);
ct = texel.rgb;
at = texel.a;
c = cf * ct;
a = af * at;
float coef = smoothstep(1.0,0.2,intensity);
c += coef * vec3(texture2D(l3d,gl_TexCoord[0].st));
gl_FragColor = vec4(c, a);
}
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/10/13 04:32
2007/10/13 04:32
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/332 |
|
|
|
|
|
|
|
| GLSL 예제 : Texture(Combine Texture + Fragment) - 2/3 원문 : http://www.lighthouse3d.com/opengl/glsl/index.php?dirlightpix
OpenGL은 다양한 방법으로 텍스쳐 색상과 프레그먼트 생상을 혼합하는 방법을 제공한다. 바로 아래의 내용은 RGBA 모드를 위한 몇가지 모드이다.GL_REPLACE C = Ct A = At
GL_MODULATE C = Ct*Cf A = At*Af
GL_DECAL C = Cf * (1 - At) + Ct * At A = Af Ct와 At는 텍스쳐의 색상과 알파값이고, Cf와 Af는 프레그먼트의 색상과 알파값이며 C와 A는 최종적인 색상과 알파값이다.
이전 섹션에서 제공되었던 예제는 GL_REPLACE의 경우의 예였다. 여기서는 정육면체에 GL_MODULATE의 내용을 구현해보자. 쉐이더들은 하얀색의 Diffuse Directional Light를 가지고 Diffuse와 Ambient 요소만을 계산한다. 재질에 대한 완전한 정의는 Lighting(광원) 섹션을 살펴보길 바란다.
빛을 사용하기 때문에, 그래서 법선벡터에 대해, 버텍스 쉐이더는 몇가지 작업을 해야한다. 주로 법선벡터를 카메라 좌표계로 변환하고 정규화하는 일이며 빛의 방향에 대해서도 정규화를 해야한다. (빛의 방향은 이미 OpenGL에 의해서 카메라 좌표계로 변환되어졌다). 지금 단계에서 버텍스 쉐이더는 다음과 같다.varying vec3 lightDir,normal;
void main()
{
normal = normalize(gl_NormalMatrix * gl_Normal);
lightDir = normalize(vec3(gl_LightSource[0].position));
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = ftransform();
} 프레그먼트 쉐이더에서, 프레그먼트의 색상과 알파값은 각각 cf와 af에 계산되어진다. 위에서 언급한 GL_MODULATE 공식을 계산하는 나머지 쉐이더 코드는 다음과 같다.varying vec3 lightDir,normal;
uniform sampler2D tex;
void main()
{
vec3 ct,cf;
vec4 texel;
float intensity,at,af;
intensity = max(dot(lightDir,normalize(normal)),0.0);
cf = intensity * (gl_FrontMaterial.diffuse).rgb +
gl_FrontMaterial.ambient.rgb;
af = gl_FrontMaterial.diffuse.a;
texel = texture2D(tex,gl_TexCoord[0].st);
ct = texel.rgb;
at = texel.a;
gl_FragColor = vec4(ct * cf, at * af);
}
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/10/12 20:08
2007/10/12 20:08
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/331 |
|
|
|
|
|
|
|
| GLSL 예제 : Texture(Simple Texture) - 1/3 원문 : http://www.lighthouse3d.com/opengl/glsl/index.php?dirlightpix
GLSL에서 텍스쳐링 연산을 하기 위해서, 버텍스에 대한 텍스쳐 좌표에 접근해야 한다. GLSL은 각 텍스쳐 유닛 각각에 대한 Attribute 변수들을 제공한다.
attribute vec4 gl_MultiTexCoord0;
attribute vec4 gl_MultiTexCoord1;
attribute vec4 gl_MultiTexCoord2;
attribute vec4 gl_MultiTexCoord3;
attribute vec4 gl_MultiTexCoord4;
attribute vec4 gl_MultiTexCoord5;
attribute vec4 gl_MultiTexCoord6;
attribute vec4 gl_MultiTexCoord7; 또한 GLSL은 uniform 변수 배열 형태로 각 텍스쳐에 대한 텍스쳐 행렬에 접근할 수 있다.
uniform mat4 gl_TextureMatrix[gl_MaxTextureCoords]; 버텍스 쉐이더는 OpenGL 어플리케이션에서 지정한 텍스쳐 좌표 등을 얻을 수 있다. 버텍스에 대한 텍스쳐 좌표를 계산을 해야하고, 계산후에 미리 정의된 varying 변수인 gl_TexCoord[i] 변수에 계산된 텍스쳐 좌표를 저장하는데, 여기서 i는 텍스쳐 유닛에 대한 인덱스이다.
텍스쳐에 대한 텍스쳐 좌표를 설정하는 간단한 버텍스 쉐이더는 아래와 같다. 사용하는 텍스쳐 유닛은 0이다.
void main() {
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = ftransform();
} 만약 텍스쳐 행렬을 사용하길 원한다면 아래와 같다.
void main() {
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
gl_Position = ftransform();
} gl_TexCoord가 Varying 변수라고 언급했었는데, 예를들어서 이 gl_TexCoord는 프레그먼트 쉐이더에서 계산된 텍스쳐 좌표를 접근하는데 사용될 수 있다.
텍스쳐 값에 접근하기 위해서, 프레그먼트 쉐이더에서는 특별한 타입의 변수을 선언할 필요가 있다. 2D 텍스쳐에 대해서는 다음과 같다.
uniform sampler2D tex; 1D와 3D 텍스쳐에 대한 데이터 타입도 가능한데, 일반적인 포멧은 sampler_i_D이며 _i_에 해당하는 것이 텍스쳐의 차원이다. 사용하고자 하는 텍스쳐 유닛을 포함하는 tex 변수를 선언한다. 텍셀(텍스쳐 이미지의 화소 색상)을 제공하는 함수는 texture2D이다. 이 함수는 sampler2D와 텍스쳐의 좌표를 인자로 받으며 텍셀값을 반환한다. 아래에 texture2D 함수에 대한 시그니쳐가 있다.
vec4 texture2D(sampler2D, vec2); 반환값은 OpenGL 어플리케이션에서 설정된 모든 텍스쳐 설정값을 고려해서 계산되어진 값인데, 예를들어서 필터링, 밉맵, 클램프 등이다. 프레그먼트 쉐이더에서는 아래처럼 작성할 수 있다.
uniform sampler2D tex;
void main()
{
vec4 color = texture2D(tex,gl_TexCoord[0].st);
gl_FragColor = color;
} gl_TexCoord에 접근할때 선택자 st의 사용에 주의하라. GLSL의 데이터 타입과 변수에 관해 앞서 언급했던것처럼, 텍스쳐 좌표에 접근할때는 선택자는 s,t,p,q가 될 수 있다. r은 rgb 선택자들과 충돌하기 때문에 사용하지 않는다.
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/10/11 23:30
2007/10/11 23:30
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/330 |
|
|
|
|
|
|
|
| GLSL 예제 : Lighting(Spot Light Per Pixel) - 6/6 원문 : http://www.lighthouse3d.com/opengl/glsl/index.php?dirlightpix
이 강좌는 이전 강좌에서 제공되는 코드의 90% 이상의 내용에 기반하고 있다. Point Light와 비교해 Spot Light에서 유일하게 차이점은, Point Light는 모든 방향으로 빛을 방사하는데 반해서 Spot Light는 제한 영역에만 빛을 받는다는 점이다.
OpenGL 어플리케이션의 관점에서 다음과 같은 차이들이 있다.
- Spot Light는 방향을 가지고 있으며(spotDirection) 이 방향은 Spot Light의 Cone의 축이다.
- Cone의 각도가 있다. GLSL은 어플리케이션에서 지정되어진 것으로써와 spotCosCutoff라는 cosine 변수로써, 이둘 모두를 제공한다.
- 마지막으로 감쇄 비율이 있다(spotExponent). 예를들어서, 빛의 강도가 Cone의 원 모양의 밑바닥의 중심점으로부터 어떤식으로 감소하는지를 측정하는 것이다.
버텍스 쉐이더는 이전 강좌의 Point Light와 동일하고 프레그먼트 쉐이더에서 몇가지 변경이 있다. Diffuse, Specular 그리고 Ambient 요소는 오직 빛의 Cone의 안쪽에서 프레그먼트에만 영향을 미친다. 그러므로 우리가 먼저 해야할 첫번째것은 Cone 안쪽의 프레그먼트의 검사이다.
버텍스 벡터에서 빛 사이의 Cosine 각도와 Spot 방향은 반드시 spotCosCutoff보다 넓어야 한다. 만약 그렇지 않으면, 프레그먼트는 Cone의 바깓에 있고 단지 전역 Ambient 요소의 광원 효과만 받게 된다.
...
n = normalize(normal);
/* compute the dot product between normal and ldir */
NdotL = max(dot(n,normalize(lightDir)),0.0);
if (NdotL > 0.0) {
spotEffect = dot(normalize(gl_LightSource[0].spotDirection),
normalize(-lightDir));
if (spotEffect > gl_LightSource[0].spotCosCutoff) {
/* compute the illumination in here */
}
}
gl_FragColor = ... 조도의 계산은 Point Light의 경우에 매우 많이 비슷한데, 유일한 차이점은 감쇄값은 아래의 공식의 Spot Light의 효과(spotEffect)와 곱해져야 한다는 것이다.
spotDirection은 빛의 상태로부터 얻어진 값이며, lightDir은 광원으로부터 버텍스까지의 벡터이며, spotExp는 Spot의 감쇄비율이다. 이것 역시 OpenGL의 상태로부터 가져오며, 빛들의 강도가 Cone의 중심으로부터 Cone의 경계까지 어떻게 점점 감쇄하는지를 조정한다. 값이 크면 클수록 더 빨리 빛의 강도가 감쇄하며, Zero(0)의 의미는 빛의 Cone 안에서 일정한 빛의 강도를 의미한다.
spotEffect = pow(spotEffect, gl_LightSource[0].spotExponent);
att = spotEffect / (gl_LightSource[0].constantAttenuation +
gl_LightSource[0].linearAttenuation * dist +
gl_LightSource[0].quadraticAttenuation * dist * dist);
color += att * (diffuse * NdotL + ambient);
halfV = normalize(halfVector);
NdotHV = max(dot(n,halfV),0.0);
color += att * gl_FrontMaterial.specular *
gl_LightSource[0].specular *
pow(NdotHV,gl_FrontMaterial.shininess); 아래의 이미지는 OpenGL의 고정기능의 결과와 우리의 Spot Light Per Pixel에 대한 결과이다. OpenGL의 고정기능은 버텍스에 대해서 빛의 효과를 계산하는데 반해 우리의 Spot Light는 픽셀(프레그먼트)에 대해 빛의 효과를 계산한다.
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/10/11 01:07
2007/10/11 01:07
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/329 |
|
|
|
|
|
|
|
| GLSL 예제 : Lighting(Point Light Per Pixel) - 5/6 원문 : http://www.lighthouse3d.com/opengl/glsl/index.php?dirlightpix
이 튜터리얼은 Directional Lights의 코드의 99% 상당 부분에 기반하고 있다. 이 튜토리얼은 Directional Light와 Point Light의 차이점에 대해 기반한다. Directional Light는 무한이 멀리 있다고 가정되므로 빛에 대한 광선이 모든 물체에 도달할때 평행하다. 반면에, Point Light는 위치를 가지고 있으며 모든 방향에서 광선을 보낸다. 더욱이 Point Light에서는, 버텍스와의 거리가 멀어질 수 록 빛의 강도가 감쇄한다.
OpenGL 어플리케이션의 관점으로부터, Directional Light와 Point Light 사이에는 두가지 차이점이 있다.
- 광원의 위치 필드중 w 요소 : Directional Light에서는 이 값은 0이지만 Point Light에서는 1이다.
- 빛의 감쇄는 세개의 계수에 기반한다 : 상수항, 1차항, 2차항
계산식 관점에서 이들 차이를 살펴봐야한다. Directional Light의 경우, 빛의 광선의 방향은 모든 버텍스에 대해서 일정하지만, Point Light의 경우, 빛의 위치에서 시작해서 각 버텍스까지의 벡터이다. 그러므로 버텍스 쉐이더에서 변경해야할 것은 빛의 방향을 계산하는 것이다. 빛의 감쇄는 OpenGL에서 다음 공식에 기반하여 계산된다.
k0은 상수항 감쇄이고, k1은 1차항 감쇄, k2는 2차항감쇄이며 d는 빛의 위치와 버텍스 사이의 거리이다.
주의할것은, 빛의 감쇄 모델은 거리에 따른 선형회귀가 아니라는 점이다. 그래서 버텍스에 대해 감쇄를 계산할 수 없으며 프레그먼트 쉐이더에서 보간된 값을 사용할 수 없다. 그러나 우리는 버텍스 쉐이더에서 거리를 계산할 수 있고 프레그먼트 쉐이더에서 보간된 거리를 사용해 감쇄를 계산할 수 있다.
Point Light에 대한 색상에 대한 공식은 다음과 같다.
위의 공식을 보면, ambient항은 반드시 2개로 나눠야 한다: 광원 모델 Ambient 설정을 이용한 전역 Ambient 항과 빛에 대한 일반 Ambient 항. 버텍스 쉐이더는 정확하게 Ambient 항의 계산을 구분해야 한다. 아래는 새로운 버텍스 쉐이더에 대한 코드이다.
varying vec4 diffuse,ambientGlobal,ambient;
varying vec3 normal,lightDir,halfVector;
varying float dist;
void main()
{
vec4 ecPos;
vec3 aux;
normal = normalize(gl_NormalMatrix * gl_Normal);
/* these are the new lines of code to compute the light's direction */
ecPos = gl_ModelViewMatrix * gl_Vertex;
aux = vec3(gl_LightSource[0].position-ecPos);
lightDir = normalize(aux);
dist = length(aux);
halfVector = normalize(gl_LightSource[0].halfVector.xyz);
/* Compute the diffuse, ambient and globalAmbient terms */
diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
/* The ambient terms have been separated since one of them */
/* suffers attenuation */
ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;
ambientGlobal = gl_LightModel.ambient * gl_FrontMaterial.ambient;
gl_Position = ftransform();
} 프래그먼트 쉐이더는 감쇄를 계산해야 한다. 해석된 빛의 방향을 정규화도 해야해야 하는데, 방향은 모든 버텍스에 대해서 다르기 때문이다.
varying vec4 diffuse,ambientGlobal, ambient;
varying vec3 normal,lightDir,halfVector;
varying float dist;
void main()
{
vec3 n,halfV,viewV,ldir;
float NdotL,NdotHV;
vec4 color = ambientGlobal;
float att;
/* a fragment shader can't write a varying variable, hence we need
a new variable to store the normalized interpolated normal */
n = normalize(normal);
/* compute the dot product between normal and normalized lightdir */
NdotL = max(dot(n,normalize(lightDir)),0.0);
if (NdotL > 0.0) {
att = 1.0 / (gl_LightSource[0].constantAttenuation +
gl_LightSource[0].linearAttenuation * dist +
gl_LightSource[0].quadraticAttenuation * dist * dist);
color += att * (diffuse * NdotL + ambient);
halfV = normalize(halfVector);
NdotHV = max(dot(n,halfV),0.0);
color += att * gl_FrontMaterial.specular *
gl_LightSource[0].specular *
pow(NdotHV,gl_FrontMaterial.shininess);
}
gl_FragColor = color;
} 아래의 이미지는 Point Light와 OpenGL의 고정 기능에 의해 계산된 빛에 대한 차이를 보여준다. 하나는 버텍스에 대한 광원이고 다른 하나는 이 튜터리얼의 쉐이더를 이용한 픽셀에 대한 광원이다.
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/10/10 23:48
2007/10/10 23:48
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/328 |
|
|
|
|
|
|
|
| GLSL 예제 : Lighting(Directional Light Per Pixel) - 3/6 원문 : http://www.lighthouse3d.com/opengl/glsl/index.php?dirlightpix
이 션섹에서는 이전 셕센에서의 쉐이더를 Directional Light를 픽셀 마다 계산하도록 수정할 것이다.
먼저 버텍스 당 우리가 받는 정보를 살펴보면, ...
법선벡터를 카메라 공간 좌표계로 변환하고 정규화해야한다. 또한 이미 카메라 공간 좌표계인 Half 벡터와 빛의 방향 벡터 역시 정규화해야 한다. 이들 정규화된 벡터는 보간되어질 것이고 프레그먼트 쉐이더로 보내지는데, 이를 위해서 정규화된 벡터를 유지하기 위해서 varying 변수를 선언할 필요가 있다.
버텍스 쉐이더에서는 광원설정값과 재질을 조합하는 몇가지 연산을 수행할 수 있다.
아래는 버텍스 쉐이더의 코드이다.
varying vec4 diffuse,ambient;
varying vec3 normal,lightDir,halfVector;
void main()
{
/* first transform the normal into eye space and
normalize the result */
normal = normalize(gl_NormalMatrix * gl_Normal);
/* now normalize the light's direction. Note that
according to the OpenGL specification, the light
is stored in eye space. Also since we're talking about
a directional light, the position field is actually direction */
lightDir = normalize(vec3(gl_LightSource[0].position));
/* Normalize the halfVector to pass it to the fragment shader */
halfVector = normalize(gl_LightSource[0].halfVector.xyz);
/* Compute the diffuse, ambient and globalAmbient terms */
diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;
ambient += gl_LightModel.ambient * gl_FrontMaterial.ambient;
gl_Position = ftransform();
} 이제 프레그먼트 쉐이더에 대해서 살펴보자. 동일한 Varying 변수가 선언되어야 한다. 법선벡터를 다시 정규화해야한다. 하지만 빛의 방향벡터는 다시 정규화할 필요가 없다. 우리는 Directional Light에 대해 이야기 하고 있으므로 이 마지막 벡터는 모든 버텍스에 공통이다(쌩뚱맞은 말같은데....... =_=). 두개의 동일한 벡터 사이의 보간에 대한 결과는 같은 벡터이므로, 다시 정규화할 필요가 없는 것이다. 다음으로 우리는 보간되고 정규화된 법선벡터와 빛의 방향 벡터를 내적계산한다. 아래가 여기서 언급한 프레그먼트 쉐이더에 대한 시작 부분에 대한 코드이다.
varying vec4 diffuse,ambient;
varying vec3 normal,lightDir,halfVector;
void main()
{
vec3 n,halfV;
float NdotL,NdotHV;
/* The ambient term will always be present */
vec4 color = ambient;
/* a fragment shader can't write a varying variable, hence we need
a new variable to store the normalized interpolated normal */
n = normalize(normal);
/* compute the dot product between normal and ldir */
NdotL = max(dot(n,lightDir),0.0);
....
} 만약 NdotL이 0보다 크다면, Diffuse 요소를 계산해야 하는데, 버텍스 쉐이더로부터 받은 Diffuse 설정값은 내적값으로 곱해진다. Specular 요소도 반드시 계산해야 한다. Specular 요소를 계산하기 위해서는 먼저 버텍스 쉐이더로부터 받은 halfVector를 정규화해야하고, halfVector와 normal 간의 내적 계산을 한다.
....
if (NdotL > 0.0) {
color += diffuse * NdotL;
halfV = normalize(halfVector);
NdotHV = max(dot(n,halfV),0.0);
color += gl_FrontMaterial.specular *
gl_LightSource[0].specular *
pow(NdotHV, gl_FrontMaterial.shininess);
}
gl_FragColor = color;
}
다음 이미지는 Per Pixel과 Per Vertex 광원에 대한 결과화면이다.
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/10/10 10:20
2007/10/10 10:20
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/326 |
|
|
|
|
|
|
|
| GLSL 예제 : Lighting(Directional Lights 2) - 3/6
원문 : http://www.lighthouse3d.com/opengl/glsl/index.php?ogldir2
OpenGL의 Directional 빛에 대한 Specular 요소에 대한 시간이다. 사용한 광원공식 모델은 Blinn-Phong 모델로써, 이 모델은 Phong 모델을 간략화한 것이다.
Phong 모델은 Specular 요소는 빛의 반사벡터와 시선벡터 사이의 cosine에 비례함을 나타낸다.
L은 광원에서 버텍스까지로 형성된 벡터이다. N은 법선벡터이고 Eye는 버텍스로부터 눈(카메라)까지의 벡터이다. R은 벡터 L이 표면에 반사되어진 벡터다. Specular 요소는 각 alpha의 consine에 비례한다.
만약 눈(카메라) 벡터(시선벡터)가 반사 벡터와 일치한다면, 최대의 강도를 갖는 Specular를 얻을것이다. 시선벡터가 반사벡터로부터 갈라지면, Specular 강도는 쇠퇴한다. 쇠퇴정도는 Shininess 값으로 조절할 수 있다. 더 높은 Shininess 값은 더 빠르게 Specular를 감퇴시킨다. 이것의 의미는 높은 Shininess를 가진 것이 더 낮은 Shininess를 가진것보다 밝기스팟의 크기가 작아짐을 의미한다. OpenGL에서 Shininess는 0~128 사이의 값이고 밝기스팟의 크기를 조절하는 값이라고 생각하면 쉽다.
반사 벡터에 대한 공식은 다음과 같다.
그리고 Phong 모델식을 사용하는 OpenGL에서 Specular 요소는 다음과 같다.
지수 s가 Shininess 값이고 Ls는 빛의 Specular 강도이며, Ms는 재질에 대한 Specular 계수이다.
Blinn은 좀더 빠르고 이해하기 쉬운 Phong 모델을 간략화해서 제안하였는데, 그것이 바로 Blinn-Phong 모델이며 Half-Vector에 기반한다. Half-Vector는 시선벡터와 광원벡터 사이의 각을 반으로 하여 고려한다는 것으로 다음 그림을 보면 이해가 쉬울것이다.
Specular 요소의 강도는 법선벡터와 H 벡터 사이의 Cosine 값에 의존한다. Half-Vector에 대한 공식은 반사벡터에 대한 것보다 훨씬 간단하다.
그리고 Blinn-Phong 모델을 사용하는 OpenGL에서의 Specualr 요소 값은 다음과 같다.
이것이 실제 그래픽스 하드웨어의 고정기능에서 일반적으로 사용되는 식이다. 우리는 지금 OpenGL의 Directional 빛을 모방하길 원하므로, 쉐이더에서 이 마지막 공식을 사용한다. 여기에 좋은 소식이 있는데, OpenGL은 우리를 위해 Half-Vector를 계산해 준다는 것이다! 아래 코드를 살펴보길 바란다.
/* compute the specular term if NdotL is larger than zero */
if (NdotL > 0.0) {
// normalize the half-vector, and then compute the
// cosine (dot product) with the normal
NdotHV = max(dot(normal, gl_LightSource[0].halfVector.xyz),0.0);
specular = gl_FrontMaterial.specular * gl_LightSource[0].specular *
pow(NdotHV,gl_FrontMaterial.shininess);
}
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/10/06 23:39
2007/10/06 23:39
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/322 |
|
|
|
|
|
|
|
| GLSL 예제 : Lighting(Directional Lights 1) - 2/6 원본 : http://www.lighthouse3d.com/opengl/glsl/index.php?ogldir1
OpenGL Programming Guide(일명: Red Book)라는 책에 The Mathematics of Lights 챕터에 본 내용에 나오는 공식이 있다.
먼저 Diffuse 용어부터 시작해보자. OpenGL에서 Diffuse 빛은 관찰자의 위치에 상관없이 일정한 빛의 강도이다.Diffuse는 재질의 Diffuse 반사 계수뿐만이 아니라 빛의 Diffuse 강도에 대해 비례한다. 강도는 빛의 방향과 표면의 법선벡터 사이의 각도에 비례한다.
다음 공식은 OpenGL에서 Diffuse를 계산하는데 사용되는 공식이다.
위의 식에서, I는 반사강도, Ld는 빛의 Diffuse 색상(gl_LightSource[0].diffuse), 그리고 Md는 재질의 Diffuse 계수(gl_FrontMaterial.diffuse)이다.
위의 식은 Lambertian 반사식으로 알려져있다. Lambert의 Cosine 법칙은 평면에 대한 표면의 Diffuse 밝기는 시선과 표면의 법선벡터로 형성되어진 Cosine 각에 비례함을 나타낸다. 이 법칙은 200년전의 이론이다. (Johann Heinrich Lambert, 1728~1777)
버텍스 쉐이더에서 이 공식을 구현하기 위해서는 빛의 속성을 사용할 것이고, 주로 빛의 위치와 Diffuse 강도에 대한 속성이다. 또한 재질에 대한 Diffuse 설정 속성도 이용할 것이다. 따라서 버텍스 쉐이더에서는 OpenGL에서 했던 것처럼 빛을 설정하면된다. 그러나 주의할 것은 고정기능을 사용하지 않을 것이기때문에, 빛을 활성화 시킬 필요는 없다.
Cosine을 계산할 필요가 있으므로, 먼저 우리는 법선벡터와 빛의 방향 벡터(gl_LightSource[0].position)를 정규화할 필요가 있다. 그리고 Cosine 값을 얻기 위해서 내적을 사용할 것이다. Directional Lights에 대해서는, OpenGL이 빛의 방향을 위의 그림에서 보는 것처럼 반대로 하고 있음을 알수 있다.
OpenGL은 빛의 방향을 Eye 공간좌표계로 저장하고 있다; 그러므로 우리는 내적을 계산하기 위해서 법선벡터를 Eye 공간좌표계로 변환해야한다. 법선벡터를 Eye 공간좌표계로 변환하기 위해서는, 미리 정의된 Uniform 변수인 mat3 gl_NormalMatrix를 사용해야할 것이다. 이 행렬은 모델뷰행렬로부터 3x3 좌상단매트릭스의 역전치행렬이다.
다음 버텍스 쉐이더는 위에서 언급한 것들을 위한 버텍스 쉐이더 코드이다.
void main() {
vec3 normal, lightDir;
vec4 diffuse;
float NdotL;
/* 먼저 법선벡터를 Eye 공간좌표계로 변환하고 정규화한다 */
normal = normalize(gl_NormalMatrix * gl_Normal);
/* 이제 빛의 방향 벡터를 정규화한다. OpenGL의 소펙을 보면, 빛은 Eye 공간좌표계이다.
또한 우리가 지금 Directional Light에 대해 이야기하고 있으므로, 빛의 위치 필드는
실제 빛의 방향이다. */
lightDir = normalize(vec3(gl_LightSource[0].position));
/* 법선벡터와 빛의 방향 사이의 각도에 대한 Cos 값을 계산한다. 빛은 Directional이므로
모든 좌표에 대해서 빛의 방향은 일정하다. 이 두벡터는 정규화되었으므로 내적을 구하면된다.
결과는 0~1 범위 사이로 맞춘다. */
NdotL = max(dot(normal, lightDir), 0.0);
/* Diffuse를 계산한다. */
diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
gl_FrontColor = NdotL * diffuse;
gl_Position = ftransform();
} 이제, 프레그먼트 쉐이더에서 해야할 것이 남았는데, gl_Color Varying 변수를 사용해서 프레그먼트의 색상을 설정해보자.
void main()
{
gl_FragColor = gl_Color;
} 다음 이미지가 주전자 모델에 대해 적용된 결과이다. 주전자의 밑바닦을 보면 매우 어둡게 표현이 되었음을 주목하기 바란다. 이것은 OpenGL에서 Ambient 빛을 아직 적용하지 않았기 때문이다.
Ambient 빛을 통합시키는 것은 어렵지 않다. 아래의 식은 Ambient 빛에 대한 공식이다.
버텍스 쉐이더에서 Ambient를 계산하기 위해서 몇가지 코드를 추가할 필요가 있다.
void main()
{
vec3 normal, lightDir;
vec4 diffuse, ambient, globalAmbient;
float NdotL;
normal = normalize(gl_NormalMatrix * gl_Normal);
lightDir = normalize(vec3(gl_LightSource[0].position));
NdotL = max(dot(normal, lightDir), 0.0);
diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
/* Compute the ambient and globalAmbient terms */
ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;
globalAmbient = gl_LightModel.ambient * gl_FrontMaterial.ambient;
gl_FrontColor = NdotL * diffuse + globalAmbient + ambient;
gl_Position = ftransform();
} 다음 이미지가 최종 결과이다. Ambient 빛을 추가하자 색상을 씻어내는 듯(밝게하다)하고 있다. 결국 효과가 별로라는 얘기이다.
이제 다음 색선에서 Specular 요소에 대해서 살펴보겠다.
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/10/05 23:58
2007/10/05 23:58
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/317 |
|
|
|
|
|
|
|
GLSL 예제 : Lighting(광원) - 1/6
원문 : http://www.lighthouse3d.com/opengl/glsl/index.php?lights
OpenGL에는 세가지 종류의 빛이 있습니다: Directional, Point, Spotlight. 이 장에서는 Directional 광원을 구현하는 것으로 시작해 보겠다. 먼저 GLSL을 이용해서 OpenGL의 광원효과를 모방해 보겠다.
우리는 Ambient 빛으로 시작해서 GLSL을 점진적으로 발전시켜 Specular 빛까지 구현해보겠다.
다음으로 좀더 나은 결과를 제공하는 Lighting Per Pixel을 구현해보겠다.
그리고 이 다음으로는, Point와 Spot Lighting Per Pixel을 구현해보겠다. 빛에 대한 총 6개의 장은 Directional Lights에 관련된 장에서의 코드의 내용을 공통적으로 사용할 것이다.
툰쉐이더에서 언급했듯이, GLSL은 광원 설정에 대한 데이터를 포함하는 OpenGL 상태값에 접근할 수 있다. 이 데이터는 광원 설정에 대한 세세한 내용을 담고 있는 구조체형식의 전역변수이다.
struct gl_LightSourceParameters {
vec4 ambient;
vec4 diffuse;
vec4 specular;
vec4 position;
vec4 halfVector;
vec3 spotDirection;
float spotExponent;
float spotCutoff; // (range: [0.0, 90.0], 180.0)
float spotCosCutoff; // (range: [1.0, 0.0], -1.0)
float constantAttenuation;
float linearAttenuation;
float quadraticAttenuation;
};
uniform gl_LightSourceParameters gl_LightSource[gl_MaxLights];
struct gl_LightModelParameters {
vec4 ambient;
};
uniform gl_LightModelParameters gl_LightModel; 재질 속성도 역시 GLSL에서 접근할 수 있다.
struct gl_MaterialParameters {
vec4 emission;
vec4 ambient;
vec4 diffuse;
vec4 specular;
float shiness;
};
uniform gl_MaterialParameters gl_FrontMaterial;
uniform gl_MaterialParameters gl_BackMaterial; 광원과 재질에 대한 이 파라메터들의 대부분의 사용은 OpenGL 어플리케이션에서 사용하는 것과 유사하다. 이제 우리는 이들 속성을 사용해서 Directional 광원을 구현해 볼 것이다.
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/10/05 23:44
2007/10/05 23:44
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/315 |
|
|
|
|
|
|
|
| GLSL 예제 - 툰쉐이딩 마지막 장.. (4/4)
원본 : http://www.lighthouse3d.com/opengl/glsl/index.php?toon3
툰쉐이딩을 끝내기 전에 한가지 더 살펴보자 : lightDir 변수를 사용하는 대신에 OpenGL 빛을 사용한 것. OpenGL에서 빛을 하나 정의하고 이 빛의 방향을 쉐이더에서 사용하는 방법이다. 주의: glEnable을 사용해서 빛을 활성화할 필요가 없는데, OpenGL에서 이 빛을 실제로 사용하지는 않을 것이기 때문이다.
우리는 OpenGL에서 첫번째 빛(GL_LIGHT0)이 Directional 빛이라고 가정하겠다.
GLSL은 OpenGL 상태의 일부에 접근할 수 있는데, 바로 빛과 같은 속성에 접근할 수 있다. GLSL은 빛의 속성에 대한 C언어 형식의 구조체를 정의하고 있는데 각 빛에 대한 속성을 정의하기 위한 배열로 존재한다. struct gl_LightSourceParameters {
vec4 ambient;
vec4 diffuse;
vec4 specular;
vec4 position;
};
uniform gl_LightSourceParamters gl_LightSource[gl_MaxLights]; 위의 구조체와 변수를 이용해서 버텍스 쉐이더에서 빛의 방향을 얻어낼 수 있는데, 구조체의 필드중에 position을 이용하면 된다. 여기서 다시 우리는 OpenGL 어플리케이션에서 빛의 방향 벡터가 정규화되었다고 가장하겠다.
OpenGL은 스펙상 빛의 위치가 지정되면 이 위치 좌표가 자동으로 눈 공간 좌표계(eye space coordinate), 예를 들어서 카메라 좌표계로 바뀐다. 우리는 좌표체계가 바뀌어도 빛의 위치가 정규화된 상태로 유지된다고 가정할 수 있다. 이 가정은 모델뷰해열의 좌측상단의 3x3 부분의 행렬이 직교일때 옳다(만약 gluLookAt함수를 사용하고, 어플리케이션에서 좌표계의 크기조정을 하지 않았다면 확실히 옳다).
우리는 법선벡터를 눈 공간 좌표계(카메라 좌표계)로 변환해야 하며, 빛의 방향벡터와 법선벡터 사이의 각을 계산하기 위해 내적 계산을 해야 한다.
법선벡터를 카메라 좌표계로 변환하기 위해서는 미리 정의된 Uniform 변수인 gl_NormalMatrix를 사용한다. 이 행렬 변수는 모델뷰 매트릭스의 좌상단의 3x3 부분의 역행렬의 전치 행렬이다. 우리는 하나의 버텍스 마다 법선 변환을 수행할 것인데 아래의 코드가 바로 이 변환에 대한 코드이다.
varying vec3 normal;
void main()
{
normal = gl_NormalMatrix * gl_Normal;
gl_Position = ftransform();
} 아래의 코드처럼 프레그먼트 쉐이더에서 빛의 위치를 얻어와 빛의 밝기값을 계산한다.
varying vec3 normal;
void main()
{
float intensity;
vec3 color;
vec3 n = normalize(normal);
intensity = dot(vec3(gl_LightSource[0].position, n);
if(intensity > 0.95)
color = vec4(1.0, 0.5, 0.5, 1.0);
else if(intensity > 0.5)
color = vec4(0.6, 0.3, 0.3, 1.0);
else if(intensity > 0.25)
color = vec4(0.4, 0.2, 0.2, 1.0);
else
color = vec4(0.2, 0.1, 0.1, 1.0);
gl_FragColor = color;
} 최종 소스 코드는 다음을 통해 다운로드 받길 바란다.
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/10/01 23:04
2007/10/01 23:04
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/313 |
|
|
|
|
|
|
|
GLSL 예제 - 툰쉐이딩 3(총4장)
원문 : http://www.lighthouse3d.com/opengl/glsl/index.php?toon2
GLSL은 OpenGL의 상태의 일부에 접근할 수 있다. 이 강좌에서는 OpenGL 어플리케이션에서 glColor로 설정된 색을 읽는 방법에 대해서 살펴보겠다.
GLSL은 현재의 색상값을 가지고 있는 Attribute 변수가 있다. 이 센션에서는, 프레그먼트 마다 툰 쉐이딩 효과를 적용할 것이다. 이렇게 하기 위해서는, 프레그먼트 마다에 대한 법선벡터값을 읽어야 한다. 버텍스 쉐이더는 Varying 변수에 법선벡터를 기록할 필요만 있는 반면, 프레그먼트 쉐이더는 보간된 법선벡터를 읽어야한다.
프레그먼트 쉐이더에서 즉시 빛의 밝기값이 계산되므로 버텍스 쉐이더의 코드는 간단해진다. lightDir은 Uniform 변수인데, 이 변수는 프레그먼트 쉐이더로 옮겨지게되며, 버텍스 쉐이더에서는 더 이상 사용되지 않는다.varying vec3 normal;
void main()
{
normal = gl_Normal;
gl_Position = ftransform();
} 프레그먼트 쉐이더에서, Uniform 변수인 lightDir를 선언할 필요가 있는데, 이 변수가 빛의 밝기값을 계산하는데 사용된다. 보간된 법선벡터를 받기 위해 Varying 변수도 정의해야한다. 아래 프레그먼트 쉐이더의 코드 내용이다.uniform vec3 lightDir;
varying vec3 normal;
void main()
{
float intensity;
vec4 color;
intensity = dot(lightDir, normal);
if(intensity > 0.95)
color = vec4(1.0, 0.5, 0.5, 1.0);
if(intensity > 0.5)
color = vec4(0.6, 0.3, 0.3, 1.0);
if(intensity > 0,25)
color = vec4(0.4, 0.2, 0.2, 1.0);
else
color = vec4(0.2, 0.1, 0.1, 1.0);
gl_FragColor = color;
} 결과는 다음과 같다.
이전이랑 결과가 똑같네? =_=;; 뭐여....?
이전 장에서 살펴본 것과 이번 장의 것의 차이점을 좀더 살펴보자. 첫번째 것은 빛의 밝기를 버텍스 쉐이더에서 계산을 했고 프레그먼트 쉐이더에서 보간된 값을 사용했다. 두번째 것은 내적을 계산한 프레그먼트 쉐이더를 위해 버텍스쉐이더에서 법선벡터를 보간했다. 보간과 내적 연산은 둘다 선형 연산이므로 내적연산을 수행한 다음에 보간 연산을 수행하나 보간 연산을 수행하고 선형 연산을 수행하나 결과는 동일하다.
그럼 도데체 프레그먼트 쉐이더에서 내적을 위한 법선벡터의 보간의 사용에 뭐가 문제가 있다는 것인가!! 법선벡터가 옳바른 방향을 가지고 있을지라도 법선벡터가 잘못인데, 이유는 법선벡터가 정확히 단위벡터의 길이(1)이 아니기 때문이다.
We know that the direction is right because we assumed that the normals that arrived at the vertex shader were normalized, and interpolating normalized vectors, provides a vector with the correct direction. However the length is wrong in the general case because interpolating normalized normals only yields a unit length vector if the normals being interpolated have the same direction, which is highly unlikely in smooth surfaces. 보다 자세한 내용은 이후에 Normalization 이슈에서 다시 살펴보겠다.
버텍스 쉐이더로부터 프레그먼트 쉐이더로 빛의 밝기계산을 옮긴 주요 이유는 프레그먼트에 대해 적당한 법선벡터를 사용해 계산하기 위함이다. 방향은 옳지만 단위벡터가 아닌 법선 벡터를 가지고 있다. 단위 벡터가 아닌 문제를 해결하려면, 프레그먼트 쉐이더에서 법선벡터를 정규화해주면 된다. 다음의 코드가 이런 문제를 해결한 완벽한 튠쉐이더이다.
uniform vec3 lightDir;
varying vec3 normal;
void main()
{
float intensity;
vec4 color;
intensity = dot(lightDir, normalize(normal));
if (intensity > 0.95)
color = vec4(1.0,0.5,0.5,1.0);
else if (intensity > 0.5)
color = vec4(0.6,0.3,0.3,1.0);
else if (intensity > 0.25)
color = vec4(0.4,0.2,0.2,1.0);
else
color = vec4(0.2,0.1,0.1,1.0);
gl_FragColor = color;
} 위 코드에 대한 결과는 다음과 같다. 훨씬 멋있어 졌당~ 하지만 여전이 완벽하지 않다. 그것은 모서리 부분이 계단처럼 나타나는 문제인데, 이 문제는 이 장의 범위를 벗어난다.
다음 장에서는 쉐이더를 통해 다양한 광원에 대해 살펴보겠다.
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/09/20 23:55
2007/09/20 23:55
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/309 |
|
|
|
|
|
|
|
| GLSL 예제 - 툰 쉐이딩(Toon Shading) - 2장(총4장)
원문 : http://www.lighthouse3d.com/opengl/glsl/index.php?toon1
이 장에서 보일 첫번째 툰 쉐이딩은 버텍스에 대한 명도를 계산한다. 다음으로 프레그먼트 쉐이더는 프레그먼트에 대한 톤을 계산하기 위해 버텍스에 대한 보간된 명도를 사용한다. 그래서 버텍스 쉐이더는 반드시 명도를 저장하는 변수를 Varying으로 선언해야 한다. 프레그먼트 쉐이더는 같은 변수를 선언해야하며 Varying 지정자를 사용하여 버텍스 쉐이더에서 계산된 명도값을 받을 수 있다.
빛의 방향은 지역변수나 상수로써 버텍스 쉐이더 안에 정의될 수 있다. 그러나 Uniform 변수로써 정의되면 융통성이 좋은데, OpenGL 어플리케이션에서 자유롭게 설정할 수 있기 때문이다. 빛의 방향에 대한 변수는 다음과 같이 쉐이더 안에서 정의된다. uniform vec3 lightDir; 지금부터는, 빛의 방향을 World 공간에서 정의되었다고 가정하겠다.
버텍스 쉐이더는 OpenGL 어플리케이션에서 지정된 법선벡터에 접근할 수 있는데, gl_Normal이라는 Attribute 변수를 통해 가능하다. 이 법선벡터는 OpenGL 어플리케이션에서 glNormal 함수를 통해 정의한 것이며 Local 공간에서 정의된다.
만약 OpenGL 어플리케이션에서 모델에 대해 회전이나 크기조정이 수행되지 않는다면, World 공간에서 정의된 법선벡터는 gl_Normal 변수를 통해 버텍스 쉐이더에 제공되며 Local 공간에서 정의된 법선벡터와 일치한다. 법선 벡터는 방향벡터이므로 이동에는 영향을 받지 않는다. 법선벡터와 빛의 방향 모두 같은 공간에서 지정되므로, 버텍스 쉐이더는빛의 방향 사이의 각(밫의 방향벡터와 법선벡터 사이 각)에 대한 코사인(cos) 계산으로 바로 계산할 수 있다. 코사인(cos)은 다음 공식을 사용해 계산할 수 있다.
cos(lightDir, normal) = (lightDir dot-product normal) / ( |lightDir| * |normal| ) 법선벡터(normal)과 빛의방향벡터(lightDir)가 단위벡터라면 위의 공식은 다음처럼 간단하게 된다.
cos(빛과 법선벡터의 사이각) = lightDir dot-product normal lightDir 변수는 OpenGL 어플리케이션에서 제공받으므로, 이 변수는 이미 단위벡터라고 가정할 수 있다. 이런 가정이 가능하다면 모든 버텍스에 대해 매번 단위벡터화를 해주지 않고도, 단지 lightDir 변수가 바뀔때 단 한번만 단위벡터로 바꾸면 된다.
GLSL에서 제공하는 dot 함수를 사용해서 intensity라는 이름의 변수에 위에서 설명한 값을 저장한다.
intensity = dot(lightDir, gl_Normal); 이제 버텍스 쉐이더 부분에서 마지막으로 해야할 것은 버텍스 좌표로 변환하는 것이다. 아래가 완성된 코드이다.
uniform vec3 lightDir;
varying float intensity;
void main()
{
intensity = dot(lightDir, gl_Normal);
gl_Position = ftransform();
} 이제, 프레그먼트 쉐이더에서 해야할 것은 intensity에 기반해서 프레그먼트의 색을 지정하는 것이다. intensity는 반드시 프레그먼트 쉐이더로 넘겨줘야하는데, 프레그먼트의 색상을 설정할 책임이 바로 프레그먼트 쉐이더에 있기 때문이다. 이전에 언급했듯이 intensity는 버텍스 쉐이더나 프레그먼트 쉐이더 모두에서 Varying 지정자로 정의된다. Varying 변수는 버텍스 쉐이더에서 설정되고 난뒤에 프레그먼트 쉐이더에서 읽혀진다.
색상은 다음처럼 프레그먼트 쉐이더에서 계산되어진다.
vec4 color;
if(intensity > 0.95)
color = vec4(1.0, 0.5, 0.5, 1.0);
else if(intensity > 0.5)
color = vec4(0.6, 0.3, 0.3, 1.0);
else if(intensity > 0.25)
color = vec4(0.4, 0.2, 0.2, 1.0);
else
color = vec4(0.2, 0.1, 0.1, 1.0); 위의 코드를 보면, 코사인값(intensity)이 0.95보다 크면 가장 밝은 색상으로 지정하고 0.25보다 작으면 가장 어두운 색상으로 지정하고 있다. 프레그먼트 쉐이더에서 해야할 것은 color 변수수를 기반으로 해서 gl_FragColor를 설정하는 것이다. 프레그먼트 쉐이더에 대한 전체 코드는 다음과 같다.varying float intensity;
void main()
{
vec4 color;
if(intensity > 0.95)
color = vec4(1.0, 0.5, 0.5, 1.0);
else if(intensity > 0.5)
color = vec4(0.6, 0.3, 0.3, 1.0);
else if(intensity > 0.25)
color = vec4(0.2, 0.1, 0.1, 1.0);
gl_FragColor = color;
} 아래의 이미지가 최종 결과이다. 근데 그다지 멋있지는 않은것 같은데, 어떻게 생각하는가? 좀더 근사한 툰 쉐이딩을 연출하기 위해서는 intensity 계산(보간) 방법을 개선해야 한다. 이에 대해서는 다음 섹션에서 다루도록 하겠다.
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/09/19 01:22
2007/09/19 01:22
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/307 |
|
|
|
|
|
|
|
GLSL 예제 - 툰 쉐이딩(Toon Shading) - 1장(총4장)
원문 : http://www.lighthouse3d.com/opengl/glsl/index.php?toon
툰 쉐이딩은 아마도 우리가 작성할 수 있는 가장 간단한 비실사적(Non-Photorealistic)인 쉐이더일 것이다. 툰 쉐이딩은 소수의 색상만을 사용하는데, 급작스러운 톤의 변화가 나타난다. 말보다는 아래의 이미지를 살펴보면 이해가 쉬울 것이다.
위의 주전자 모델에서 명도(Tone)은 각도에 의해 선택되어지는데, 사실 코사인의 각도에 기반하며, 이 각도는 실제 빛의 방향과 표면의 법선 벡터의 각이다.
그래서 빛의 방향에 근접한 법선벡터를 가지고 있다면, 명도을 계산해서 사용할 수 있다. 법선과 빛의 방향 사이의 각도가 점점 증가함에 따라 더 어두운 명암의 색조를 사용하게 된다. 코사인의 각이 명암의 세기를 제공한다.
툰쉐이더에 대한 이 섹션에서는 버텍스 당 명암의 세기를 계산하는 방식으로 시작을 한 뒤에, 계산된 명암의 세기를 프레그먼트 쉐이더로 보낸다. 여기서 OpenGL의 빛의 위치를 어떻게 쉐이더에서 접근할 수 있는지를 살펴본다.
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/09/17 23:54
2007/09/17 23:54
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/305 |
|
|
|
|
|
|
|
GLSL 예제 - Flatten Shader(납작 쉐이더? =_=;)
원문 : http://www.lighthouse3d.com/opengl/glsl/index.php?flatten
쉐이더 프로그래밍은 3차원 장면에 새로운 효과를 넣는데 매우 유용하다. 이 작은 예는 버텍스가 기묘한 방법으로 가공되는 것을 보여준다.
먼저 3D 모델을 납작하게 렌더링시키기 위해, 모델뷰 변환을 적용하기 전에 z 좌표의 값을 0으로 설정한다. 아래의 버텍스 쉐이더가 이 연산을 수행한다.
void main(void)
{
vec4 v = vec4(gl_Vertex);
v.z = 0.0;
gl_Position = gl_ModelViewProjectionMatrix * v;
} 위의 코드를 보면, 먼저 지역변수(v)에 gl_Vertex를 복사하고 있다. gl_Vertex는 GLSL에서 제공하는 Attribute 변수이며, 버텍스 쉐이더가 수행되는 동안에는 읽기전용으로 사용할 수 있는 변수이다. 읽기전용이기 때문에 지역변수에 복사하여 값을 변환시킨것이다.
프레그먼트 쉐이더는 단지 색상만을 지정하므로, 이전 섹션(Hello World 예제)에서 제공한 코드와 동일하다.
이 쉐이더는 각 버텍스의 z 좌표를 0으로 지정한다. 주전자 3D 모델에 적용을 해보면, 아래의 그림처럼 납작해진 것으로 표현된다.
됐다. 이제 여기서 좀 응용을 해보자. 버텍스의 z값을 sin함수와 sin함수의 변수는 버텍스의 x좌표로 해면 주전자 모델이 너울거리는 것처럼 표시된다.
void main(void)
{
vec4 v = vec4(gl_Vertex);
v.z = sin(5.0 * v.x) * 0.25;
gl_Position = gl_ModelViewProjectionMatrix * v;
} 이제 이 간단한 예제에 마지막으로 버텍스 에니메이션 효과를 적용해보자. 이 효과를 위해서, 시간을 추적하거나 프레임 카운터를 위한 변수가 필요하다. A vertex shader can't keep track of values between vertices, let alone between frames. 그래서 OpenGL 어플리케이션에 변수를 하나 정의하고, 이 변수를 Uniform 변수로 쉐이더에 넘겨야 한다. OpenGL 어플리케이션에 "time"이라는 이름의 변수가 있는데, 이변수는 프레임을 카운터하고, 같은 이름의 Uniform 변수가 쉐이더 안에 있다.
버텍스 쉐이더에 대한 코드는 다음과 같다.
uniform float time;
void main(void)
{
vec4 v = vec4(gl_Vertex);
v.z = sin(5.0*v.x + time*0.01)*0.25;
gl_Position = gl_ModelViewProjectionMatrix * v;
} Uniform 변수를 설명한 섹션에서 언급했듯, OpenGL 어플리케이션에서는 다음 두단계가 필요하다.
- setup : Uniform 변수의 위치를 얻는다.
- render : Uniform 변수를 갱신한다.
setup 부분은 다음 코드와 같다. loc = glGetUniformLocationARB(p, "time"); 위의 코드에서 인자 p는 쉐이더 프로그램의 헨들이고, time은 버텍스 쉐이더에서 정의한 Uniform 변수의 이름이다. loc 변수는 GLint 형이며 render 함수에서 접근할 수 있는 위치에 정의되어야 한다.
render 함수는 아래와 같다.
void renderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLootAt(0, 0, 5, 0, 0, 0, 0, 1, 0);
glUniform1fARB(loc, time);
glutSolidTeaport(1);
time += 0.1;
glutSwapBuffers();
} time 변수는 초기화부분에서 임의값으로 초기화되었을 것이고 매 프레임마다 증가된다.
여기까지의 예제 코드에 대한 전체 코드는 아래를 통해 다운로드 받길 바란다.
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/09/12 23:17
2007/09/12 23:17
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/303 |
|
|
|
|
|
|
|
| GLSL 예제 : Color Shader
원문 : http://www.lighthouse3d.com/opengl/glsl/index.php?color
GLSL은 OpenGL 상태의 일부분에 접근할 수 있다. 이 섹션에서는 glColor를 사용하는 OpenGL 어플리케이션의 색상에 어떻게 접근하는지를 살펴보겠다.
GLSL은 현재의 색상에 대한 Attribute 변수를 가지고 있다. 또한 버텍스 쉐이더로부터 프레그먼트 쉐이더로 전달되는 색상을 얻기 위한 Varying 변수를 가지고 있다. attribute vec4 gl_Color;
varying vec4 gl_FrontColor; // 버텍스 쉐이더에서 쓰기 가능
varying vec4 gl_BackColor; // 버텍스 쉐이더에서 쓰기 가능
varying vec4 gl_Color; // 프레그먼트 쉐이더에서 읽기 가능 아이디어는 다음과 같다.
- OpenGL 어플리케이션은 glColor 함수를 사용해서 색상값을 보낸다.
- 버텍스 쉐이더는 gl_Color Attribute 변수로 색상값을 받는다.
- 버텍스 쉐이더는 앞면과 뒷면의 색상을 계산하고, gl_FrontColor과 gl_BackColor에 저장한다.
- 프레그먼트 쉐이더는 gl_Color Varying 변수로 보간된 색상을 받는데, 이 색상은 현재의 프리미티브의 방향에 따라 다르다. 예를들어 보간은 gl_FrontColor나 gl_BackColor 값을 사용해서 보간된다.
- 프레그먼트 쉐이더는 gl_Color 값에 기반해서 gl_FragColor를 설정한다.
varying 변수는 버텍스 쉐이더와 프레그먼트 쉐이더 모두에서 같은 이름으로 선언되어져야한다. 여기서의 파악해야할 주요 내용은, 버텍스 쉐이더안에는 2개의 변수가 있는데, 바로 gl_FrontColor와 gl_BackColor이며, 현재의 프리미티브의 면의 방향에 따라 gl_Color의 값이 자동으로 산출되어 진다는 것이다. 여기서 gl_Color Attribute 변수와 gl_Color Varying 변수 사이에는 어떤 충돌도 없다는 점인데, gl_Color Attribute 변수는 버텍스 쉐이더에서만 볼 수 있고 gl_Color Varying 변수는 프레그먼트 쉐이더에서 볼 수 있기 때문이다.
설명은 충분이 했고, 버텍스 쉐이더에 대한 코드를 살펴보자. 여기서 앞면의 색이 계산되어졌다.
void main()
{
gl_FrontColor = gl_Color;
gl_Position = ftransform();
} 위의 코드를 들여다보면, gl_Color는 Attribute 변수로써 OpenGL 어플리케이션의 glColor를 통해 값이 지정된다. 이렇게 지정된 색상값을 gl_FrontColor Varying 변수에 입력되어 프레그먼트 쉐이더로 넘겨진다.
프레그먼트 쉐이더를 살펴보자. 버텍스 쉐이더처럼 매우 간단하다.
void main()
{
gl_FragColor = gl_Color;
} 간단이 설명해보면, 먼저 버텍스 쉐이더로부터 받은 색상(gl_Color Varying 변수)을 실제 프리미티브의 색상으로 지정하기 위해 gl_FragColor에 지정하고 있다.
위의 실제 예제 코드는 아래를 통해 다운로드 받기 바란다.
실행 결과는 다음과 같다. (썰렁 썰렁~)
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/09/10 23:24
2007/09/10 23:24
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/302 |
|
|
|
|
|
|
|
GLSL Samples - Hello World in GLSL
원문 : http://www.lighthouse3d.com/opengl/glsl/index.php?minimal
이 섹션은 Hello World에 대한 GLSL 판이다. 가장 기본적인 내용을 수행하는 쉐이더를 살펴볼 것이다 : 버텍스의 변환, 단일 색상으로 프리미티브 렌더링하여 화면 표시.
버텍스 쉐이더
이전 섹션중에 버텍스 쉐이더 부분에서 언급했듯이, 버텍스 쉐이더는 버텍스의 변환을 담당한다. OpenGL의 고정기능과 동일한 내용을 수행하는 버텍스의 변환을 수행하는 쉐이더를 살펴볼 것이다.
고정기능은 다음과 같이 모델뷰 행렬과 투영행렬에 의해 변환을 수행한다.
vTrans = projection * modelview * incomingVertex
GLSL에서 위의 내용을 수행하는 코드를 작성하려면 모델뷰 행렬과 투영행렬을 얻을 수 있도록 OpenGL에 접근할 필요가 있다. 이전에 언급했듯이, OpenGL의 상태 중 일부를 GLSL에서 접근할 수 있는데, 주로 언급한 투영행렬과 모델뷰행렬이다. 행렬은 이미 정의된 Uniform 변수를 통해서 제공된다.
uniform mat4 gl_ModelViewMatrix;
uniform mat4 gl_ProjectionMatrix; 하나 더 필요한 것은 입력 버텍스에 접근하는 것이다. 이런 버텍스는 하나씩 하나씩 버텍스 쉐이더에 접근되는데 Attribute 변수를 통해서 제공된다.
attribute vec4 gl_Vertex; 행렬에 의해 변환된 버텍스를 출력하기 위해서, 쉐이더는 반드시 미리 정의된 변수인 gl_Position을 사용해야 하며 gl_Position은 vec4로 선언된 변수다.
위처럼 한다면, 이제 버텍스 쉐이더를 작성하는게 가능하다. 하지만 아직은 버텍스 변환 연산만 가능하다. 주의할 것은 버텍스 변환 이외의 다른 기능은 작동하지 않는데, 예를들어 빛계산은 수행되지 않는다.
버텍스 쉐이더는 main 함수를 가져야만 한다.
void main()
{
gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;
} 위의 코드에서, 투영행렬은 모든 버텍스에 대해서 모델뷰행렬과 곱해지는데, 이것은 분명이 시간 낭비다. 왜냐하면 투영행렬과 모델뷰행렬은 모든 버텍스에 대해서 변하지 않는다. 이 행렬들은 Uniform 변수다.
GLSL은 몇개의 파생된 행렬을 제공하는데, 바로 gl_ModelViewProjecteionMatrix로써, 투영행렬과 모델뷰행렬을 곱한 결과 매트릭스이다. 이 변수를 사용해 다시 코드를 작성하면...
void main()
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
} 위의 두 main() 함수에 대한 쉐이더의 최종 결과는 동일하다. 그런데 고정기능과 동일한 변환을 보장하는가? 음... 이론적으로 그렇다. 그러나 버텍스의 변환의 실제 절차는 여기와 달리 동일한 순서를 따르지 않는다. 이것은 보통 그래픽 카드에 매우 최적화된 작업인데, 최적화의 이점을 취하기 위해 하나의 특별한 기능이 제공된다. 이 기능의 또 다른 이유는 float 데이터 타입의 정밀도에 제약이 있기 때문이다. 계산이 다른 순서로 이뤄질때, 이 제한된 정밀도로 인해 다른 결과가 얻어진다. 그래서 GLSL은 최고의 수행속도뿐만 아니라 고정기능과 동일한 결과를 항상 얻을 수 있는 함수를 제공한다. 바로 마법과 같은 그 함수는:
vec4 ftransform(void); 이 함수는 입력받은 버텍스를 변환한 결과를 반환하며, 고정기능과 동일한 단계를 수행해 고정기능과 동일한 결과를 제공한다. 이제 쉐이더는 다음과 같이 재작성될 수 있다.
void main()
{
gl_Position = ftransform();
} 프레그먼트 쉐이더
프레그먼트 쉐이더 역시 프레그먼트의 색상을 설정할 수 있는 미리 정의된 변수를 가지고 있다: gl_FragColor. 버텍스 쉐이더의 경우에서처럼, 프레그먼트 쉐이더 역시 main 함수를 가지고 있다. 다음 코드는 푸르스름한 색상으로 모든 프레그먼트를 그리는 프레그먼트 쉐이더 코드이다.
void main()
{
gl_FragColor = vec4(0.4, 0.4, 0.8, 1.0);
} 위의 버텍스 쉐이더와 프레그먼트 쉐이더를 적용한 결과는 아래와 같다.
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/09/06 23:27
2007/09/06 23:27
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/300 |
|
|
|
|
|
|
|
Varying 변수
원문 : http://www.lighthouse3d.com/opengl/glsl/index.php?varying
이전에 언급했듯이, 쉐이더는 2가지가 있다 : 버텍스 쉐이더와 프레그먼트 쉐이더. 프레그먼트에 대한 값을 계산하기 위해서는, 버텍스 쉐이더에 접근할 필요가 있다. 예를들어서, 프레그먼트에 대한 빛 계산을 하려면, 해당 프레그먼트에서의 노말벡터를 얻어와야 한다. 그러나 OpenGL에서, 노말벡터는 오직 버텍스에 지정되어져 있다. Attribute 변수를 사용해서 OpenGL 어플리케이션으로부터 노말벡터를 얻어왔기 때문에 노말벡터를 버텍스 쉐이더에서 접근할 수 있지만, 프레그먼트 쉐이더에서는 접근할 수 없다.
모든 버텍스 데이터를 포함해서, 버텍스가 처리된 후에, 버텍스 정보는 연결정보를 이용할 수 있는, 파이프라인의 어떤 단계로 이동된다. 이 어떤 단계가 프리미티브가 만들어지고 계산되어지는 단계이다. 각 프레그먼트에 대해서, 자동으로 해석되어지고 프레그먼트 쉐이더에 제공되지는 변수가 있다. 예를들어 프레그먼트의 색상이 있다. 프레그먼트 쉐이더에 도착하는 색상은 프리미티브를 구성하는 버텍스의 색상 보간의 결과이다.
이 변수의 타입이 바로 "varying" 변수이다. GLSL은 미리 정의된 몇개의 varying 변수를 가지고 있는데, 위에서 언급한 색상이 한 예이다. GLSL은 varying 변수를 사용자가 정의할 수 있다. 이 변수는 버텍스 쉐이더와 프레그먼트 쉐이더 모두에서 선언되어져야한다. 아래처럼 말이다.
varying float intensity; varying 변수는 버텍스 쉐이더에서 각 버텍스에 대한 계산값으로 설정된다. 프레그먼트 쉐이더에서 이 varying 변수(버텍스 쉐이더에서 이미 계산되어진 값들)는 단지 읽기만 할 수 있다.
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/09/04 14:09
2007/09/04 14:09
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/299 |
|
|
|
|
|
|
|
| GLSL의 제어문과 함수 제어문
제어문은 C언어와 매우 비슷하다. if-else, for, do-while문과 같은 조건문과 반복문이 있다. if (bool expression)
...
else
...
for(initialization; bool expression; loop expression)
...
while(bool expression)
...
do
...
while(bool expression) GLSL의 스펙에는 위의 제어문들이 사용가능하다고 되어있지만, if 문은 요즘의 하드웨어에서만 지원되는 경우가 많다.
제어문과 관련된 몇개의 함수가 정의되어 있는데,
- continue - 반복문에서 사용 가능하며, 바로 다음 반복의 단계로 간다.
- break - 반복문에서 사용 가능하며, 반복문을 종료한다.
- discard
discard 키워드는 프레그먼트 쉐이더에서만 사용할 수 있다. 이 키워드가 실행되면 현재 프레그먼트 쉐이더는 종료되며, 프레임버퍼나 깊이 버퍼에 아무런 내용도 쓰지 않는다.
함수
C에서처럼, 쉐이더는 함수로 정의된다. 쉐이더는 아래와 같은 형태의 최소한 하나의 main 함수를 가져야 한다.
void main() 사용자 함수도 정의할 수 있다. C에서처럼, 함수는 값을 반환할 수 있는데, return 문을 써서 결과값을 반환한다. 물론 함수는 void 를 써서 반환하지 않을 수 있다. 반환 타입은 GLSL에서 제공하는 어떤 타입이든지 가능하지만, 배열은 될 수 없다.
함수의 인자는 다음 지정자와 함께 쓸 수 있다.
- in - 오직 입력 인자로써 사용됨
- out - 어떤 값을 반환하는 용도로 사용됨. 함수의 결과를 보내기 위한 또 다른 방법
- inout - 입력 및 값 반환의 두가지 용도로 사용됨
인자에 지정자가 없다면, 기본적으로 in 이다.
마지막으로 몇가지 주의할 점이 있는데,
- 함수는 인자를 다르게 해서 오버로드될 수 있다.
- GLSL 스펙상 재귀호출은 가능하지 않다.
마지막으로 함수에 대한 하나의 예를 제시하겠다.
vec4 toonify(in float intensity) {
vec4 color;
if(intensity > 0.98)
color = vec4(0.8, 0.8, 0.8, 1.0);
else if(intensity > 0.5)
color = vec4(0.5)
else if(intensity > 0.25)
color = vec4(0.2, 0.2, 0.4, 1.0);
else
color = vec4(0.1, 0.1, 0.1, 1.0);
return(color);
}
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/08/29 03:44
2007/08/29 03:44
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/298 |
|
|
|
|
|
|
|
| GLSL에서의 데이터 타입과 변수
원문 : http://www.lighthouse3d.com/opengl/glsl/index.php?data
타입(Type)
GLSL에서 사용가능한 간단한 데이터 타입은 다음과 같다. float와 int는 C언어와 동일하며 bool은 true와 false 값을 취한다.
2, 3 또는 4개의 요소를 가지는 벡터 타입이 있으며, 벡터 요소의 타입은 위에서 언급한 것이 될 수 있다. 벡터 타입의 선언은, - vec{2,3,4} : 2, 3 또는 4개의 요소를 가지는 실수 벡터
- bvec{2,3,4} : 2, 3 또는 4개의 요소를 가지는 블린 벡터
- ivec{2,3,4} : 정수 벡터
그래픽에서 매우 중요한 2x2, 3x3 또는 4x4 행렬 타입이 있으며 아래와 같다. 텍스쳐 접근이 가능하는 특별한 타입들이 있다. 이 타입들은 샘플러(Sampler)라고 불리며, 텍스쳐 값(텍셀;texel)에 접근하는데 사용된다. 이 텍스쳐 샘플링을 위한 데이터 타입은 아래와 같다. - sampler1D - 1D 텍스쳐을 위한 샘플러
- sampler2D - 2D 텍스쳐를 위한 샘플러
- sampler3D - 3D 텍스쳐를 위한 샘플러
- samplerCube - 큐브맵 텍스쳐를 위한 샘플러
- sampler1DShadow - 그림자맵을 위한 샘플러
- sampler2DShadow - 그림자맵을 위한 샘플러
GLSL에서 배열은 C언어에서처럼 선언할 수 있다. 그러나 배열은 선언할때 초기화할 수가 없다. 배열의 요소에 접근하는 방법은 C언어와 동일하다.
구조체 역시 GLSL에서 가능하며, C언어와 동일하다. struct dirlight {
vec3 direction;
vec3 color;
}; 변수(Variables)
간단한 변수의 선언은 C언어와 매우 유사하다. 변수의 선언과 함께 초기화도 가능하다.
float a, b; // 2개의 실수형 변수(C언어처럼 주석이 가능하다)
int c = 2 // c변수는 2로 초기화되었다
bool d = true; // d는 true 값이다 변수의 다른 타입이 선언 역시 같은 식이지만, GLSL와 C 사이에 차이가 있다. GLSL은 초기화와 형변환 생성자에 매우 의존적이다.
float b = 2; // 옳지않아~ =_=; GLSL에는 자동형변환이 않되~
float e = (float)2; // 옳지않아~ 형변환 생성자가 필요해~
int a = 2;
float c = float(a); // 옳다! ^^* c는 2.0
vec3 f; // f는 vec3로 선언
vec3 g = vec3(1.0, 2.0, 3.0); // 선언과 동시에 초기화 GLSL은 다른 변수를 가지고 초기화하는 것에 매우 유연하다. 다음 예를 보자.
vec2 a = vec2(1.0, 2.0);
vec2 b = vec2(3.0, 4.0);
vec4 c = vec4(a, b); // c=vec4(1.0, 2.0, 3.0, 4.0)
vec2 g = vec2(1.0, 2.0);
float h = 3.0;
vec3 j = vec3(g, h); 행렬도 마찬가지 방식이다.
mat4 m = mat4(1.0); // 행렬의 대각요소를 1.0으로 초기화
vec2 a = vec2(1.0, 2.0);
vec2 b = vec2(3.0, 4.0);
mat2 n = mat2(a, b); // 컬럼 방향으로 값이 지정된 행렬
mat2 k = mat2(1.0, 0.0, 1.0, 0.0); // 모든 요소를 지정 구조체의 선언과 초기화는 아래와 같다.
struct dirlight { // 타입정의
vec3 direction;
vec3 color;
};
dirlight d1;
dirlight d2 =
dirlight(vec(1.0, 1.0, 0.0), vec3(0.8, 0.8, 0.4)); GLSL에서 제공하는 몇가지 여유로움이 우리의 삶을 단순하게 해주며 코드를 명확하게 만들어 준다. 아래의 예를 보자.
vec4 a = vec4(1.0, 2.0, 3.0, 4.0);
float posX = a.x;
float posY = a[1];
vec2 posXY = a.xy;
float depth = a.w; 이전 코드에서 살펴 본것처럼, 벡터의 요소에 접근하기 위해서 x, y, z, w 문자를 사용할 수 있다. 만약 색상에 대해서 이야기할때는 r, g, b, a 문자를 사용하면된다. 텍스쳐 좌표에서 사용할 수 있는 문자는 s, t, p, q이다. 변환에 주의해야 하는데, 텍스쳐 좌표는 s, t, r, q로 자주 참조된다. 그러나 r은 이미 앞에서 RGBA에의 "Red"에 해당하는 것으로 사용되고 있다. 이러한 x, y, z, w, r, g, b, a, s, t, p, q를 선택자(Selector)이라고 한다.
행렬에 대한 선택자는 하나나 두개 인자를 취할 수 있는데, m[0] 또는 m[2][3]처럼 말이다. 첫번째 경우는 첫번째 컬럼을 선택한 것이고 두번째 경우는 행렬의 요소중에 하나의 요소를 선택한 것이다.
구조체에서 요소의 이름은 C언어에서처럼 사용된다. 위의 구조체 설명에서 예로써 정의한 경우에서 예를 들어본다면..
d1.direction = vec3(1.0, 1.0, 1.0); 변수 평가자(Variable Qualifiers)
평가자는 변수에 특별한 의미를 제공한다. 다음과 같은 평가자가 있다.
const - 변수는 상수값이다.
attribute - 전역 변수이며 버텍스 마다 바뀔 수 있고, OpenGL 어플리케이션에서 버텍스 쉐이더로 값을 변경한다. 이 평가자는 버텍스 쉐이더에서만 사용된다. 쉐이더에서는 읽기전용이다. Attribute 변수 섹션을 참조하기 바란다.
uniform - 전역 변수이며 프리미티브 마다 바뀔 수 있고(glBegin, glEnd 사이에 오지 않음), OpenGL 어플리케이션에서 쉐이더로 값을 변경한다.이 평가자는 버텍스나 프래그먼트 쉐이더 모두에서 사용될 수 있다. 쉐이더에서 이 변수는 상수이다. Uniform 섹션을 참조하기 바란다.
varying - 버텍스 쉐이더와 프레그먼트 쉐이더 사이에 값을 주고 받기 위해 사용된다. 버텍스 쉐이더에서는 쓰기가 허용되지만, 프레그먼트 쉐이더에서는 읽기 전용이다. Varying 섹션을 참고하라.
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/08/27 23:10
2007/08/27 23:10
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/297 |
|
|
|
|
|
|
|
| GLSL을 위한 OpenGL 설정 - Attribute 변수
원문 : http://www.lighthouse3d.com/opengl/glsl/index.php?oglattribute
이전의 Uniform 변수 섹션에서 언급했듯이, Uniform 변수는 오직 프리미티브에 의해서만 설정할 수 있다. 즉, Uniform 변수는 glBegin~glEnd 사이에서는 설정할 수 없다.
만약에 프리미티브를 구성하는 버텍스 당위로 변수를 설정하려고 한다면 Attribute 변수를 사용해야만 한다. 사실 Attribute 변수는 아무때나 설정될 수 있다. Attribute 변수는 버텍스 쉐이더에서만 읽힐 수(쓸수는 없다) 있다. 왜냐하면 Attribute 변수는 버텍스 데이터를 가지고 있어서, 프레그먼트 쉐이더에 사용하기는 적당하지 않다. (이 부분에 대해서는 추후에 varying 변수를 살펴보겠다) uniform 변수처럼, 변수에 대한 메모리 주소값을 읽어오는 것이 필요하다. 쉐이더 프로그램은 먼저 링크되어져야하며 몇몇 그래픽 카드는 쉐이더 프로그램이 사용중이여야 변수에 대한 주소값을 읽어올 수 있다.
다음은 OpenGL 2.0에서 Attribute 변수의 메모리 주소를 얻어오는 함수이다.
GLint glGetAttribLocation(GLuint program, char *name);
Parameters:
program - 쉐이더 프로그램의 핸들
name - 변수의 이름
ARB 확장 형태는 다음과 같다.
GLint glGetAttribLocationARB(GLhandleARB program, char *name);
Parameters:
program - 쉐이더 프로그램의 핸들
name - 변수의 이름
메모리의 변수 위치는 위의 함수의 리턴값으로 알수있다. 다음 단계는 값을 지정하는 것인데, uniform 변수처럼, 각 데이터 타입에 대한 함수가 있다.
OpenGL 2.0 문법은 아래와 같다.
void glVertexAttrib1f(GLint location, GLfloat v0);
void glVertexAttrib2f(GLint location, GLfloat v0, GLfloat v1);
void glVertexAttrib3f(GLint location, GLfloat v0, GLfloat v2);
void glVertexAttrib4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
또는...
GLint glVertexAttrib{1,2,3,4}fv(GLint location, GLfloat *v);
Parameter:
location - 이전에 질의해서 얻은 변수의 메모리 위치
v0, v1, v2, v3 - 실수값
v - 실수 배열
ARB 확장에 대한 문법은 아래와 같다.
void glVertexAttrib1fARB(GLint location, GLfloat v0);
void glVertexAttrib2fARB(GLint location, GLfloat v0, GLfloat v1);
void glVertexAttrib3fARB(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
void glVertexAttrib4fARB(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
또는...
GLint glVertexAttrib{1,2,3,4}fvARB(GLint location, GLfloat *v);
Parameter:
location - 이전에 질의한 변수의 위치
v0, v1, v2, v3 - 실수 변수
v - 실수 배열
정수와 몇몇 다른 데이터 타입에 대한 유사한 함수군이 제공되어진다. uniform 변수의 경우에서처럼 벡터 버전에 대한 설정 함수는 제공되지 않는다. 벡터에 대한 경우는 하나의 Attribute 변수의 값으로 지정할 수 있는데, 이것은 OpenGL에서 glColor3f와 glColor3fv 함수의 예와 비슷하다.
아래 간단한 예를 살펴보자. 이 예는 버텍스 쉐이더가 실수형 Attribute 변수로써 "height" 이름으로 선언된 경우이다. 쉐이더 프로그램이 링크된 후에 의미가 있는 예라는 점을 염두해 두길 바란다. loc = glGetAttribLocation(p, "height"); 렌더링 함수에 대한 코드 예는 아래와 같다.
glBegin(GL_TRIANGLE_STRIP);
glVertexAttrib1f(loc,2.0);
glVertex2f(-1,1);
glVertexAttrib1f(loc,2.0);
glVertex2f(1,1);
glVertexAttrib1f(loc,-2.0);
glVertex2f(-1,-1);
glVertexAttrib1f(loc,-2.0);
glVertex2f(1,-1);
glEnd(); 위의 코드에 대한 ARB 확장은 매우 비슷한데, 단지 함수에 ARB만 붙이기만 하면 된다.
위의 코드에 대한 전체 샘플은 아래를 통해 다운로드 받길 바란다.
버텍스 배열은 Attribute 변수와 함께 사용될 수 있다. 가장 먼저 해야할 것은 Array를 활성화 시키는 것인데, 활성화 시키기 위해서는 다음 OpenGL 2.0 함수를 사용하면 된다.
void glEnableVertexAttribArray(GLint loc);
Parameter:
loc - 변수의 위치
ARB 확장의 경우는 아래와 같다.
void glEnableVertexAttribArrayARB(GLint loc);
Parameter:
loc - 변수의 위치
이제 다음으로 해야할 일은, 다음 함수를 사용해서 배열에 데이터를 제공하는 것이다. OpenGL 2.0 문법이다.
void glVertexAttribPointer(GLint loc, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer);
Parameters:
loc - 변수의 위치
size - 배열 요소들의 개수로써, 예를들어, float 인경우 1, vec2인 경우 2, vec3인 경우는 3
type - 데이터 타입으로, 예를들어 GL_FLOAT
normalized - 만약 1인 경우, 배열의 값은 정규되어져 있다(부호있는 경우 -1~1, 부호가 없는 경우는 0~1로 정규화되었다는 의미)
stride - 배열 요소 사이의 간격. OpenGL와 정확히 동일함
pointer - 데이터를 가지고 있는 배열의 포인터
ARB 확장 문법은..
void glVertexAttribPointerARB(GLint loc, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer);
Parameters:
loc - 변수의 위치
size - 배열 요소들의 개수로써, 예를들어, float 인경우 1, vec2인 경우 2, vec3인 경우는 3
type - 데이터 타입으로, 예를들어 GL_FLOAT
normalized - 만약 1인 경우, 배열의 값은 정규되어져 있다(부호있는 경우 -1~1, 부호가 없는 경우는 0~1로 정규화되었다는 의미)
stride - 배열 요소 사이의 간격. OpenGL와 정확히 동일함
pointer - 데이터를 가지고 있는 배열의 포인터
이제 아래에 소스 코드를 살펴보라. 첫번째 초기화 단계에 이어, 2개의 배열이 있는데, 버텍스 배열과 속성 배열이다. "height" 변수는 적당한 위치에 선언되어져 있다고 가정할 수 있는데, 예를들어서 렌더링할때 등과 같은 시기에 접근할 수 있다.
float vertices[8] = {-1,1, 1,1, -1,-1, 1,-1};
float heights[4] = {2,2,-2,-2};
...
loc = glGetAttribLocationARB(p,"height");
glEnableClientState(GL_VERTEX_ARRAY);
glEnableVertexAttribArrayARB(loc);
glVertexPointer(2,GL_FLOAT,0,vertices);
glVertexAttribPointerARB(loc,1,GL_FLOAT,0,0,heights); 전체 소스 코드는 아래를 통해 다운로드 받기 바란다.
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/08/25 01:44
2007/08/25 01:44
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/294 |
|
|
|
|
|
|
|
| GLSL을 위한 OpenGL 설정 - Uniform 변수
원문 : http://www.lighthouse3d.com/opengl/glsl/index.php?ogluniform
Uniform 변수는 오로지 Primitive에 의해 변경될 수 있는 변수인데, glBegin과 glEnd 사이에서는 변경될 수 없다. 이러한 이유로해서 버텍스의 속성을 위해서는 사용될 수 없다. 만약 버텍스의 속성에 대한 변수를 원한다면, 이 섹선 바로 다음 섹션인 Attribute 변수를 보면된다. Uniform 변수는 Primitive나 프레임 또는 전체 장면 동안에 유지해야할 변수에 적당하다. Uniform 변수는 버텍스 쉐이더나 프레그먼트 쉐이더에서 읽을 수 있지만 쓸수는 없다.
Uniform 변수를 정의하는 가장 먼저 해야할 일은 변수에 대한 메모리 위치를 얻는 것이다. 쉐이더 프로그램이 링크된 후에야 변수에 대한 메모리 정보를 얻어오는 것이 가능하다는 점에 주의하기 바란다. 몇몇의 그래픽 카드 드라이버에서는 메모리의 위치를 얻어오기 위해 먼저 glUseProgram(OpenGL 2.0) 또는 glUseProgramObjectARB(ARB 확장)을 호출해야할 경우도 있다는 점을 주의하자.
변수를 처리할때 OpenGL 2.0과 ARB 확장은 매우 유사한 문법을 가지고 있다. 기본적으로 OpenGL 2.0 함수의 뒤에 ARB를 붙이면 ARB 확장 함수가 되는 경우가 많다.
다음 OpenGL 2.0형태의 함수는 주어진 이름에 대한 Uniform 변수(쉐이더 안에서 정의)의 위치를 얻어온다.
GLint glGetUniformLocation(GLuint program, const char *name);
Parameters:
program - 프로그램의 핸들
name - 변수의 이름
ARB 확장의 형태는 다음과 같다.
GLint glGetUniformLocationARB(GLhandleARB program, const char *name);
Parameters:
program - 프로그램의 핸들
name - 변수의 이름
반환값이 바로 변수의 위치인데, 이 변수에 값을 할당할 수 있다. Uniform 변수에 값을 할당하는 함수군은 다음과 같다.
void glUniform1f(GLint location, GLfloat v0);
void glUniform2f(GLint location, GLfloat v0, GLfloat v1);
void glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
void glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
또는
GLint glUnform{1,2,3,4}fv(GLint location, GLsizei count, GLfloat *v);
Parameters:
location - 이전에 구한 변수의 위치
v0, v1, v2, v3 - 실수값
count - 배열에서 요소의 수
v - 실수 배열
ARB 확장의 경우는 다음과 같다.
void glUniform1fARB(GLint location, GLfloat v0);
void glUniform2fARB(GLint location, GLfloat v0, GLfloat v1);
void glUniform3fARB(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
void glUniform4fARB(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
또는
GLint glUnform{1,2,3,4}fvARB(GLint location, GLsizei count, GLfloat *v);
Parameters:
location - 이전에 구한 변수의 위치
v0, v1, v2, v3 - 실수값
count - 배열에서 요소의 수
v - 실수 배열
위의 함수는 실수타입의 경우이고 정수타입도 가능한데, "f"를 "i"로 바꾸기만하면된다. 하지만 boolean 타입에 대한 함수는 없다. Boolean에 대한 경우가 필요하다면 실수나 정수형 함수에 대해서 false의 경우 0으로 할당하여 사용하면 된다. uniform 변수의 배열을 가질 경우, 벡터로 사용될 수 있다.
sampler 변수에 대해서는 OpenGL 2.0에서는 sampler의 배열을 설정하여 glUniform1i나 glUniform1iv를 사용할 수 있으며 ARB 확장의 경우 glUniform1iARB나 glUniform1ivARB를 사용하면 된다.
GLSL에서 매트릭스 데이터 타입도 사용이 가능하며 이 타입에 대한 함수는 다음과 같다.
GLint glUniformMatrix{2,3,4}fv(GLint location, GLsizei count, GLboolean transpose, GLfloat *v);
Parameters:
location - 이전에 질의한 위치
count - 행렬의 개수. 단일 매트릭스라면 1이고 n 매트릭스 배열이라면 n
transpose - 전치 행렬인지 여부이며 1인 경우 Row 방향으로 배열된 행렬이며 0인 경우 Column 방향으로 정렬된 행렬을 의미함
v - 실수 배열
ARB 확장의 경우는 아래와 같다.
GLint glUniformMatrix{2,3,4}fvARB(GLint location, GLsizei count, GLboolean transpose, GLfloat *v);
Parameters:
location - 이전에 질의한 위치
count - 행렬의 개수. 단일 매트릭스라면 1이고 n 매트릭스 배열이라면 n
transpose - 전치 행렬인지 여부이며 1인 경우 Row 방향으로 배열된 행렬이며 0인 경우 Column 방향으로 정렬된 행렬을 의미함
v - 실수 배열
주의할 것은 위의 함수들을 통해 설정된 Uniform 변수의 값들은 쉐이더 프로그램이 다시 링크될동안 유지된다. 일단 새로운 링크 처리가 수행되면 이 값들은 모두 0으로 재설정된다.
간단한 소스코드를 살펴보자. 만약 다음과 같은 변수를 사용하는 쉐이더가 있다고 해보자. uniform float specIntensity;
uniform vec4 specColor;
uniform float t[2];
uniform vec4 colors[3]; OpenGL 2.0 어플리케이션에서는, 변수 설정을 위한 코드는 다음과 같을 것이다.
GLint loc1,loc2,loc3,loc4;
float specIntensity = 0.98;
float sc[4] = {0.8,0.8,0.8,1.0};
float threshold[2] = {0.5,0.25};
float colors[12] = {0.4,0.4,0.8,1.0,
0.2,0.2,0.4,1.0,
0.1,0.1,0.1,1.0};
loc1 = glGetUniformLocation(p,"specIntensity");
glUniform1f(loc1,specIntensity);
loc2 = glGetUniformLocation(p,"specColor");
glUniform4fv(loc2,1,sc);
loc3 = glGetUniformLocation(p,"t");
glUniform1fv(loc3,2,threshold);
loc4 = glGetUniformLocation(p,"colors");
glUniform4fv(loc4,3,colors); 위의 코드에 대한 ARB 확장 형태는 다음과 같다.
GLint loc1,loc2,loc3,loc4;
float specIntensity = 0.98;
float sc[4] = {0.8,0.8,0.8,1.0};
float threshold[2] = {0.5,0.25};
float colors[12] = {0.4,0.4,0.8,1.0,
0.2,0.2,0.4,1.0,
0.1,0.1,0.1,1.0};
loc1 = glGetUniformLocationARB(p,"specIntensity");
glUniform1fARB(loc1,specIntensity);
loc2 = glGetUniformLocationARB(p,"specColor");
glUniform4fvARB(loc2,1,sc);
loc3 = glGetUniformLocationARB(p,"t");
glUniform1fvARB(loc3,2,threshold);
loc4 = glGetUniformLocationARB(p,"colors");
glUniform4fvARB(loc4,3,colors); 위의 예에 대한 전체 코드의 샘플은 다음 링크를 통해 다운로드 받기 바란다.
t나 colors 변수의 경우와 specColor의 4개의 값을 가진 벡터를 설정하는 것과 같은 배열을 설정하는 부분을 주의깊게 보기 바란다. count 인자(glGetUniform{1,2,3,4}fv)의 가운데 인자)는 쉐이더에서 선언된 배열 요소의 개수를 의미하지 OpenGL에서 선언된 요소의 개수를 의미하는 것이 아니다. 이것이 specColor가 4개의 값을 가지고 있음에도, glUniform4fv 함수의 인자 중 count는 1로 설정된 이유인데, specColor는 쉐이더에서 하나의 벡터로 선언되었기 때문이다. specColor 변수를 설정하기 위한 다른 방법은 다음과 같다.
loc2 = glGetUniformLocation(p,"specColor");
glUniform4f(loc2,sc[0],sc[1],sc[2],sc[3]); 배열 안의 변수의 위치를 얻기 위해 GLSL이 제공하는 다른 방법이 또 있는데, 예를들면.. t[1]과 같은 변수의 위치를 얻기 위해 다음과 같이 하면 된다.
loct0 = glGetUniformLocation(p,"t[0]");
glUniform1f(loct0,threshold[0]);
loct1 = glGetUniformLocation(p,"t[1]");
glUniform1f(loct1,threshold[1]); glGetUniformLocation에서 '[]'를 사용해서 원하는 요소의 구성 변수를 지정되는 방법을 사용해서 원하는 바를 얻는다.
위의 경우에 대한 ARB 확장은 ARB를 함수 이름 뒤에 추가하면 동일하므로 여기에서는 생략하겠다.
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/08/24 02:25
2007/08/24 02:25
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/292 |
Tracked from Discount phentermine.
2009/11/14 21:38 x
제목 : Phentermine 37.5.
Phentermine. Phentermine no prescription. Phentermine forum. Phentermine cash on delivery. Picture of phentermine....more
|
Tracked from Tramadol hcl.
2009/11/15 19:30 x
제목 : Tramadol.
Buy tramadol online save wholesale price yep. Tramadol hcl. Tramadol....more
|
|
|
|
|
|
|
|
GLSL을 위한 OpenGL 설정 - OpenGL에서 Shaders로의 통신
원문 : http://www.lighthouse3d.com/opengl/glsl/index.php?oglvariables
OpenGL 어플리케이션은 쉐이더와 통신할 수 있는 몇가지 방법을 가지고 있다. Note that this is a one way communication through, since the only output from a shader is to render to some targets, usually the color and depth buffers.
쉐이더는 OpenGL 상태의 일부에 접근할 수 있으므로, 어플리케이션이 OpenGL 상태의 일부를 변경하면, 쉐이더에서 이 변경된 상태를 접근할 수 있음으로 해서 효과적으로 통신을 할 수 있게 된다. 그래서 만약에 어플리케이션이 쉐이더에게 빛의 색을 전달한다고 할때, 고정기능에서 정상적으로 했던 것처럼 쉐이더는 OpenGL의 상태를 쉽게 변경할 수 있다.
그러나, OpenGL 상태의 사용이 쉐이더에 대한 값을 설정하는 항상 가장 직관적인 방법은 아니다. 예를들어서, 에니메이션의 수행 초과 시간을 전달해주는 변수를 요구하는 쉐이더가 있다고 해보자. 이런 예에서 사용할 목적에 적당한 OpenGL 상태 변수가 없다. 사실, 사용하지 않는 빛과 연관된 상태 변수를 이런 목적으로도 사용할 수 있으나, 매우 직관적이지 못하다.
다행히, GLSL은 쉐이더와 OpenGL 어플리케이션과의 통신을 위한 변수를 사용자가 정의할 수 있다. 변수에 적당한 이름, 위의 예에 적당한 'timeElapsed'이라는 이름을 붙이고 계속 사용할 수 있다.
GLSL은 2가지 종류의 변수 평가자를 가지고 있다. (이후의 섹션에서 더 많은 평가자를 소개할 것이다)
쉐이더 안에서 정의된, 위의 평가자에 대한 변수는 읽기 전용이다. 이후의 섹션에서는 이런 변수를 언제 사용하고 어떻게 사용하는지에 대해서 자세히 살펴보겠다.
변수를 쉐이더에게 전달하는 또다른 방법이 있는데. 바로 텍스쳐를 이용하는 것이다. 텍스쳐는 반드시 이미지를 표현해야만 하는 것은 아니다. 텍스쳐는 데이터의 배열로써 해석될 수 있다. 사실, 텍스쳐 데이터가 설사 이미지라도 할지라도, 쉐이더를 사용하는 여러분이 텍스쳐 데이터를 어떻게 해석할 것인지 결정할 수 있다. 이런 용도로써의 텍스쳐의 사용은 이 섹션의 영역을 벗어나므로 설명하지는 않겠다.
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/08/22 23:55
2007/08/22 23:55
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/291 |
|
|
|
|
|
|
|
GLSL을 위한 OpenGL 설정 - 청소
원문 : http://www.lighthouse3d.com/opengl/glsl/index.php?oglcleanup
이전 섹션에서는, 프로그램에 쉐이더를 붙이는 함수를 보였다. 이제 이렇게 붙인 쉐이더를 프로그램에서 때어내는 함수에 대해서 알아보자. (OpenGL 2.0 형태)
void glDetachShader(GLuint program, GLuint shader);
Parameter:
program - 쉐이더를 떼어낼 프로그램 핸들
shader - 떼어낼 쉐이더 핸들
이에 대한 ARB 확장 형태는 다음과 같다.
void glDetachObjectARB(GLhandleARB program, GLhandleARB shader);
Parameter:
program - 쉐이더를 떼어낼 프로그램 핸들
shader - 떼어낼 쉐이더 핸들
쉐이더 삭제는 프로그램에서 떼어내야만 가능하며, 쉐이더 삭제와 프로그램 삭제에 대한 OpenGL 2.0 함수는 다음과 같다.
void glDeleteShader(GLuint id);
void glDeleteProgram(GLuid id);
Parameter:
id - 삭제할 프로그램 또는 쉐이더의 핸들
쉐이더가 프로그램에 붙여져 있을 경우, 위의 함수를 사용해 삭제를 시도해도 실제로 삭제되지 않고 단지 지워졌다고 표시만된다. 쉐이더의 실제 삭제는 프로그램에서 해당 쉐이더가 떼어지면 진짜로 삭제가 된다. 참고로 쉐이더는 하나의 프로그램에만 붙을 수 있는게 아니고 여러개에 붙을 수 있으며, 쉐이더를 삭제하기 위해서는 붙은 모든 프로그램으로부터 떼어내야 한다.
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/08/22 01:18
2007/08/22 01:18
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/290 |
|
|
|
|
|
|
|
GLSL을 위한 OpenGL 설정 - InfoLog를 통한 디버깅
원문: http://www.lighthouse3d.com/opengl/glsl/index.php?oglinfo
쉐이더 디버깅은 어렵다. 아직 printf와 같은 출력문도 없고 앞으로도 없을 것이다. 하지만 향후 개발툴에서 쉐이더 디버깅을 위한 기능을 제공할지 모르겠다. 쉐이더 코드가 옳바르게 컴파일 되고 링크 되었는지를 검사하기 위한 함수가 있다.
컴파일 단계들에 대한 결과 상태를 얻기 위한 OpenGL 2.0 형태의 함수는 다음과 같다.
void glGetShaderiv(GLuint object, GLenum type, int *param);
Parameters:
object - 쉐이더나 프로그램에 대한 객체 핸들
type - GL_COMPILE_STATUS
param - 반환값으로써 성공이면 GL_TRUE를, 실패면 GL_FALSE
링크 단계에 대한 결과 상태를 얻기 위한 OpenGL 2.0 형태의 함수는 다음과 같다.
void glGetProgramiv(GLuint object, GLenum type, int *param);
Parameters:
object - 쉐이더나 프로그램에 대한 객체 핸들
type - GL_LINK_STATUS
param - 반환값으로써 성공이면 GL_TRUE이고 실패면 GL_FALSE
위의 OpenGL 2.0 형태의 두개의 함수에 대한 ARB 확장 함수는 하나로 대신할 수 있다.
void glGetObjectParameterivARB(GLhandleARB object, GLenum type, int *param);
Parameters:
object - 쉐이더나 프로그램에 대한 핸들
type - GL_OBJECT_LINK_STATUS_ARB 또는 GL_OBJECT_COMPILE_STATUS_ARB
param - 반환값으로써 성공이면 1, 실패면 0
위에서 언급한 함수들의 두번째 인자(type)에 대해 더 많은 옵션이 있지만, 자세한 설명은 여기서 하지 않겠다. 대신 http://developer.3dlabs.com/openGL2/index.htm를 참고하길 바란다.
에러가 발생할 경우 InfoLog를 사용해서 에러에 대한 더 많은 정보를 얻어올 수 있다. 이 로그는 수행한 마지막 연산에 대한 정보를 담고 있는데, 그 내용은 컴파일에 대한 경고나 에러 또는 링크 단계에서에서 발생한 문제들이다. 로그는 소프트웨어에서 실행될 쉐이더에 대해 더 많은 정보를 제공한다. 예를들어서 사용하고자 하는 기능이 하드웨어에서 지원하지 않는다든지, 아무런 문제가 없다든지와 같은 정보이다. 불행이도 InfoLog 메세지에 대한 스펙은 없다. 그래서 각 벤더마다 그 메세지의 내용이 다르다.
특정한 쉐이더나 프로그램에 대한 InfoLog를 얻기 위한 OpenGL 2.0 형태의 함수는 다음과 같다.
void glGetShaderInfoLog(GLuint object, int maxLen, int *len, char *log);
void glGetProgramInfoLog(GLuint object, int maxLen, int *len, char *log);
Parameters:
object - 쉐이더나 프로그램에 대한 객체 핸들
maxLen - InfoLog로부터 받을수 있는 문자의 최대 개수
len - 실제 받을 문자의 개수
log - 실제 로그 메세지 문자열
위의 함수에 대한 ARB 확장 형태는 다음과 같이 하나의 함수로 대신할 수 있다.
void glGetInfoLogARB(GLhandleARB object, int maxLen, int *len, char *log);
Parameters:
object - 쉐이더나 프로그램 객체에 대한 핸들
maxLen - InfoLog로부터 받을 수 있는 문자열의 최대 길이
len - 실제 받을 문자열의 길이
log - 실제 로그 메세지 문자열
InfoLog를 통해 얻을 정보의 정확한 길이를 알아야할 필요가 있는데, 얻는 방법은 아래의 함수와 같다. (OpenGL 2.0 형태)
void glGetShaderiv(GLuint object, GLenum type, int *param);
void glGetProgramiv(GLuint object, GLenum type, int *param);
Parameter:
object - 쉐이더나 프로그램 객체에 대한 핸들
type - GL_INFO_LOG_LENGTH
param - 반환값으로써 InfoLog의 길이
위의 함수에 대한 ARB 확장은 아래와 같다.
void glGetObjectParameterivARB(GLhandleARB object, GLenum type, int *param);
Parameters:
object - 쉐이더나 프로그램에 대한 핸들
type - GL_OBJECT_INFO_LOG_LENGTH_ARB
param - 반환값으로써 InfoLog의 길이
다음 함수는 OpenGL 2.0에서 InfoLog의 내용을 출력하는 예이다.
void printShaderInfoLog(GLuint obj)
{
int infologLength = 0;
int charsWritten = 0;
char *infoLog;
glGetShaderiv(obj, GL_INFO_LOG_LENGTH, &infologLength);
if (infologLength > 0)
{
infoLog = (char *)malloc(infologLength);
glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog);
printf("%s\n",infoLog);
free(infoLog);
}
}
void printProgramInfoLog(GLuint obj)
{
int infologLength = 0;
int charsWritten = 0;
char *infoLog;
glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infologLength);
if (infologLength > 0)
{
infoLog = (char *)malloc(infologLength);
glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog);
printf("%s\n",infoLog);
free(infoLog);
}
} ARB 확장 형태는 아래와 같다.
void printInfoLog(GLhandleARB obj)
{
int infologLength = 0;
int charsWritten = 0;
char *infoLog;
glGetObjectParameterivARB(obj,
GL_OBJECT_INFO_LOG_LENGTH_ARB, &infologLength);
if(infologLength > 0)
{
info = (char *)malloc(infologLength);
glGetInfoLogARB(obj,infologLength, &charsWritten, infoLog);
printf("%s\n", infoLog);
free(infoLog);
}
}
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/08/20 22:33
2007/08/20 22:33
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/288 |
|
|
|
|
|
|
|
GLSL을 위한 OpenGL 설정 - 예제
원본 : http://www.lighthouse3d.com/opengl/glsl/index.php?oglexample1
다음 코드는 이전 섹션에서 설명했던 모든 단계를 포함하고 있다. p, f, v는 OpenGL 2.0 문법으로는 GLuint 타입이고 ARB 확장 문법으로는 GLhandleARB 타입인 전역변수이다.
OpenGL 2.0 문법은 다음과 같다.
void setShaders() {
char *vs,*fs;
v = glCreateShader(GL_VERTEX_SHADER);
f = glCreateShader(GL_FRAGMENT_SHADER);
vs = textFileRead("toon.vert");
fs = textFileRead("toon.frag");
const char * vv = vs;
const char * ff = fs;
glShaderSource(v, 1, &vv, NULL);
glShaderSource(f, 1, &ff, NULL);
free(vs);
free(fs);
glCompileShader(v);
glCompileShader(f);
p = glCreateProgram();
glAttachShader(p,v);
glAttachShader(p,f);
glLinkProgram(p);
glUseProgram(p);
} ARB 확장 문법은 다음과 같다.
void setShaders() {
char *vs,*fs;
v = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
f = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
vs = textFileRead("toon.vert");
fs = textFileRead("toon.frag");
const char * vv = vs;
const char * ff = fs;
glShaderSourceARB(v, 1, &vv,NULL);
glShaderSourceARB(f, 1, &ff,NULL);
free(vs);
free(fs);
glCompileShaderARB(v);
glCompileShaderARB(f);
p = glCreateProgramObjectARB();
glAttachObjectARB(p,v);
glAttachObjectARB(p,f);
glLinkProgramARB(p);
glUseProgramObjectARB(p);
} OpenGL 2.0의 형태와 ARB 확장 형태에 대한 GLUT를 사용한 완전한 예제는 다음을 통해 다운로드하길 바란다.
위의 코드는 2개의 간단한 쉐이더 코드와 text 파일을 읽는 함수가 포함되어져 있다. 참고로 위의 코드를 실행하면 그 결과는 다음과 같다.
네, 툰 쉐이딩이로군요~ 약간 어슬픈 느낌이긴 하지만 말입니다.
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/08/19 01:02
2007/08/19 01:02
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/287 |
|
|
|
|
|
|
|
GLSL을 위한 OpenGL 설정 - 프로그램 만들기
원문 : http://www.lighthouse3d.com/opengl/glsl/index.php?oglprogram
다음 그림은 쉐이더 프로그램을 준비하고 실행해가는데 필요한 함수 호출 단계이다.
첫번째 단계(glCreateProgram)는 프로그램(쉐이더에 대한) 컨테이너를 위한 객체를 생성이다. 이 함수는 컨테이너에 대한 핸들을 반환한다. OpenGL 2.0 문법은 아래와 같다.
GLuint glCreateProgram(void);
ARB 확장 형태의 문법은 아래와 같다.
GLhandleARB glCreateProgramObjectARB(void);
원하는 만큼의 프로그램 컨테이너를 생성할 수 있다. 렌더링 시에 원하는 쉐이더 프로그램으로 번갈아가며 교체할 수 있고, OpenGL에서 기본적으로 제공하는 고정기능(Fixed Functionality)으로 돌아갈 수도 있다. 예를들어서, 반사 쉐이더를 이용해 주전자를 그리고, 동시에 직육면체 큐브는 OpenGL의 원래 기능인, 고정기능으로 그릴 수 있다.
다음 단계는 이전 섹션에서 생성한 쉐이더를 프로그램 컨테이너에 붙이는 glAttachShader이다. 쉐이더는 이 시점에서 컴파일될 필요가 없고, 이 단계까지는 쉐이더 소스 코드를 가지지 않아도 된다. 쉐이더를 프로그램에 붙어기 위해 필요한 것은 오로지 쉐이더 컨테이너이다.
쉐이더를 프로그램에 붙이기 위한 OpenGL 2.0 함수의 형태는 다음과 같다.
void glAttachShader(GLuint program, GLuint shader);
Parameters:
Program - 프로그램 컨테이너 핸들
shader - 프로그램 컨테이너에 붙이고자 하는 쉐이더의 핸들
ARB 확장에 대한 함수 형태는 다음과 같다.
void glAttachObjectARB(GLhandleARB program, GLhandleARB shader);
Parameters:
Program - 프로그램 컨테이너 핸들
shader - 프로그램 컨테이너에 붙이고자 하는 쉐이더의 핸들
만약, 프로그램에 버텍스와 프레그먼트 쉐이더 두개를 동시에 붙이고자 할때가 있다. 같은 프로그램에 붙이고자 하는 같은 종류의 많은 쉐이더를 가질 수 있는데, 이것은 마치 C언어로 작성된 프로그램이 많음 모듈을 가질 수 있는 것과 같은 경우이다. C언에서와 마찬가지로 각각의 쉐이더에 대해서 딱 하나의 main 함수를 가질 수 있다.
하나의 쉐이더를 여러개의 프로그램에 붙일 수 있는데, 예를들어서 동일한 버텍스 쉐이더를 여러개의 프로그램에서 사용하는 것이다.
마지막 단계는 프로그램을 링크하는 것이다. 이 단계를 수행하기 위해서 세이더는 이전 섹션에서 설명했던 것처럼 반드시 컴파일 되어져 있어야 한다. 이렇게 컴파일 되어져 있는 쉐이더를 링크해주는 OpenGL 2.0 함수는 다음과 같다.
void glLinkProgram(GLuint program);
Parameters:
program - 프로그램 컨테이너의 핸들
위의 함수를 ARB 확장 형태로 살펴보면 다음과 같다.
void glLinkProgramARB(GLhandleARB program);
Parameters:
program - 프로그램 컨테이너의 핸들
링크가 된 후에, 쉐이더의 소스는 수정될 수 있고 프로그램에 영향을 미치지 않고 다시 컴파일 되어 진다.
위의 그림에서 처럼, 프로그램이 링크되어지면 이제 실제로 프로그램은 사용할 수 있게되는데, 이것은 ARB 확장함수인 glUseProgramObjectARB나 OpenGL 2.0인 glUseProgram을 이용한다. 각 프로그램은 핸들에 할당되어져 있고, 하드웨어가 허락하는 한, 우리가 사용하길 원하는 만큼 프로그램을 링크해 놓고 사용할 수 있다.
실제 컴파일되어진 쉐이더 프로그램을 사용하는 OpenGL 2.0 형태의 함수는 다음과 같다.
void glUseProgram(GLuint prog)
Parameters:
prog - 사용하길 원하는 프로그램의 핸들이며 고정기능으로 복귀할 경우 0
ARB 확장의 형태는 다음과 같다.
void glUseProgramObjectARB(GLhandleARB prog);
Parameters:
prog - 사용하길 원하는 프로그램의 핸들이며 고정기능으로 복귀할 경우 0
만약 프로그램이 사용중이고, 다시 링크되어진다면, 자동으로 수정된 내용이 사용되도록 설정되므로, 이 함수를 다시 호출할 필요가 없다. 그리고 OpenGL의 고정기능으로 복귀할 경우에 prog 인자에 0(Zero)을 넣고 호출하면 된다.
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/08/16 23:58
2007/08/16 23:58
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/285 |
|
|
|
|
|
|
|
OpenGL Setup for GLSL- Shader 생성하기
원문 : http://www.lighthouse3d.com/opengl/glsl/index.php?oglshader
다음 그림은 쉐이더를 생성하는데 필요한 단계를 보이고 있다.
첫번째 단계(glCreateShader)는 쉐이더 컨테이너로써 수행하는 오브젝트를 생성하는 것이다. 이 함수는 컨테이너의 헨들을 반환한다.
이 함수에 대한 OpenGL 2.0 문법은 다음과 같다:
GLuint glCreateShader(GLenum shaderType);
Parameter:
shaderType - GL_VERTEX_SHADER 또는 GL_FRAGMENT_SHADER
ARB 확장문법은 다음과 같다.
GLhandleARB glCreateShaderObjectARB(GLenum shaderType);
Parameter:
shaderType - GL_VERTEX_ARB 또는 GL_FRAGMENT_SHADER_ARB
프로그램에 추가하고자 하는 만큼의 쉐이더를 생성할 수 있지만, remember that there can only be a main function for the set of vertex shaders and one main function for the set of fragment shaders in each single program.
다음 단계(glShaderSource)는 특정한 소스 코드를 추가하는 것이다. 소스 코드는 문자 배열이다.
이 함수에 대한 OpenGL 2.0에 대한 형태는 다음과 같다.
void glShaderSource(GLuint shader, int numOfString. const char** strings, int *lenOfStrings);
Parameters:
shader - 쉐이더의 핸들
numOfStrings - 문자 배열의 구성 요소 수
strings - 문자 배열
lenOfStrings - 각 문자열의 길이를 가지는 배열 또는 NUL값(문자열들이 NULL로 끝남)
다음은 이 함수에 대한 ARB 확장이다.
void glShaderSourceARB(GLhandleARB shader, int numOfStrings, const char **strings, int *lenOfStrings);
Parameters:
OpenGL 2.0 형태의 인자 설명과 동일함
최종적으로, 쉐이더는 반드시 컴파일 되어져야 한다. 세번째 단계(glCompileShader)가 쉐이더 코드를 컴파일해주며 OpenGL 2.0에서의 형태는 다음과 같다.
void glCompileShader(GLuint shader);
Parameters:
shader - 쉐이더의 핸들
다음으로 ARB 확장에 대한 형태는 다음과 같다.
void glCompileShaderARB(GLhandleARB shader);
Parameters:
shader - 쉐이더의 핸들
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/08/14 23:38
2007/08/14 23:38
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/282 |
|
|
|
|
|
|
|
OpenGL Setup for GLSL - Overview
원문: http://www.lighthouse3d.com/opengl/glsl/index.php?ogloverview
GLSL을 위한 OpenGL 설정이라는 이 섹션은 두개의 버텍스 쉐이더와 프레그먼트 쉐이더에 대해 들어봤다고 가정을 하고 진행되며 OpenGL 어플리케이션에서 이 쉐이더들을 사용기 위한 내용이다. 만약 아직까지 직접 쉐이더를 작성해보지 않았다면, 인터넷으로부터 쉐이더를 구할 많은 사이트가 있으니 참고하길 바란다. 참고 사이트는 http://www.3dshaders.com/home/가 있으며 쉐이더 개발을 위한 툴로는 Shader Designer와 RenderMonkey (원문에서는 링크가 깨져있으며 구글에서 검색해서 현재 사용가능한 사이트의 URL을 검색해보길 바란다)가 있고, 이 툴에는 매우 많은 쉐이더 예제가 있다.
OpenGL을 보면, 쉐이더 프로그램을 설정하는 것은 C 프로그램을 작성하는 흐름과 유사하다. 각 쉐이더는 C 모듈과 유사하며 이 모듈은 C언어에서 처럼 개별적으로 컴파일되어져야하고, 또 정확히 C에서처럼 프로그램에 링크되여야 한다.
ARB 확장들과 OpenGL이 이 섹션에서 사용된다. 만약에 OpenGL의 버전이 1.1 이상을 사용해 보지 않았거나 확장이 처음이라면, GLEW를 보길바란다. GLEW는 확장기능과 OpenGL 최신 함수 사용를 바로 사용할 수 있도록 해준다.
만약에 아직 OpenGL 2.0을 지원하지 않는다면, 확장을 이용해야 하는데, 필요한 확장은 아래와 같다.
- GL_ARB_fragment_shader
- GL_ARG vertex_shader
아래는 GLEW를 사용하는 GLUT 프로그램의 간단한 예제인데, 위의 두개의 확장을 사용할 수 있는지 검토하는 코드이다.
#include <GL/glew.h>
#include <GL/glut.h>
void main(int argc, char **argv) {
glutInit(&argc, argv);
...
glewInit();
if (GLEW_ARB_vertex_shader && GLEW_ARB_fragment_shader)
printf("Ready for GLSL\n");
else {
printf("Not totally ready :( \n");
exit(1);
}
setShaders();
glutMainLoop();
} OpenGL 2.0이 가능한지 검사하기 위해서 아래와 같은 코드를 사용한다.
#include <GL/glew.h>
#include <GL/glut.h>
void main(int argc, char **argv) {
glutInit(&argc, argv);
...
glewInit();
if (glewIsSupported("GL_VERSION_2_0"))
printf("Ready for OpenGL 2.0\n");
else {
printf("OpenGL 2.0 not supported\n");
exit(1);
}
setShaders();
glutMainLoop();
} 아래의 그림은 OpenGL 2.0의 함수로써 나타낸 쉐이더를 생성하는 단계를 나타내고 인데, 언급한 함수의 세부내용은 나중에 자세히 살펴보도록 하겠다.
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/08/10 02:56
2007/08/10 02:56
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/281 |
|
|
|
|
|
|
|
프래그먼트 처리기
프래그먼트 처리기는 프래그먼트 쉐이더가 실행되는 곳에 있으며 다음고 ㅏ같은 연산을 담당한다.
- 색상 및 픽셀에 대한 텍스쳐 좌표 계산
- 텍스쳐 적용
- 안개 계산
- 픽셀에 대한 조명이 필요할 경우에 노멀 계산
이 처리기에 대한 입력값은 이전 단계에서 계산되어 보간된 값들로써, 버텍스의 위치, 색상, 법선벡터 등이다.
버텍스 쉐이더에서 이러한 값들은 버텍스 하나 하나에 대해서 계산되어진다. 여기서는 프레그먼트의 내부를 다루므로 보간된 값을 필요로 한다.
버텍스 처리기에서 처럼, 프레그먼트 쉐이더를 작성하면 모든 고정 기능은 작성된 프로게먼트 쉐이더가 대신한다. 그래서 안개 기능은 고정 기능을 사용하고 텍스쳐링은 쉐이더를 사용하는 방식은 지원하지 않는다. 프로그래머는 반드시 어플리케이션이 필요로 하는 모든 효과를 코딩해야 한다.
프레그먼트 처리기는 하나의 프레그먼트에 대해서 작동을 한다. 예를 들어서, 하나의 프레그먼트를 처리하고 있을 때 또 다른 프레그먼트는 알 수 없다. 버텍스 쉐이더와 마찬가지로 이 쉐이더도 OpenGL의 상태를 접근할 수 있으므로, OpenGL 어플리케이션에서 지정된 안개의 색상값을 알아 낼 수 있다.
한가지 중요한 점은, 파이프라인 단계에서 이전에 계산되어졌으므로, 프레그먼트 쉐이더는 픽셀의 좌표를 변경할 수 없다는 것이다. 버텍스 처리기에서 모델뷰와 프로젝션 행렬이 버텍스를 변환하는데 사용했다는 것을 다시 상기하기 바란다. The viewport comes into play after that but before the fragment processor. 프레그먼트 쉐이더는 스크린 상에 위치하는 픽셀에 접근할 수 있지만 변경할 수 있는 없다.
프레그먼트 쉐이더는 2개의 출력 옵션을 갖는다.
- 프레그먼트를 무시하므로 출력은 없음
- 여러개의 메시를 렌더링할때 gl_FragColor(프레그먼트의 최종 색상)이나 gl_FragData 둘중에 하나를 계산
비록 깊이값이 필요하지 않아도 깊이값이 쓰여질 수 있는데, 이것은 이전 단계에서 이미 깊이값을 계산했기 때문이다.
프레그먼트 쉐이더는 프레임버퍼에 접근할 수 없다. 그래서 만약 블렌딩과 같은 연산은 프레그먼트 쉐이더 연산 이후에 수행되어야 한다.
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/07/30 16:49
2007/07/30 16:49
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/276 |
|
|
|
|
|
|
|
Vertex Processor
버텍스 프로세서는 버텍스 쉐이더를 실행한다. 버텍스 쉐이더의 입력은 버텍스 데이터로써, 주로 버텍스의 위치, 색, 법선벡터 등으로써 OpenGL 어플리케이션이 보내준다.
다음 OpenGL 코드는 버텍스 프로세서에게 각 버텍스에 대한 색상, 위치 값을 전달해준다.
glBegin(...);
glColor3f(0.2,0.4,0.6);
glVertex3f(-1.0,1.0,2.0);
glColor3f(0.2,0.4,0.8);
glVertex3f(1.0,-1.0,2.0);
glEnd(); 버텍스 쉐이더에서 다음과 같은 일을 할 수 있다.
- 모델뷰 행렬과 프로젝션 행렬을 이용해서 버텍스의 위치를 이동
- 노말 벡터의 변환, 그리고 필요하다면 노말 벡터의 정규화
- 텍스쳐 좌표 생성과 변환
- 버텍스에 대한 빛 또는 픽셀에 대한 빛 계산
- 색상 계산
위의 모든 연산을 수행할 필요는 없다. 그러나 일단 버텍스 쉐이더를 만들었다면 버텍스 프로세서의 전체 기능을 버텍스 쉐이더가 대신하며, 따라서 법선 변환을 수행할 수 없고 고정 기능이 텍스쳐 좌표 생성을 수행하도록 할 수 없다. 버텍스 쉐이더가 사용될때 파이프 라인의 이 단계의 필요한 모든 기능을 버텍스 쉐이더가 대신하게 된다.
이전에서 설명했던 것처럼, 버텍스 쉐이더는 버텍스간 연결성 고려에 대한 정보를 가지고 있지 않다. 그러므로 위상 데이터를 필요로 하는 연산은 버텍스 쉐이더에서 수행할 수 없다. 예를들어서, 버텍스 쉐이더가 뒷면 제외를 할 수 없는데, 버텍스 쉐이더는 버텍스 단위 연산이지 버텍스가 이루고 있는 면에 대한 연산을 할 수 없기 때문이다. 면을 알려면 버텍스간의 연결 정보를 알아야 한다. 이러한 연결정보가 바로 위상 데이터의 하나이다. 버텍스 프로세서는 개별적인 버텍스 하나 하나를 처리 하는 순간에 그 하나 이외의 나머지 버텍스를 알지 못한다.
버텍스 쉐이더는 최소한 gl_Position 이라는 변수를 변경해야만 한는데, 이 변수는 보통 모델뷰 행렬과 프로젝션 행렬을 이용한 변환이다.
버텍스 프로세서는 OpenGL 상태에 접근할 수 있어서, 예를 들어 빛을 포함하고 재질을 사용하는 연산을 수행할 수 있다. 또한 텍스쳐에 대한 정보도 접근할 수 있는데 이것은 최신 그래픽 카드에서만 허용한다. 하지만 프레임 버퍼에는 접근할 수 없다.
이 글이 도움이 되셨다면, 짧은 댓글이라도 달아주시길, 큰 힘이 됩니다. ^^*
|
김형준(Dip2K)
2007/07/27 15:13
2007/07/27 15:13
|
|
| Track this back : http://www.gisdeveloper.co.kr/trackback/273 |
|
|
|
|
«
2010/03
»
| 일 |
월 |
화 |
수 |
목 |
금 |
토 |
| |
1 |
2 |
3 |
4 |
5 |
6 |
| 7 |
8 |
9 |
10 |
11 |
12 |
13 |
| 14 |
15 |
16 |
17 |
18 |
19 |
20 |
| 21 |
22 |
23 |
24 |
25 |
26 |
27 |
| 28 |
29 |
30 |
31 |
|
|
|
|
Total : 597694
Today : 36
Yesterday : 344 |
|
|
|