3

In the following example, there is a function called generateTexture().

Is it possible to draw text (numbers) into the pixel array? Or is it possible to draw text (numbers) on top of that shader?

Our goal is to draw a circle with a number inside of it.

https://forge.autodesk.com/blog/using-dynamic-texture-inside-custom-shaders

UPDATE: We noticed that each circle can't use a unique generateTexture(). The generateTexture() result is used by every single one of them. The only thing that can be customized per object is the color, plus what texture is used.

We could create a workaround for this, which is to generate every texture from 0 to 99, and to then have each object choose the correct texture based on the number we want to display. We don't know if this will be efficient enough to work properly though. Otherwise, it might have to be 0 to 9+ or something in that direction. Any guides on our updated question would be really appreciated. Thanks.

Torbjorn
  • 45
  • 4

2 Answers2

2

I am able to successfully display text with the following code, simply replace generateTexture() by generateCanvasTexture() in the sample and you should get the result below:

const generateCanvasTexture = () => {

  const canvas = document.createElement("canvas")
  const ctx = canvas.getContext('2d')

  ctx.font = '20pt Arial'
  ctx.textAlign = 'center'
  ctx.textBaseline = 'middle'
  ctx.fillText(new Date().toLocaleString(),
    canvas.width / 2, canvas.height / 2)

  const canvasTexture = new THREE.Texture(canvas)

  canvasTexture.needsUpdate = true
  canvasTexture.flipX = false
  canvasTexture.flipY = false

  return canvasTexture
}

enter image description here

Felipe
  • 4,325
  • 1
  • 14
  • 19
  • Thanks again. We will do some testing the next couple of days. Seems like we are closing in on a solution. Appreciate the help. – Torbjorn Feb 13 '18 at 23:54
  • Hello again Philippe. It all came together nicely. Thanks for the assistance. However, one small question: for some reason, the shadowing or ambient occlusion goes on top of the markup shaders, which in rare cases results in the markup being all in the dark. Example from the chair: http://oi65.tinypic.com/15x4w7.jpg Example from our app: http://oi64.tinypic.com/jicpaa.jpg – Torbjorn Feb 17 '18 at 18:54
  • Not sure how to work around those... did you try switching off ambient shadows and anti-aliasing in the viewer (can be done through API as well) – Felipe Feb 19 '18 at 18:03
0

It is possible but you would need to implement it yourself. Shaders are a pretty low level feature so there is no way to directly draw a number or a text, but you can convert a given character into its representation as a 2d pixel array.

Felipe
  • 4,325
  • 1
  • 14
  • 19
  • Thanks. We'll do some testing and draw white text (0 to 9) on top of a black background, then we can take the pixel data from that and use it in the shader. We'll see if we find any program that can help us automatically get the pixel values out of the image, otherwise we will just have to manually measure and write down every pixel value. – Torbjorn Feb 03 '18 at 23:56
  • This may help: https://stackoverflow.com/questions/13963308/how-do-you-simply-obtain-an-array-of-pixel-data-from-an-image – Felipe Feb 05 '18 at 13:45
  • Thanks. We have updated our question. Would you kindly share your take on this? Thanks a lot. – Torbjorn Feb 12 '18 at 10:12
  • There is no limitation here, in that sample the texture is part of the shader.uniforms, which means it is common to all vertices using that shader. If you want different textures for each vertex you can either use shader.attributes (which have a 1 to 1 correspondance with the vertices, similar to color or pointSize) or create a different shader for each texture but one entity in three.js can only be affected one material, so you are rather in the first case. – Felipe Feb 12 '18 at 11:54
  • Hi again, we have tried do to what you suggested but unfortunately with no luck. Apparently, it is invalid shader code to have a sampler2D (a texture) as an attribute, it has to be a uniform. See https://msdn.microsoft.com/en-us/ie/dn611835(v=vs.94) at "Invalid qualifier on sampler variable declaration - must be uniform". Also, see this: https://stackoverflow.com/questions/46553165/what-are-the-valid-types-for-a-webgl-vertex-shader-attribute. Would you kindly give us your take on this? – Torbjorn Feb 12 '18 at 20:53
  • Adding our interest. We are also experimenting with custom markups. – Mykita Feb 12 '18 at 21:46
  • 1
    You could use an array of sampler2D as uniform, like in this question: https://stackoverflow.com/questions/26579109/three-js-using-multiple-textures-in-a-single-pointcloud – Felipe Feb 12 '18 at 22:09
  • 1
    It also comes to my mind that you can render a 2d canvas in a texture, this will give you powerful way to render text or more complex 2d shapes to the shaders without having to implement complex logic yourself. See that demo: https://stemkoski.github.io/Three.js/Texture-From-Canvas.html or this https://www.npmjs.com/package/threejs-texture-tool – Felipe Feb 13 '18 at 07:40
  • Thanks - we will give the canvas suggestion a try. – Torbjorn Feb 13 '18 at 11:55