24

Since the webgl/opengl doesn't support text drawing, so it possible to draw 3D object using 3D context and text drawing using 2D context ?

genpfault
  • 51,148
  • 11
  • 85
  • 139
Pointer
  • 627
  • 2
  • 8
  • 19

4 Answers4

41

No, unfortunately not.

The HTML 5 spec says that if you call getContext on a canvas element that is already in a different context mode and the two contexts are not compatible then return null.

Unfortunately "webgl" and "2d" canvases are not compatible and thus you will get null:

var canvas = document.getElementById('my-canvas');
var webgl = canvas.getContext("webgl"); // Get a 3D webgl context, returns a context
var twod = canvas.getContext("2d"); // Get a 2D context, returns null
Sebastian
  • 7,729
  • 2
  • 37
  • 69
dave
  • 2,191
  • 4
  • 21
  • 25
19

As stated, you cannot do this.

However you can put one canvas on top of another and draw to them separately. I've done this before and it can work out quite well.

Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
  • 2
    For more info, see this question: http://stackoverflow.com/questions/3008635/html5-canvas-element-multiple-layers – 1j01 Dec 03 '16 at 21:56
5

Create the text as a texture using canvas 2D, then render it in 3D. See here for a tutorial.

Marcelo Cantos
  • 181,030
  • 38
  • 327
  • 365
3

What I've been doing, whether I just need troubleshooting feedback or 2D text content on a 3D canvas, is just use CSS to put some HTML elements on top of the canvas.

You can make a canvas and a group of text fields share the same space, and ensure that the text fields are on top as follows:

HTML:

<div id="container">
  <canvas id="canvas"></canvas>
  <div id="controlsContainer">
    <label>Mouse Coordinates</label>
      <div>
        <label for="xPos">X</label>
        <span id="xPos"></span>
      </div>
      <div>
        <label for="yPos">Y</label>
        <span id="yPos"></span>
      </div>
  </div>
</div>

CSS:

canvas {
    margin: 0px;
    position: relative;
    top: 0px;
    left: 0px;
    width: 100%;
}

#container {
  position: relative;
}

#controlsContainer {
  position: absolute;
  left: 10px;
  top: 10px;
  z-index: 3;
}

  #controlsContainer div {
    padding-left: 8px;
  }

  #controlsContainer label {
    color: white;
    z-index: 4;
  }

  #controlsContainer span {
    color: white;
    z-index: 4;
  }

The z-index will ensure which elements are in front, and position: relative for the container and position: absolute, in coordination with the top and left for the controls will ensure that they share the same space.

I have been having very good luck with this, and the troubleshooting feedback is invaluable.

enter image description here

An example of the Javascript (ES6 in this case) is:

let xPos = document.getElementById("xPos");
let yPos = document.getElementById("yPos");
let x = event.clientX - containerDiv.offsetLeft -parseInt(window.getComputedStyle(pageBody).getPropertyValue("margin-left"));
let y = event.clientY - containerDiv.offsetTop - parseInt(window.getComputedStyle(pageBody).getPropertyValue("margin-top"));
xPos.innerText = x;
yPos.innerText = y;

which I've placed in a mousemove handler.

Kent Weigel
  • 1,168
  • 1
  • 11
  • 16