本帖最后由 chyx 于 2016-10-28 20:21 编辑

我在mcforum上逛的时候看见了一个貌似不错的教程 感到有趣 于是决定尽我所能翻译它 如有任何错误请指出 谢谢
希望不会已经有人翻译过了
有glsl问题不要问我
这只是一个基础教程 会光影的大神请绕路
原文minecraftforum.net/forums/resource-pack-discussion/1255965

@tsd1 @719220502 @⊙v⊙ @乙烯_中国 @719823597 @pacerrecap @pca006132
章节
  • 着色器导论
  • 计算机如何理解颜色
  • 向量
  • glsl数据类型和声明变量
  • glsl格式
  • 函数
  • 例子
  • minecraft着色器文件系统


第一节 着色器导论
在你开始前,你需要对着色器有个概念。着色器是一段在显示器显示前修改3d的对象的代码。着色器有两种,分别是顶点着色器和片元着色器。顶点着色器修改3d对象的几何尺寸,而片元着色器修改画到屏幕的像素。在原版minecraft中,着色器访问不了3d尺寸,所以你完全不用理会顶点着色器。
这是一个最简单的片元着色器:
  1. uniform sampler2D DiffuseSampler;
  2. varying vec2 texCoord;
  3. void main() {
  4. gl_FragColor = texture2D(DiffuseSampler, texCoord);
  5. }
复制代码
这两行
  1. uniform sampler2D DiffuseSampler;
  2. varying vec2 texCoord;
复制代码
是着色器的输入。"DiffuseSampler"是minecraft游戏的图案,而texCoord是我们正在编辑的像素的位置。为了获得该像素的颜色,你需要使用"texture2D"函数。他需要一个图片和一个坐标,并且他返回该图片在该坐标处的位置。
"gl_FragColor"是着色器的输出。它的值就是将要显示的颜色。

第二节 计算机如何理解颜色
现在,为了让你知道如何编辑颜色,你需要懂得计算机是如何理解颜色的。
每个屏幕上的像素由三色光组成。分别是红光、绿光和蓝光。
在着色器里,1代表完全点亮,0表示完全熄灭,0.5表示半亮半灭。
三个颜色总是按照红绿蓝的顺序排列的。(这就是RGB这个词的来源)
(1,1,1) 代表白色
(0,0,0) 代表黑色
(1,0,0) 代表红色
(0,1,0) 代表绿色
(0,0.5,0) 代表深绿色
在你继续前请确保你熟练掌握RGB。

第三节 向量
向量是一组数,glsl中的颜色是用向量表示的。对向量做乘法就是把他的各个分量分别乘起来。
例如:
(1,2,3) x (1,2,3) = (1,4,9)

你也可以用一个数来乘向量。这就是用向量的各个分量分别乘以这个数。
(1,2,3) x 4 = (4,8,12)


第四节 glsl数据类型和声明变量
glsl有许多数据类型,包括向量。
向量可以是各种不同的大小,这是创建他们的方法:

vec2(1.0,1.0)
vec3(1.0,1.0,1.0)
vec4(1.0,1.0,1.0,1.0)

通常使用vec4来表示颜色
每个分量都在0和1之间
这些数依次代表红绿蓝和透明度。
透明度是颜色透明的程度。若他是0,颜色是不可见的。若他是0.5,他是半透明的。等等。
注意:永远要在你用的所有的数后面加上小数位。glsl对待整数和浮点数是不一样的。把它们混在一起会引起BUG。

这是你在glsl中声明一个变量的方法(如果你不知道啥是变量,Google它)。
  1. [type] [name] = [value];
复制代码


你可以用的type包括向量:"vec2","vec3","vec4"
还有数:"float","int" (除非你知道你在干什么,不要用int)
例如:
  1. vec4 myColor = vec4(1.0,1.0,1.0,1.0);
  2. float myNumber = 3.0;
复制代码

注意:每个操作后面都要有一个分号:";"


第五节 glsl格式
让我们回到我们最初的例子
  1. uniform sampler2D DiffuseSampler;
  2. varying vec2 texCoord;
  3. void main() {
  4. gl_FragColor = texture2D(DiffuseSampler, texCoord);
  5. }
复制代码


我们将像素点的颜色存储到变量中。
  1. uniform sampler2D DiffuseSampler;
  2. varying vec2 texCoord;
  3. void main() {
  4. vec4 color = texture2D(DiffuseSampler, texCoord);
  5. gl_FragColor = color;
  6. }
复制代码


glsl拥有这些运算
加: +
减: -
乘: *
除: /
我们用*将这颜色乘以一个系数
  1. uniform sampler2D DiffuseSampler;
  2. varying vec2 texCoord;
  3. void main() {
  4. vec4 color = texture2D(DiffuseSampler, texCoord);
  5. gl_FragColor = color*1.5;
  6. }
复制代码


如果我们只想将图中红色分量放大呢?
  1. uniform sampler2D DiffuseSampler;
  2. varying vec2 texCoord;
  3. void main() {
  4. vec4 color = texture2D(DiffuseSampler, texCoord);
  5. gl_FragColor = color*vec4(1.5,1.0,1.0,1.0);
  6. }
复制代码



你可以像这样获得 color 的各个分量
color.r
color.g
color.b
color.a
下面是你在黑白着色器中使用它的方法:
  1. uniform sampler2D DiffuseSampler;
  2. varying vec2 texCoord;
  3. void main() {
  4. vec4 color = texture2D(DiffuseSampler, texCoord);
  5. vec4 average = (color.r+color.g+color.b)/3.0;
  6. gl_FragColor = vec4(average,average,average,1.0);
  7. }
复制代码

译注 原文如此  中间的vec4 average那里似乎是float average
(notice how you can use parentheses)

你也可使用xyzw获得向量的分量
如果一个向量代表坐标 你就可以这样获得x坐标
vector.x;
你也可以用这个输出多个量 比如说 这个着色器对换红色和蓝色通道

  1. uniform sampler2D DiffuseSampler;
  2. varying vec2 texCoord;
  3. void main() {
  4. vec4 color = texture2D(DiffuseSampler, texCoord);
  5. gl_FragColor = color.bgra;
  6. }
复制代码



glsl也可以使用条件语句


  1. if(color<3){

  2. }else{

  3. }
复制代码


还有循环 (大括号中所有语句会执行5次)


  1. float i;
  2. for (i = 0; i < 5.0; i++){

  3. }
复制代码




第六节 函数
你能够让一些代码重复使用(通常称为函数或子程序)
  1. vec4 brighten( vec4 input )
  2. {
  3.         vec4 output  =  input*1.5;
  4.         return output;
  5. }
复制代码


接下来 你就可以任意使用它了 像这样
  1. vec4 newColor = brighten(color);
复制代码


这里有一些有用的程序


  1. vec4 RGBtoHSL( vec4 col )
  2. {
  3.         float red   = col.r;
  4.         float green = col.g;
  5.         float blue  = col.b;
  6.         float minc  = min(min( col.r, col.g),col.B) ;
  7.         float maxc  = max(max( col.r, col.g),col.B);
  8.         float delta = maxc - minc;
  9.         float lum = (minc + maxc) * 0.5;
  10.         float sat = 0.0;
  11.         float hue = 0.0;
  12.         if (lum > 0.0 &amp;amp;&amp;amp; lum < 1.0) {
  13.                 float mul = (lum < 0.5)  ?  (lum)  :  (1.0-lum);
  14.                 sat = delta / (mul * 2.0);
  15.         }
  16.         vec3 masks = vec3(
  17.                 (maxc == red   &amp;amp;&amp;amp; maxc != green) ? 1.0 : 0.0,
  18.                 (maxc == green &amp;amp;&amp;amp; maxc != blue)  ? 1.0 : 0.0,
  19.                 (maxc == blue  &amp;amp;&amp;amp; maxc != red)   ? 1.0 : 0.0
  20.         );
  21.         vec3 adds = vec3(
  22.                           ((green - blue ) / delta),
  23.                 2.0 + ((blue  - red  ) / delta),
  24.                 4.0 + ((red   - green) / delta)
  25.         );
  26.         float deltaGtz = (delta > 0.0) ? 1.0 : 0.0;
  27.         hue += dot( adds, masks );
  28.         hue *= deltaGtz;
  29.         hue /= 6.0;
  30.         if (hue < 0.0)
  31.                 hue += 1.0;
  32.         return vec4( hue, sat, lum, col.a );
  33. }
复制代码
译注 原文如此  中间的amp那里似乎是逻辑与&&



  1. vec4 HSLtoRGB( vec4 col )
  2. {
  3.     const float onethird = 1.0 / 3.0;
  4.     const float twothird = 2.0 / 3.0;
  5.     const float rcpsixth = 6.0;

  6.     float hue = col.x;
  7.     float sat = col.y;
  8.     float lum = col.z;

  9.     vec3 xt = vec3(
  10.         rcpsixth * (hue - twothird),
  11.         0.0,
  12.         rcpsixth * (1.0 - hue)
  13.     );

  14.     if (hue < twothird) {
  15.         xt.r = 0.0;
  16.         xt.g = rcpsixth * (twothird - hue);
  17.         xt.b = rcpsixth * (hue      - onethird);
  18.     }

  19.     if (hue < onethird) {
  20.         xt.r = rcpsixth * (onethird - hue);
  21.         xt.g = rcpsixth * hue;
  22.         xt.b = 0.0;
  23.     }

  24.     xt = min( xt, 1.0 );

  25.     float sat2   =  2.0 * sat;
  26.     float satinv =  1.0 - sat;
  27.     float luminv =  1.0 - lum;
  28.     float lum2m1 = (2.0 * lum) - 1.0;
  29.     vec3  ct     = (sat2 * xt) + satinv;

  30.     vec3 rgb;
  31.     if (lum >= 0.5)
  32.          rgb = (luminv * ct) + lum2m1;
  33.     else rgb =  lum    * ct;

  34.     return vec4( rgb, col.a );
  35. }
复制代码


第七节 例子
一个简单的爆炸着色器

  1. uniform sampler2D DiffuseSampler;
  2. varying vec2 texCoord;


  3. //width of steps (higher numbers make quality worse)
  4. const float blurWidth=0.001;

  5. //number of steps (higher numbers cause more lag)
  6. const float blurSteps=8.0;

  7. //bloom brightness
  8. const float amount=1.0;

  9. void main() {
  10.     vec4 color=texture2D(DiffuseSampler, texCoord);
  11.     float brightness=(color.r+color.g+color.b)/3.0;

  12.     vec4 sum = vec4(0);
  13.     float j;
  14.     float i;
  15.     const float foo = 10.0/(   ((blurSteps*2.0)+1.0)*((blurSteps*2.0)+1.0)   );


  16.     for( i= -blurSteps ;i < blurSteps; i++){
  17.         for (j = -blurSteps; j < blurSteps; j++){
  18.             sum += texture2D(DiffuseSampler, texCoord + vec2(j, i)*blurWidth);
  19.         }
  20.     }

  21.     sum*=foo;
  22.     vec4 modifier = sum*sum*(0.015-(brightness*0.01));
  23.     vec4 outputColor = modifier*amount + color;

  24.     gl_FragColor = outputColor;
  25. }
复制代码



原版着色器可以放在资源包里
这里有一个你能够魔改的范例着色器材质
http://pack.maloweb.com/willpackshaders.zip









未完待续。。。