2017-12-31 204 views
0

3Dモデルの各オブジェクトの上に特定の場所(右上)にマークアップを表示しようとしています。また、3Dマークアップ上にテキストをレンダリングする必要があります。これは可能ですか?そうであれば、ポストプロセッシングシェーダをその上に置いて、モデル内の他のものの下に隠れないようにします。Forgeビューア:テキストの3Dマークアップ

オプション2 2Dでは、ForgeまたはHTMLのいずれかで、これはテキストが上に表示される画像で、フレームごとにこれらの画像+テキストの位置を3Dの2D位置に合わせて更新する必要がありますこれはうまくいくかもしれませんが、遅れる可能性があるので、これが可能なら3Dオプションを使用する方が望ましい理由です。

答えて

2

動的テクスチャを使用するカスタムシェーダの例については、最新のPointCloud Markup demoをご覧ください。High-Performance 3D markups with PointCloud in the Forge Viewer

あなたはラベルが含まれているテクスチャを生成するために、同様のアプローチを使用することができます...

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 
    } 
} 
+0

おかげでたくさんの更新のための

enter image description here

。 これで、フレームごとにどのシンボル(ピクセル)を表示するかを決定できます。 これですべてのアニメーションを行うことができますが、さらに重要なのは、想像できる任意のシンボル/テキストを描画できるため、番号の付いた円が可能になりました。 欠点は、ピクセルごとにプログラムする必要があるということだけです。つまり、次のように言うことはできません:fontsize 20pxで白を中心とするテキスト「50」を描画します。代わりに、あなたは言う必要があります:ピクセル1,1透明、ピクセル1,2白、等それはテキストレンダリングを可能にするには時間がかかるかもしれません。 今は元に戻すことはできませんが、それは重要なことです。 – Mykita

+1

電源には責任があります...シェーダは非常に強力ですが、レベルが低いので、これをあなたの側で処理する必要があります。他の回避策は言及したように2D DOMオーバーレイを使用することです。ここではsvgグラフィックスとともにテキストを簡単に表示できますが、多数のマークアップを表示する予定の場合は、シェイダーで得られるものの近くにはパフォーマンスがありません。 –

関連する問題