GLSL下几个简单的Shader (转载)

在ShaderDesigner下编Shader是最为方便的,但这里先用OpenGL下的编程来举例

转载自 http://blog.csdn.net/boksic

这几个Shader的实际效果:


1.最简单的固定单色Shader

Vertex Shader

坐标经过投影矩阵变换:vTrans = projection * modelview * incomingVertex

  1. void main()  
  2. {  
  3.     gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;  
  4. }  

或者更简单的方式,使用ftransform函数

  1. void main()  
  2. {  
  3.     gl_Position = ftransform();  
  4. }  

Fragment Shader

赋予像素一个固定值的颜色

  1. void main()  
  2. {  
  3.     gl_FragColor = vec4(0.4,0.4,0.8,1.0);  
  4. }  



2.颜色Shader

在OpenGL程序当中使用 glColor函数指定颜色时,接收该颜色值的Shader

例如OpenGL程序当中画一个红色茶壶:

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

glColor在Shader当中总共涉及四个值

  1. attribute vec4 gl_Color;  
  2.   
  3. varying vec4 gl_FrontColor; // writable on the vertex shader  
  4. varying vec4 gl_BackColor; // writable on the vertex shader  
  5.   
  6. 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

  1. void main()  
  2. {  
  3.     gl_FrontColor = gl_Color;  
  4.     gl_Position = ftransform();  
  5. }  


Fragment Shader

  1. void main()  
  2. {  
  3.     gl_FragColor = gl_Color;  
  4. }  



3.动态变形Shader

随着时间变动,改变渲染坐标。关键在于如何把OpenGl的变量传递给Shader

比如在OpenGL中设定一个时间变量time,初始化为0,每次渲染时增加0.1:

  1. float t = 0;  
  2. void renderScene(void) {  
  3. ...  
  4.     t += 0.001;  
  5. }  

那么将其传递给Shader需要做的是:

1.在初始化阶段使用glGetUniformLocation获取Shader里变量的存取位置

2.在渲染阶段使用glUniform给该存取位置变量赋值

  1. GLint loc;  
  2. float t = 0;  
  3. void renderScene(void) {  
  4. ...  
  5.     glUniform1f(loc, t);  
  6.     t += 0.001;  
  7. }  
  8. void setShaders() {  
  9. ...  
  10.  glUseProgram(p);  
  11.     loc = glGetUniformLocation(p, "time");  
  12. }  


最后在shader中使用时声明一下即可使用(本例当中让图形沿x轴3d翻转)

Vertex Shader

  1. uniform float time;  
  2. void main()  
  3. {  
  4.     gl_FrontColor = gl_Color;   
  5.   
  6.     vec4 v = vec4(gl_Vertex);  
  7.         v.y=v.y*cos(time)+v.y*sin(time);  
  8.         v.z=-v.y*sin(time)+cos(time)*v.z;  
  9.     gl_Position = gl_ModelViewProjectionMatrix * v;  
  10. }  

Fragment Shader

  1. void main()  
  2. {  
  3.   
  4.     gl_FragColor = gl_Color;  
  5. }  

 


4.Lambert Shader

Lambert模型下的Shader,只考虑漫反射,反射强度正比于入射光与法线方向的夹角余弦值:Io= Ld*Md*cosθ

Ld是散射光颜色(gl_LightSource[0].diffuse),Md是材质散射系数(gl_FrontMaterial.diffuse),夹角余弦cosθ可由正规化的法线向量(normal)和入射光向量(lightDir)点乘得到。

OpenGL当中可以对材质和光照的属性进行设置

  1. float lpos[4] = { 1, 0.5, 1, 0 };  
  2. float lAmb[4] = { 0.2, 0.5, 1.0, 1 };  
  3. float lDif[4] = { 0.2, 1.0, 1.0, 1 };  
  4. float lSpe[4] = { 1.0, 1.0, 1.0, 1 };   
  5.     glLightfv(GL_LIGHT0, GL_POSITION, lpos);  
  6.     glLightfv(GL_LIGHT0, GL_AMBIENT, lAmb);  
  7.     glLightfv(GL_LIGHT0, GL_DIFFUSE, lDif);  
  8.     glLightfv(GL_LIGHT0, GL_SPECULAR, lSpe);  
  1. GLfloat ambient  [] = { 0.1f, 0.1f, 0.1f, 1.0f};  
  2. GLfloat diffuse  [] = { 1.0f, 0.0f, 0.0f, 1.0f};  
  3. GLfloat specular [] = { 1.0f, 1.0f, 1.0f, 1.0f};  
  4. GLfloat shininess[] = { 0.0f};  
  5. glMaterialfv(GL_FRONT, GL_AMBIENT, ambient);  
  6. glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse);  
  7. glMaterialfv(GL_FRONT, GL_SPECULAR, specular);  
  8. glMaterialfv(GL_FRONT, GL_SHININESS, shininess);  


Vertex Shader

  1. void main() {  
  2.   
  3.     vec3 normal, lightDir;  
  4.     vec4 diffuse;  
  5.     float NdotL;  
  6.     /* 法线向量 */  
  7.     normal = normalize(gl_NormalMatrix * gl_Normal);  
  8.     /* 入射光向量*/  
  9.     lightDir = normalize(vec3(gl_LightSource[0].position));   /* cosθ */  
  10. NdotL = max(dot(normal, lightDir), 0.0);/* 散射项 */  
  11. diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;  
  12.   
  13.   gl_FrontColor = NdotL * diffuse;gl_Position = ftransform();  
  14. }  

 

Fragment Shader

 

  1. void main()  
  2. {  
  3.     gl_FragColor = gl_Color;  
  4. }  


如果再考虑上环境散射项,那么OpenGL中使用glLightfv来设定环境光

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

 

Vertex Shader

  1. void main()  
  2. {  
  3.     vec3 normal, lightDir;  
  4.     vec4 diffuse, ambient, globalAmbient;  
  5.     float NdotL;  
  6.   
  7.     normal = normalize(gl_NormalMatrix * gl_Normal);  
  8.     lightDir = normalize(vec3(gl_LightSource[0].position));  
  9.     NdotL = max(dot(normal, lightDir), 0.0);  
  10.     diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;  
  11.     /* Compute the ambient and globalAmbient terms */  
  12.   
  13.     ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;  
  14.     globalAmbient = gl_LightModel.ambient * gl_FrontMaterial.ambient;  
  15.     gl_FrontColor =  NdotL * diffuse + globalAmbient + ambient;  
  16.   
  17.     gl_Position = ftransform();  
  18. }  

 

5.Blinn-Phong Shader

Phong光照模型,考虑反射成分(specular项)。其中Shininess在OpenGL中材质可用glMaterialfv进行设置

  1. void main()  
  2. {  
  3.     vec3 normal, lightDir;  
  4.     vec4 diffuse, ambient, globalAmbient,specular;  
  5.     float NdotL;float NdotHV;  
  6.   
  7.     normal = normalize(gl_NormalMatrix * gl_Normal);  
  8.     lightDir = normalize(vec3(gl_LightSource[0].position));  
  9.     NdotL = max(dot(normal, lightDir), 0.0);  
  10.     diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;  
  11.     /* Compute the ambient and globalAmbient terms */  
  12.   
  13.     ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;  
  14.     globalAmbient = gl_LightModel.ambient * gl_FrontMaterial.ambient;  
  15.       
  16.         /* compute the specular term if NdotL is  larger than zero */  
  17.     if (NdotL > 0.0) {  
  18.   
  19.         // normalize the half-vector, and then compute the  
  20.         // cosine (dot product) with the normal  
  21.         NdotHV = max(dot(normal, gl_LightSource[0].halfVector.xyz),0.0);  
  22.         specular = gl_FrontMaterial.specular * gl_LightSource[0].specular *  
  23.                 pow(NdotHV,gl_FrontMaterial.shininess);  
  24.     }  
  25.       
  26.       
  27.     gl_FrontColor =  NdotL * diffuse + globalAmbient + ambient +specular;  
  28.   
  29.     gl_Position = ftransform();  
  30. }  


6.法线Shader

将法线方向映射到颜色空间中,可用于生成法线贴图


    1. void main()  
    2. {  
    3.     vec3 normal;  
    4.     normal = normalize(gl_NormalMatrix * gl_Normal);  
    5.     gl_FrontColor =  (vec4(normal.x,normal.y,normal.z,1.0)+1)/2;  
    6.   
    7.     gl_Position = ftransform();  

posted on 2016-07-21 20:26  不吃鱼的猫  阅读(1282)  评论(0编辑  收藏  举报