首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >动画线框线条

动画线框线条
EN

Stack Overflow用户
提问于 2019-03-04 23:54:32
回答 1查看 305关注 0票数 0

我只是好奇,有没有人知道如何实现这样的线框“淡入”绘制逐行效果?

可能不是很精确,但类似于这样的svg动画,使它更清晰,更容易可视化https://maxwellito.github.io/vivus/

如果你在幻灯片之间切换,这里的Webgl示例https://www.orano.group/experience/innovation/en/slider

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-03-05 02:12:50

你需要给每个你想要画的元素按照你想画的顺序给它们一个数字。例如,如果要按绘制顺序为每个顶点绘制线框过程,请将该数字从顶点着色器传递到片段着色器,然后再传递一次。如果数字大于数字discard (或者以其他方式不绘制)

示例:

代码语言:javascript
运行
复制
'use strict';

/* global THREE */

function main() {
  const canvas = document.querySelector('#c');
  const renderer = new THREE.WebGLRenderer({canvas: canvas});

  const fov = 40;
  const aspect = 2;  // the canvas default
  const near = 0.1;
  const far = 1000;
  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  camera.position.z = 25;

  const scene = new THREE.Scene();
  scene.background = new THREE.Color('white');

  const objects = [];

  {
    const width = 8;
    const height = 8;
    const depth = 8;
    // using edges just to get rid of the lines triangles
    const geometry = new THREE.EdgesGeometry(new THREE.BoxBufferGeometry(width, height, depth));
    const numVertices = geometry.getAttribute('position').count;
    const counts = new Float32Array(numVertices);
    // every 2 points is one line segment so we want the numbers to go
    // 0, 1, 1, 2, 2, 3, 3, 4, 4, 5 etc
    const numSegments = numVertices / 2;
    for (let seg = 0; seg < numSegments; ++seg) {
      const off = seg * 2;
      counts[off + 0] = seg;
      counts[off + 1] = seg + 1;
    }
    const itemSize = 1;
    const normalized = false;
    const colorAttrib = new THREE.BufferAttribute(counts, itemSize, normalized);     geometry.addAttribute('count', colorAttrib);
    
    const timeLineShader = {
      uniforms: {
        color: { value: new THREE.Color('red'), },
        time: { value: 0 },
      },
      vertexShader: `
        attribute float count;
        varying float vCount;
        void main() {
          vCount = count;
          gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1);
        }
      `,
      fragmentShader: `
        #include <common>

        varying float vCount;
        uniform vec3 color;
        uniform float time;

        void main() {
          if (vCount > time) {
            discard;
          }
          gl_FragColor = vec4(color, 1);
        }
      `,
    };
   
    const material = new THREE.ShaderMaterial(timeLineShader);
    const mesh = new THREE.LineSegments(geometry, material);
    scene.add(mesh);
    objects.push(mesh);
  }

  function resizeRendererToDisplaySize(renderer) {
    const canvas = renderer.domElement;
    const width = canvas.clientWidth;
    const height = canvas.clientHeight;
    const needResize = canvas.width !== width || canvas.height !== height;
    if (needResize) {
      renderer.setSize(width, height, false);
    }
    return needResize;
  }

  function render(time) {
    time *= 0.001;

    if (resizeRendererToDisplaySize(renderer)) {
      const canvas = renderer.domElement;
      camera.aspect = canvas.clientWidth / canvas.clientHeight;
      camera.updateProjectionMatrix();
    }

    objects.forEach((obj, ndx) => {
      const speed = .1 + ndx * .05;
      const rot = time * speed;
      obj.rotation.x = rot;
      obj.rotation.y = rot;
      obj.material.uniforms.time.value = (time * 4) % 15;
    });

    renderer.render(scene, camera);

    requestAnimationFrame(render);
  }

  requestAnimationFrame(render);
}

main();
代码语言:javascript
运行
复制
body { margin: 0; }
#c { width: 100vw; height: 100vh; display: block; }
代码语言:javascript
运行
复制
<canvas id="c"></canvas>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r98/three.min.js"></script>

如果想要连续绘制多个对象,只需调整每个对象的时间

代码语言:javascript
运行
复制
'use strict';

/* global THREE */

function main() {
  const canvas = document.querySelector('#c');
  const renderer = new THREE.WebGLRenderer({canvas: canvas});

  const fov = 40;
  const aspect = 2;  // the canvas default
  const near = 0.1;
  const far = 1000;
  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  camera.position.z = 15;

  const scene = new THREE.Scene();
  scene.background = new THREE.Color('white');

  const objects = [];

  {
    const width = 2;
    const height = 2;
    const depth = 2;
    // using edges just to get rid of the lines triangles
    const geometry = new THREE.EdgesGeometry(new THREE.BoxBufferGeometry(width, height, depth));
    const numVertices = geometry.getAttribute('position').count;
    const counts = new Float32Array(numVertices);
    // every 2 points is one line segment so we want the numbers to go
    // 0, 1, 1, 2, 2, 3, 3, 4, 4, 5 etc
    const numSegments = numVertices / 2;
    for (let seg = 0; seg < numSegments; ++seg) {
      const off = seg * 2;
      counts[off + 0] = seg;
      counts[off + 1] = seg + 1;
    }
    const itemSize = 1;
    const normalized = false;
    const colorAttrib = new THREE.BufferAttribute(counts, itemSize, normalized);     geometry.addAttribute('count', colorAttrib);
    
    const timeLineShader = {
      vertexShader: `
        attribute float count;
        varying float vCount;
        void main() {
          vCount = count;
          gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1);
        }
      `,
      fragmentShader: `
        #include <common>

        varying float vCount;
        uniform vec3 color;
        uniform float time;

        void main() {
          if (vCount > time) {
            discard;
          }
          gl_FragColor = vec4(color, 1);
        }
      `,
    };
   
    for (let x = -2; x <= 2; x += 1) {
      timeLineShader.uniforms = {
        color: { value: new THREE.Color('red'), },
        time: { value: 0 },
      };
      const material = new THREE.ShaderMaterial(timeLineShader);
      const mesh = new THREE.LineSegments(geometry, material);
      scene.add(mesh);
      mesh.position.x = x * 4;
      objects.push(mesh);
    }
  }

  function resizeRendererToDisplaySize(renderer) {
    const canvas = renderer.domElement;
    const width = canvas.clientWidth;
    const height = canvas.clientHeight;
    const needResize = canvas.width !== width || canvas.height !== height;
    if (needResize) {
      renderer.setSize(width, height, false);
    }
    return needResize;
  }

  function render(time) {
    time *= 0.001;

    if (resizeRendererToDisplaySize(renderer)) {
      const canvas = renderer.domElement;
      camera.aspect = canvas.clientWidth / canvas.clientHeight;
      camera.updateProjectionMatrix();
    }

    objects.forEach((obj, ndx) => {
      const rotSpeed = .1;
      const rot = time * rotSpeed;
      obj.rotation.x = rot;
      obj.rotation.y = rot;
      const segmentsPer = 12;
      const speed = 8;
      const totalTime = segmentsPer * objects.length + 5 * speed;
      obj.material.uniforms.time.value = ((time * speed) % totalTime) - ndx * segmentsPer;
    });

    renderer.render(scene, camera);

    requestAnimationFrame(render);
  }

  requestAnimationFrame(render);
}

main();
代码语言:javascript
运行
复制
body { margin: 0; }
#c { width: 100vw; height: 100vh; display: block; }
代码语言:javascript
运行
复制
<canvas id="c"></canvas>
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r98/three.min.js"></script>

请注意,使用计数将使每个段花费相同的时间才能显示。如果希望它们的距离比每条线段加1所需的时间更长,则需要将距离添加到下一个点

代码语言:javascript
运行
复制
distanceSoFar = 0;
for each segment
  data.push(distanceSoFar);
  distanceSoFar += distance(segmentStartPosition, segmentEndPosition); 
  data.push(distanceSoFar);
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54986860

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档