GLSL下幾個簡單的Shader

在ShaderDesigner下編Shader是最爲方便的,但這裏先用OpenGL下的編程來舉例

轉載請註明http://blog.csdn.net/boksic 如有疑問歡迎留言

這幾個Shader的實際效果:


1.最簡單的固定單色Shader

Vertex Shader

座標經過投影矩陣變換:vTrans = projection * modelview * incomingVertex

void main()
{
	gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;
}
或者更簡單的方式,使用ftransform函數

void main()
{
	gl_Position = ftransform();
}
Fragment Shader

賦予像素一個固定值的顏色

void main()
{
	gl_FragColor = vec4(0.4,0.4,0.8,1.0);
}



2.顏色Shader

在OpenGL程序當中使用 glColor函數指定顏色時,接收該顏色值的Shader

例如OpenGL程序當中畫一個紅色茶壺:

    glColor3f(1, 0, 0);
    glutSolidTeapot(1);

glColor在Shader當中總共涉及四個值

	attribute vec4 gl_Color;

	varying vec4 gl_FrontColor; // writable on the vertex shader
	varying vec4 gl_BackColor; // writable on the vertex shader

	varying vec4 gl_Color; // readable on the fragment shader


流程如下:

OpenGL程序使用glColor函數後,將顏色值以attribute gl_Color的形式傳給了Vertex Shader, Vertext Shader接受到後開始計算gl_FontColor和gl_BackColor,而在Fragment Shader則會接受到一個由FontColor和BackColor插值計算出來的varying gl_Color(注意:該gl_Color與Vertex Shader當中的不同),因而可以基於gl_Color開始計算gl_FragColor

Vertex Shader

void main()
{
	gl_FrontColor = gl_Color;
	gl_Position = ftransform();
}

Fragment Shader

void main()
{
	gl_FragColor = gl_Color;
}



3.動態變形Shader

隨着時間變動,改變渲染座標。關鍵在於如何把OpenGl的變量傳遞給Shader

比如在OpenGL中設定一個時間變量time,初始化爲0,每次渲染時增加0.1:

float t = 0;
void renderScene(void) {
...
	t += 0.001;
}
那麼將其傳遞給Shader需要做的是:

1.在初始化階段使用glGetUniformLocation獲取Shader裏變量的存取位置

2.在渲染階段使用glUniform給該存取位置變量賦值

GLint loc;
float t = 0;
void renderScene(void) {
...
    glUniform1f(loc, t);
    t += 0.001;
}
void setShaders() {
...
 glUseProgram(p);
    loc = glGetUniformLocation(p, "time");
}

最後在shader中使用時聲明一下即可使用(本例當中讓圖形沿x軸3d翻轉)

Vertex Shader

uniform float time;
void main()
{
 	gl_FrontColor = gl_Color; 

	vec4 v = vec4(gl_Vertex);
        v.y=v.y*cos(time)+v.y*sin(time);
        v.z=-v.y*sin(time)+cos(time)*v.z;
	gl_Position = gl_ModelViewProjectionMatrix * v;
}

Fragment Shader

void main()
{

	gl_FragColor = gl_Color;
}


4.Lambert Shader

Lambert模型下的Shader,只考慮漫反射,反射強度正比於入射光與法線方向的夾角餘弦值:Io= Ld*Md*cosθ

Ld是散射光顏色(gl_LightSource[0].diffuse),Md是材質散射係數(gl_FrontMaterial.diffuse),夾角餘弦cosθ可由正規化的法線向量(normal)和入射光向量(lightDir)點乘得到。

OpenGL當中可以對材質和光照的屬性進行設置

float lpos[4] = { 1, 0.5, 1, 0 };
float lAmb[4] = { 0.2, 0.5, 1.0, 1 };
float lDif[4] = { 0.2, 1.0, 1.0, 1 };
float lSpe[4] = { 1.0, 1.0, 1.0, 1 }; 
	glLightfv(GL_LIGHT0, GL_POSITION, lpos);
	glLightfv(GL_LIGHT0, GL_AMBIENT, lAmb);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, lDif);
	glLightfv(GL_LIGHT0, GL_SPECULAR, lSpe);

    GLfloat ambient  [] = { 0.1f, 0.1f, 0.1f, 1.0f};
    GLfloat diffuse  [] = { 1.0f, 0.0f, 0.0f, 1.0f};
    GLfloat specular [] = { 1.0f, 1.0f, 1.0f, 1.0f};
    GLfloat shininess[] = { 0.0f};
    glMaterialfv(GL_FRONT, GL_AMBIENT, ambient);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, shininess);


Vertex Shader

void main() {

    vec3 normal, lightDir;
    vec4 diffuse;
    float NdotL;
    /* 法線向量 */
    normal = normalize(gl_NormalMatrix * gl_Normal);
    /* 入射光向量*/
    lightDir = normalize(vec3(gl_LightSource[0].position));   /* cosθ */
NdotL = max(dot(normal, lightDir), 0.0);/* 散射項 */
diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;

  gl_FrontColor = NdotL * diffuse;gl_Position = ftransform();
}

Fragment Shader

void main()
{
	gl_FragColor = gl_Color;
}


如果再考慮上環境散射項,那麼OpenGL中使用glLightfv來設定環境光

float lpos[4] = { 1, 0.5, 1, 0 };
float lAmb[4] = { 0.2, 0.5, 1, 1 };
void renderScene(void) {
...
	glLightfv(GL_LIGHT0, GL_POSITION, lpos);
	glLightfv(GL_LIGHT0, GL_AMBIENT, lAmb);
...
}

Vertex Shader

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

5.Blinn-Phong Shader

Phong光照模型,考慮反射成分(specular項)。其中Shininess在OpenGL中材質可用glMaterialfv進行設置

void main()
{
    vec3 normal, lightDir;
    vec4 diffuse, ambient, globalAmbient,specular;
    float NdotL;float NdotHV;

    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;
    
        /* 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);
    }
    
    
    gl_FrontColor =  NdotL * diffuse + globalAmbient + ambient +specular;

    gl_Position = ftransform();
}

6.法線Shader

將法線方向映射到顏色空間中,可用於生成法線貼圖


void main()
{
	vec3 normal;
	normal = normalize(gl_NormalMatrix * gl_Normal);
	gl_FrontColor =  (vec4(normal.x,normal.y,normal.z,1.0)+1)/2;

	gl_Position = ftransform();
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章