伪造观察者:带有文字的3D标记

时间:2017-12-31 14:03:18

标签: autodesk-forge autodesk-viewer

我们正在尝试在3D模型中每个对象顶部的特定位置(右上角)显示标记。我们还想在3D标记上渲染文本。这可能吗?如果是的话,我们会在它上面放置一个后期处理着色器,这样当我们四处走动时它就不会隐藏在模型中的其他东西下面。

选项2: 在2D中,无论是Forge还是HTML,这都是顶部有文字的图像,在每一帧中,这些图像+文本的位置必须更新以匹配3D对象的2D位置,这可能有效,但它可能会有效延迟,这就是为什么我们更喜欢使用3D选项 - 如果可能的话。

1 个答案:

答案 0 :(得分:2)

查看我最新的PointCloud Markup demo,了解使用动态纹理的自定义着色器示例:High-Performance 3D markups with PointCloud in the Forge Viewer

您可以使用类似的方法生成包含标签的纹理......

enter image description here

createShader (options) {

  // Vertex Shader code
  const vertexShader = options.vertexShader || `
      attribute float pointSize;
      attribute vec4 color;
      varying vec4 vColor;
      void main() {
        vec4 vPosition = modelViewMatrix * vec4(position, 1.0);
        gl_Position = projectionMatrix * vPosition;
        gl_PointSize = pointSize;
        vColor = color;
      }
    `

  // Fragment Shader code
  const fragmentShader = options.fragmentShader || `
      uniform sampler2D texture;
      varying vec4 vColor;
      void main() {
        vec4 tex = texture2D(texture, gl_PointCoord);
        if (tex.a < 0.2) discard;
        if (vColor.a == 0.0) {
          gl_FragColor = vec4(tex.r, tex.g, tex.b, tex.a);
        } else {
          gl_FragColor = vColor;
        }
      }
    `

  const tex = options.texture || defaultTex

  // Shader material parameters
  const shaderParams = options.shaderParams || {
      side: THREE.DoubleSide,
      depthWrite: false,
      depthTest: false,
      fragmentShader,
      vertexShader,
      opacity: 0.5,
      attributes: {
        pointSize: {
          type: 'f',
          value: []
        },
        color: {
          type: 'v4',
          value: []
        }
      },
      uniforms: {
        texture: {
          value: THREE.ImageUtils.loadTexture(tex),
          type: 't'
        }
      }
    }

  // creates shader material
  const material =
    new THREE.ShaderMaterial(
      shaderParams)

  const generateTexture = (size, radius) => {

    const pixels = []

    for (let u = 0; u < size; ++u) {

      for (let v = 0; v < size ; ++v) {

        const dist = Math.sqrt(
          (u/size - 0.5) * (u/size - 0.5) +
          (v/size - 0.5) * (v/size - 0.5))

        if (dist < 0.1) {

          pixels.push(0xff, 0x00, 0x00, 0xff)

        } else if (dist < (radius - 0.05)) {

          pixels.push(0xff, 0x00, 0x00, 0x00)

        } else if (dist < radius) {

          pixels.push(0xff, 0x00, 0x00, 0xff)

        } else {

          pixels.push(0x00, 0x00, 0x00, 0x00)
        }
      }
    }

    const dataTexture = new THREE.DataTexture (
      Uint8Array.from (pixels),
      size, size,
      THREE.RGBAFormat,
      THREE.UnsignedByteType,
      THREE.UVMapping
    )

    dataTexture.minFilter = THREE.LinearMipMapLinearFilter
    dataTexture.magFilter = THREE.LinearFilter // THREE.NearestFilter
    dataTexture.needsUpdate = true

    return dataTexture
  }

  const stopwatch = new Stopwatch()

  let radius = 0.0

  return {
    setTexture: (tex) => {

      const {texture} = shaderParams.uniforms

      texture.value = THREE.ImageUtils.loadTexture(tex)

      texture.needsUpdate = true

    },
    update: () => {

      const dt = stopwatch.getElapsedMs() * 0.001

      radius += dt * 0.25

      radius = radius > 0.5 ? 0.0 : radius

      const {texture} = shaderParams.uniforms

      texture.value = generateTexture(96, radius)

      texture.needsUpdate = true

    },
    material
  }
}