10

I'm using react-three-renderer (npm, github) for building a scene with three.js.

I'm attempting to use <sprite> and <spriteMaterial> to make a label that always faces the camera, much like in stemkoski's example.

However, I'm having trouble getting the label to display and appropriately setting its coordinates. I have a minimally verifiable complete example at Sprite-Label-Test. Download it, run npm install, and open _dev/public/home.html.

My goal is to see text displayed where I expect it, but as you'll see, it's just blackness. To prove that the sprite is in the view of the camera, I put a box at the same position. To see that uncomment it from the render method and re-gulp.

Here's my file. It has two main components, the componentDidMount method, where the text is created for the sprite, and the render method.

var React = require('react');
var React3 = require('react-three-renderer');
var THREE = require('three');
var ReactDOM = require('react-dom');

class Simple extends React.Component {
  constructor(props, context) {
    super(props, context);

    // construct the position vector here, because if we use 'new' within render,
    // React will think that things have changed when they have not.
    this.cameraPosition = new THREE.Vector3(0, 0, 100);
  }

  componentDidMount() {
    var text = "Hello world";
    var canvas = document.createElement('canvas');
    var context = canvas.getContext('2d');
    var metrics = context.measureText( text );
    var textWidth = metrics.width;

    context.font = "180px arial Bold";
    context.fillStyle = "rgba(255,0,0,1)";
    context.strokeStyle = "rgba(255,0,0,1)";
    context.lineWidth = 4;

    context.fillText( text, 0, 0);

    var texture = new THREE.Texture(canvas)
    texture.needsUpdate = true;

    this.spriteMaterial.map = texture;
    this.spriteMaterial.useScreenCoordinates = false;
  }

  render() {
    const width = window.innerWidth; // canvas width
    const height = window.innerHeight; // canvas height

    var position = new THREE.Vector3(0, 0, 10);
    var scale = new THREE.Vector3(1,1,1);

    return (<React3
      mainCamera="camera" // this points to the perspectiveCamera which has the name set to "camera" below
      width={width}
      height={height}
    >
      <scene>
        <perspectiveCamera
          name="camera"
          fov={75}
          aspect={width / height}
          near={0.1}
          far={1000}

          position={this.cameraPosition}
        />
        <sprite position={position} scale={scale} ref={(sprite) => this.sprite = sprite}>
          <spriteMaterial ref={(spriteMaterial) => this.spriteMaterial = spriteMaterial}></spriteMaterial>
        </sprite>
        {/*<mesh position={position}>
          <boxGeometry
            width={10}
            height={10}
            depth={10}
          />
          <meshBasicMaterial
            color={0x00ff00}
          />
        </mesh>*/}
      </scene>
    </React3>);
  }
}

ReactDOM.render(<Simple/>, document.querySelector('.root-anchor'));

What am I doing wrong? How can I display a sprite text label in the position established with the line var position = new THREE.Vector3(0, 0, 10);? Thanks in advance.

Scotty H
  • 6,432
  • 6
  • 41
  • 94
  • Speaking for me, I'm not going to download, install dependencies and then finally run someone's "MVCE" (I wouldn't call that *minimal*). Had a quick look at this react-three-renderer though, and it states "This is still an experimental and work in progress project, use at your own risk!". If the problem is related to that library, I'm not sure SO is the right place for questions about it. – Leeft Aug 31 '16 at 06:39
  • 2
    @Leeft I realize there is a bit of intentional work to use this example, but anyone familiar with git and npm is capable of a quick `git clone` and an `npm install`. Since it deals largely with the libraries involved. I felt a git repo was the easiest way to make the problem quickly reproducible. Additionally, all the code I've written is provided in the question for those who may not care to clone the repo, install dependencies, etc. – Scotty H Aug 31 '16 at 13:48

1 Answers1

6

All you've got is one tiny mistake:

Text drawn on <canvas> is anchored at the bottom-left corner. So drawing text at (0,0) won't even be visible. It'll be entirely outside the canvas (shown in white below):

Text outside canvas

-    context.fillText( text, 0, 0);
+    context.fillText( text, 0, 18);

This is why @df uses fontsize when setting the drawing location on line 147.


Also, you're camera wasn't looking at anything. React-Three lets do this as an attribute to your <perspectiveCamera/>.

+          lookAt={this.cameraLook}

I opened a pull request against your MVCE repository.

Robbie Wxyz
  • 7,671
  • 2
  • 32
  • 47