shader编程-着色器中颜色基础(WebGL-Shader开发基础06)

Posted 点燃火柴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了shader编程-着色器中颜色基础(WebGL-Shader开发基础06)相关的知识,希望对你有一定的参考价值。

1. 单色背景颜色

在之前的文章中我们用一个三维向量表示颜色

vec3 line_color = vec3(1.0,1.0,0.0);
vec3 color = vec3(0.6);

用三维向量表示颜色因为正好它的三个分量可以代表RGBA格式的颜色中的Red(红色)Green(绿色)Blue(蓝色)分量,
我们在最后通常会有一句

gl_FragColor = vec4(color, 1.0);

用一个四位向量来设置颜色并赋值给全局变量gl_FragColor,最后一个参数表示Alpha通道,也就是透明度,这时整个窗口都是背景的颜色为灰色

2. 颜色根据屏幕坐标变化

如果我们以屏幕坐标的x分量来创建颜色,看看发生了什么

vec3 color = vec3(st.x);

下图是执行结果,从中可以看出窗口中从x方向的中线开始向右由黑色渐变为白色,明明我们的坐标范围是[-1,1]怎么左侧全部是黑色,也就是x轴负方向的部分全部是按0计算的,实际上计算机也是这么处理的

我们给屏幕坐标的x求一下绝对值看看什么效果

vec3 color = vec3(abs(st.x));

结果如下,可看到屏幕中的颜色沿x轴方向由白变黑再由黑变白,是因为屏幕x坐标求绝对值后的值从左到右为1.0-0.0-1.0

如果只将R分量设置为x坐标的绝对值

vec3 color = vec3(abs(st.x),0.0,0.0);//背景色

结果是这样,你可以尝试一下单独设置G分量和B分量,或者同时设置RGB看看效果

你同样可以使用一个函数例如正弦函数来改变颜色

vec3 color = vec3(sin(u_time),0.0,0.0);//背景色

运行的效果是颜色慢慢变红然后慢慢变黑不断往复,效果就不贴了,之前是可以上传gif格式图片,不懂为什么现在不支持了,传视频又要先传到某个网站在引入,这么点效果不太值当花时间,望见谅

3. 物体形状颜色

上面演示的是如何改变背景色,物体形状的颜色改变也是一样,只需要给需要的分量替换为动态的变量

vec3 color = vec3(0.6);//背景色

vec3 shapeColor = vec3(sin(u_time),1.0,0.0);//形状颜色

float pct = sdTriangleRadius(st,vec2(-0.3,0.0),vec2(0.3,0.0),vec2(0.0,0.5),0.05);

color = mix(color,shapeColor,1.0-smoothstep(0.0,0.01,pct));
gl_FragColor = vec4(color, 1.0);

这一次背景色恢复了,只有绘制的三角形的颜色不断变化

4. 借助A通道处理物体形状颜色

之前处理颜色是使用颜色与形状混合然后赋值给全局变量gl_FragColor,a通道的值设置为1.0,这次借助a通道来完成形状与颜色混合,实现是创建一个函数,有一个inout参数,该参数是一个RGBA颜色,既可以输入也可返回,在函数中创建一个临时图层,将形状写入该图层的a通道,然后使用输入输出颜色进行与该图层通过a通道混合,最后颜色通过自身返回,具体如下

void sdColorBox( in vec2 p,inout vec4 outColor )

  float dist = sdTriangleRadius(p,vec2(-0.3,0.0),vec2(0.3,0.0),vec2(0.0,0.5),0.05);
  float pct = 1.0-smoothstep(0.0,0.01,dist);

  vec3 shapeColor = vec3(sin(u_time),0.0,1.0);//定义形状颜色

  vec4 layer = vec4(shapeColor.rgb, pct);//创建图层并将形状写入a通道

  outColor = mix(outColor, layer, layer.a);//图层的a通道与原颜色混合并通过参数返回

调用过程,首先准备一个四维向量来表示初始颜色,调用函数后带有颜色的形状被混合到此变量中,这时支付要将该变量赋值给全局变量gl_FragColor即可

vec4 lastColor = vec4(0.6);

sdColorBox(st,lastColor);

gl_FragColor = lastColor;

执行结果如下,同样是绘制的三角形颜色随着时间不断变化

5. 相关代码

<body>
  <div id="container"></div>
  <script src="http://www.yanhuangxueyuan.com/versions/threejsR92/build/three.js"></script>
  <script>
    var container;
    var camera, scene, renderer;
    var uniforms;
    var vertexShader = `
      void main() 
        gl_Position = vec4( position, 1.0 );
       
    `
    var fragmentShader = `
    #ifdef GL_ES
    precision mediump float;
    #endif
    uniform float u_time;
    uniform vec2 u_mouse;
    uniform vec2 u_resolution;

    float sdTriangleRadius( in vec2 p, in vec2 p0, in vec2 p1, in vec2 p2,float cornerRadius )
    
      vec2 e0 = p1-p0, e1 = p2-p1, e2 = p0-p2;
      vec2 v0 = p -p0, v1 = p -p1, v2 = p -p2;
      vec2 pq0 = v0 - e0*clamp( dot(v0,e0)/dot(e0,e0), 0.0, 1.0 );
      vec2 pq1 = v1 - e1*clamp( dot(v1,e1)/dot(e1,e1), 0.0, 1.0 );
      vec2 pq2 = v2 - e2*clamp( dot(v2,e2)/dot(e2,e2), 0.0, 1.0 );
      float s = sign( e0.x*e2.y - e0.y*e2.x );
      vec2 d = min(min(vec2(dot(pq0,pq0), s*(v0.x*e0.y-v0.y*e0.x)),
                      vec2(dot(pq1,pq1), s*(v1.x*e1.y-v1.y*e1.x))),
                      vec2(dot(pq2,pq2), s*(v2.x*e2.y-v2.y*e2.x)));
      return -sqrt(d.x)*sign(d.y) -cornerRadius;
    


    void sdColorTriangle( in vec2 p,inout vec4 outColor )

      float dist = sdTriangleRadius(p,vec2(-0.3,0.0),vec2(0.3,0.0),vec2(0.0,0.5),0.05);
      float pct = 1.0-smoothstep(0.0,0.01,dist);
 
      vec3 shapeColor = vec3(sin(u_time),0.0,1.0);//定义形状颜色

      vec4 layer = vec4(shapeColor.rgb, pct);//创建图层并将形状写入a通道

      outColor = mix(outColor, layer, layer.a);//图层的a通道与原颜色混合并通过参数返回
    


    void main( void ) 

      //窗口坐标调整为[-1,1],坐标原点在屏幕中心
      vec2 st = (gl_FragCoord.xy * 2. - u_resolution) / u_resolution.y;

      vec3 color = vec3(0.6);//背景色

      vec3 shapeColor = vec3(sin(u_time),1.0,0.0);//形状颜色

      float pct = sdTriangleRadius(st,vec2(-0.3,0.0),vec2(0.3,0.0),vec2(0.0,0.5),0.05);
 
      color = mix(color,shapeColor,1.0-smoothstep(0.0,0.01,pct));

      gl_FragColor = vec4(color, 1.0);

      vec4 lastColor = vec4(0.6);

      sdColorTriangle(st,lastColor);

      gl_FragColor = lastColor;
    
    `

    init();
    animate();

    function init() 
      container = document.getElementById('container');

      camera = new THREE.Camera();
      camera.position.z = 1;

      scene = new THREE.Scene();

      var geometry = new THREE.PlaneBufferGeometry(2, 2);

      uniforms = 
        u_time: 
          type: "f",
          value: 1.0
        ,
        u_resolution: 
          type: "v2",
          value: new THREE.Vector2()
        ,
        u_mouse: 
          type: "v2",
          value: new THREE.Vector2()
        
      ;

      var material = new THREE.ShaderMaterial(
        uniforms: uniforms,
        vertexShader: vertexShader,
        fragmentShader: fragmentShader
      );

      var mesh = new THREE.Mesh(geometry, material);
      scene.add(mesh);

      renderer = new THREE.WebGLRenderer();
      //renderer.setPixelRatio(window.devicePixelRatio);

      container.appendChild(renderer.domElement);

      onWindowResize();
      window.addEventListener('resize', onWindowResize, false);

      document.onmousemove = function (e) 
        uniforms.u_mouse.value.x = e.pageX
        uniforms.u_mouse.value.y = e.pageY
      
    

    function onWindowResize(event) 
      renderer.setSize(800, 800);
      uniforms.u_resolution.value.x = renderer.domElement.width;
      uniforms.u_resolution.value.y = renderer.domElement.height;
    

    function animate() 
      requestAnimationFrame(animate);
      render();
    

    function render() 
      uniforms.u_time.value += 0.02;
      renderer.render(scene, camera);
    
  </script>
</body>

以上是关于shader编程-着色器中颜色基础(WebGL-Shader开发基础06)的主要内容,如果未能解决你的问题,请参考以下文章

Unity Shaders and Effects Cookbook (7-1) 在Surface Shader 中 访问 顶点颜色

在 HLSL 着色器中任意限制值时避免“如果”

片段着色器中未使用纹理数据 - OpenGL

Shader中基本光照模型

shader是啥意思

unity shader有啥好处