three.js shader例子

使用 shader 绘制 五角星线段,mix 合并图层

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>五角星线段</title>
  <script src="../external/three.js"></script>
  <script src="../controls/OrbitControls.js"></script>
  <style>
    body {
      overflow: hidden;
      padding: 0;
      margin: 0;
    }
  </style>
</head>
<body>
<div id="container"></div>

<script id="vertexShader" type="x-shader/x-vertex">
  varying vec2 pos;
  void main() {
    pos = (vec2(position) + 1.0) * 0.5;
    mat4 mvp = projectionMatrix * modelViewMatrix;
    gl_Position = mvp * vec4( position, 1.0 );
  }
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
  uniform vec2 u_resolution;
  uniform float u_time;
  varying vec2 pos;

  vec4 _OutlineColor = vec4(1.0,1.0,1.0,1.0);
  vec4 _FrontColor = vec4(1.0,0.0,0.0,1.0);

  float pi=3.14159;
  float _Antialias=0.01;

  //画点
  vec4 circle(vec2 pos, vec2 center, float radius, vec4 color) {
    //求点是否在圆的半径内
    float d = length(pos - center) - radius;
    //fwidth(x) ==abs(ddx(x)) + abs(ddy(x)),对点求偏导,这种处理能让数据变平滑
    float w = fwidth(0.5*d) * 2.0;
    //图层0 画圆外边框
    vec4 layer0 = vec4(_OutlineColor.rgb, 1.0-smoothstep(-w, w, d - _Antialias));
    //图层1 画内圆
    vec4 layer1 = vec4(color.rgb, 1.0-smoothstep(0.0, w, d));
    //混合两个图层并返回
    return mix(layer0, layer1, layer1.a);
//    return layer0;
  }
  //画线
  vec4 line(vec2 pos, vec2 point1, vec2 point2, float width) {
    //分别求出点二到点一以及当前点到点一的向量
    vec2 dir0 = point2 - point1;
    vec2 dir1 = pos - point1;
    //dot()方法返回两个向量的点积 如果向量垂直返回0,平行返回1 相反返回-1
    //clamp()方法限制返回0到1 截出线段,不然会返回直线
    //这公式返回点到线上的距离
    float h = clamp(dot(dir1, dir0)/dot(dir0, dir0), 0.0, 1.0);
    //判断点是否在线的两边范围内
    float d = (length(dir1 - dir0 * h) - width * 0.5);
    //平滑处理
    float w = fwidth(0.5*d) * 2.0;
    //画线的外边
    vec4 layer0 = vec4(_OutlineColor.rgb, 1.-smoothstep(-w, w, d - _Antialias));
    //画线
    vec4 layer1 = vec4(_FrontColor.rgb, 1.-smoothstep(-w, w, d));
    //混合两个图层
    return mix(layer0, layer1, layer1.a);
  }

  //根据index来保存图层的颜色值
  void setlayer(inout vec4 layer[5],int index,vec4 val){
    if(index==0)
    layer[0]=val;
    if(index==1)
    layer[1]=val;
    if(index==2)
    layer[2]=val;
    if(index==3)
    layer[3]=val;
    if(index==4)
    layer[4]=val;
  }

  void main() {
    vec2 uv = pos * 3.0 - 1.5;
    //动态背景颜色
    vec3 col = 0.5 + 0.5*cos(u_time+uv.xyx+vec3(0.0, 2.0, 4.0));
    vec4 fragColor=vec4(col,1.0);
    //点的图层
    vec4 layers[5];
    float d=u_time*10.0;
    //保存五个点 从1开始
    vec2 degree[6];
    //for循环创建五个点
    for(int i=0;i<=4;i++){
      //保存点
      //坐标上圆边上的点的坐标(cos(r),sin(r)) r为弧度
      degree[i+1]=vec2(cos(d*pi/180.0),sin((d*pi)/180.0));
      //绘制点
      setlayer(layers, i, circle(uv, degree[i+1], 0.06, _FrontColor) );
      //圆上的五角星,每个点相隔72度
      d+=72.0;
    }
    //for循环画五条线
    for(int i=1;i<6;i++){
      vec2 point1=vec2(0.0,0.0);
      //判断连线的位置 即当前点的隔一个点
      if(i<=2) {
        point1=degree[i+3];
      } else {
        point1=degree[i-2];
      }
      //画线
      vec4 temp=line(uv,degree[i],point1,0.02);
      //混合线的图层
      fragColor=mix(fragColor, temp, temp.a);
    }
    //混合点的图层
    for (int i = 4; i >= 0; i--) {
      fragColor = mix(fragColor, layers[i], layers[i].a);
    }
    gl_FragColor = fragColor;
  }
</script>
<script>
  //https://blog.csdn.net/ssssssilver/article/details/81166233
  var container;
  var camera, scene, renderer;
  var uniforms;

  init();
  animate();

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

    camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
    camera.position.set(0, 0, 2);

    scene = new THREE.Scene();
    scene.add(new THREE.AxesHelper(20));

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

    uniforms = {
      u_time: { type: "f", value: 1.0 },
      u_resolution: { type: "v2", value: new THREE.Vector2(window.innerWidth, window.innerHeight) }
    };

    var material = new THREE.ShaderMaterial( {
      uniforms: uniforms,
      side: THREE.DoubleSide,
      vertexShader: document.getElementById( 'vertexShader' ).textContent,
      fragmentShader: document.getElementById( 'fragmentShader' ).textContent
    } );
    material.extensions.derivatives = true;
    var material2 = new THREE.MeshBasicMaterial({color: '#00bbbb', wireframe: true, side: THREE.DoubleSide})

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

    renderer = new THREE.WebGLRenderer();
    renderer.setPixelRatio( window.devicePixelRatio );
    renderer.setClearColor( '#f4f4f4', 1 );

    container.appendChild( renderer.domElement );
    let orbit = new THREE.OrbitControls( camera, renderer.domElement );

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

  function onWindowResize( event ) {
    renderer.setSize( window.innerWidth, window.innerHeight );
    // 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>
</html>

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>雨伞</title>
  <script src="../lib/three.js"></script>
  <script src="../lib/OrbitControls.js"></script>
  <style>
    body {
      overflow: hidden;
      padding: 0;
      margin: 0;
    }
  </style>
</head>
<body>
<div id="container"></div>

<script id="vertexShader" type="x-shader/x-vertex">
  varying vec2 pos;
  void main() {
    pos = (vec2(position) + 1.0) * 0.5;
    mat4 mvp = projectionMatrix * modelViewMatrix;
    gl_Position = mvp * vec4( position, 1.0 );
  }
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
  uniform vec2 u_resolution;
  uniform float u_time;
  varying vec2 pos;

  float sdfCircle(vec2 center, float radius, vec2 coord ) {
    vec2 offset = coord - center;

    return sqrt((offset.x * offset.x) + (offset.y * offset.y)) - radius;
  }

  float sdfEllipse(vec2 center, float a, float b, vec2 coord) {
    float a2 = a * a;
    float b2 = b * b;
    return (b2 * (coord.x - center.x) * (coord.x - center.x) +
    a2 * (coord.y - center.y) * (coord.y - center.y) - a2 * b2)/(a2 * b2);
  }

  float sdfLine(vec2 p0, vec2 p1, float width, vec2 coord) {
    vec2 dir0 = p1 - p0;
    vec2 dir1 = coord - p0;
    float h = clamp(dot(dir0, dir1)/dot(dir0, dir0), 0.0, 1.0);
    return (length(dir1 - dir0 * h) - width * 0.5);
  }

  float sdfUnion( const float a, const float b ) {
    return min(a, b);
  }

  float sdfDifference( const float a, const float b) {
    return max(a, -b);
  }

  float sdfIntersection( const float a, const float b ) {
    return max(a, b);
  }

  vec4 render(float d, vec3 color, float stroke) {
    //stroke = fwidth(d) * 2.0;
    float anti = fwidth(d) * 1.0;
    vec4 strokeLayer = vec4(vec3(0.05), 1.0-smoothstep(-anti, anti, d - stroke));
    vec4 colorLayer = vec4(color, 1.0-smoothstep(-anti, anti, d));

    if (stroke < 0.000001) {
      return colorLayer;
    }
    return vec4(mix(strokeLayer.rgb, colorLayer.rgb, colorLayer.a), strokeLayer.a);
  }

  void main() {
    float pixSize = 1.0 / 512.0;
    vec2 uv = pos;
    float stroke = pixSize * 1.5;
    vec2 center = vec2(0.5, 0.5 );

    float a = sdfEllipse(vec2(0.5, center.y*2.0-0.34), 0.25, 0.25, uv);
    float b = sdfEllipse(vec2(0.5, center.y*2.0+0.03), 0.8, 0.35, uv);
    b = sdfIntersection(a, b);
    vec4 layer1 = render(b, vec3(0.32, 0.56, 0.53), fwidth(b) * 2.0);

    // Draw strips
    vec4 layer2 = layer1;
    float t, r0, r1, r2, e, f;
    vec2 sinuv = vec2(uv.x, (sin(uv.x*40.0)*0.02 + 1.0)*uv.y);
    for (float i = 0.0; i < 10.0; i++) {
      t = mod(3.14 + 0.3 * i, 3.0) * 0.2;
      r0 = (t - 0.15) / 0.2 * 0.9 + 0.1;
      r1 = (t - 0.15) / 0.2 * 0.1 + 0.9;
      r2 = (t - 0.15) / 0.2 * 0.15 + 0.85;
      e = sdfEllipse(vec2(0.5, center.y*2.0+0.37-t*r2), 0.7*r0, 0.35*r1, sinuv);
      f = sdfEllipse(vec2(0.5, center.y*2.0+0.41-t), 0.7*r0, 0.35*r1, sinuv);
      f = sdfDifference(e, f);
      f = sdfIntersection(f, b);
      vec4 layer = render(f, vec3(1.0, 0.81, 0.27), 0.0);
      layer2 = mix(layer2, layer, layer.a);
    }


    // Draw the handle
    float bottom = 0.08;
    float handleWidth = 0.01;
    float handleRadius = 0.04;
    float d = sdfCircle(vec2(0.5-handleRadius+0.5*handleWidth, bottom), handleRadius, uv);
    float c = sdfCircle(vec2(0.5-handleRadius+0.5*handleWidth, bottom), handleRadius-handleWidth, uv);
    d = sdfDifference(d, c);
    c = uv.y - bottom;
    d = sdfIntersection(d, c);
    c = sdfLine(vec2(0.5, center.y*2.0-0.05), vec2(0.5, bottom), handleWidth, uv);
    d = sdfUnion(d, c);
    c = sdfCircle(vec2(0.5, center.y*2.0-0.05), 0.01, uv);
    d = sdfUnion(c, d);
    c = sdfCircle(vec2(0.5-handleRadius*2.0+handleWidth, bottom), handleWidth*0.5, uv);
    d = sdfUnion(c, d);
    vec4 layer0 = render(d, vec3(0.404, 0.298, 0.278), stroke);

    vec2 p = 2.0*uv - 1.0;
    vec3 bcol = vec3(1.0,0.8,0.7-0.07*p.y)*(1.0-0.25*length(p));
    vec4 fragColor = vec4(bcol, 1.0);
    fragColor.rgb = mix(fragColor.rgb, layer0.rgb, layer0.a);
    fragColor.rgb = mix(fragColor.rgb, layer1.rgb, layer1.a);
    fragColor.rgb = mix(fragColor.rgb, layer2.rgb, layer2.a);

    fragColor.rgb = pow(fragColor.rgb, vec3(1.0/2.2));
    gl_FragColor = fragColor;
  }
</script>
<script>
  //https://blog.csdn.net/ssssssilver/article/details/81166233
  var container;
  var camera, scene, renderer;
  var uniforms;

  init();
  animate();

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

    camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
    camera.position.set(0, 0, 2);

    scene = new THREE.Scene();
    scene.add(new THREE.AxesHelper(20));

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

    uniforms = {
      u_time: { type: "f", value: 1.0 },
      u_resolution: { type: "v2", value: new THREE.Vector2(window.innerWidth, window.innerHeight) }
    };

    var material = new THREE.ShaderMaterial( {
      uniforms: uniforms,
      side: THREE.DoubleSide,
      vertexShader: document.getElementById( 'vertexShader' ).textContent,
      fragmentShader: document.getElementById( 'fragmentShader' ).textContent
    } );
    material.extensions.derivatives = true;
    var material2 = new THREE.MeshBasicMaterial({color: '#00bbbb', wireframe: true, side: THREE.DoubleSide})

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

    renderer = new THREE.WebGLRenderer();
    renderer.setPixelRatio( window.devicePixelRatio );
    renderer.setClearColor( '#f4f4f4', 1 );

    container.appendChild( renderer.domElement );
    let orbit = new THREE.OrbitControls( camera, renderer.domElement );

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

  function onWindowResize( event ) {
    renderer.setSize( window.innerWidth, window.innerHeight );
    // 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>
</html>

https://sites.google.com/site/webglbook/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值