threejs 中的纹理未更新

Texture in threejs is not updating

我正在使用 threejs 编辑器作为一些 threejs 工作的基础。 当用户将鼠标悬停在某些元素上时,我试图显示一些工具提示。 为了实现这一点,我使用了一个 canvas,它被渲染为精灵上的纹理。

// create a canvas element
var canvas1 = document.createElement('canvas');
var context1 = canvas1.getContext('2d');
context1.font = "Bold 20px Arial";
context1.fillStyle = "rgba(0,0,0,0.95)";
context1.fillText('Hello, world!', 0, 20);

// canvas contents will be used for a texture
var texture1 = new THREE.Texture(canvas1)
texture1.needsUpdate = true;

// use the texture as material
var spriteMaterial = new THREE.SpriteMaterial({
    map: texture1,
    useScreenCoordinates: false
});

// create the sprite and add it tho the scene
var sprite1 = new THREE.Sprite(spriteMaterial);
sprite1.scale.set(1000, 500, 1.0);
sprite1.position.set(50, 50, 0);
scene.add(sprite1);

var i = 0;
// change the canvas' content
setInterval(function () {
    context1.clearRect(0, 0, canvas1.width, canvas1.height);
    var message = 'test' + i++;
    context1.fillText(message, 4, 20);
    texture1.needsUpdate = true;
}, 1000)

"test0" 已显示,但精灵未更新。如何更新精灵上的文字?我在这里错过了一些缓存失效吗?

为什么要在 3D 上渲染文本框 canvas? IMO 通过在页面的 2D 上下文中投影 3D 对象位置来定位 2D html 对象会好得多。

优点是渲染性能不会下降,您可以为信息框使用正常的 CSS/HTML 样式。

检查a great example on how you can do that here

another one belonging to this stackoverflow answer。工作起来就这么简单:

var proj = toScreenPosition(divObj, camera);

divElem.style.left = proj.x + 'px';
divElem.style.top = proj.y + 'px';

但是如果您进行一些谷歌搜索,您可以轻松找到更多示例...

Here is a fiddle 闲逛。

我认为它不起作用,因为您没有设置 canvas 的高度和宽度。

canvas1.width = 256;
canvas1.height = 256;

这一行也是一个问题:context1.fillStyle = "rgba(0.0,0,0,0.95)";
我将其更改为:context1.fillStyle = '#ff0000'; 以便我的工作

Here is a fiddle 实现了您的代码,只需将高度和宽度添加到 canvas 并更改 fillStyle

Wilt 的回答如果能满足您的需求,可能是更好的选择。

编辑:我是个白痴。这个问题已经有 2 年了。

它似乎对我有用...你确定你没有忽略控制台中的一些错误吗?您是否在 setInterval 中放置了一个断点以确保它被调用?

我确实不得不将更新移至渲染循环,因为似乎没有为 SO 片段定义 setInterval,但请在此处查看:

var renderer = new THREE.WebGLRenderer();
var w = 300;
var h = 200;
renderer.setSize(w, h);
document.body.appendChild(renderer.domElement);

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(
  45, // Field of view
  w / h, // Aspect ratio
  0.1, // Near
  10000 // Far
);
camera.position.set(15, 10, 15);
camera.lookAt(scene.position);
controls = new THREE.OrbitControls(camera, renderer.domElement);

var light = new THREE.PointLight(0xFFFF00);
light.position.set(20, 20, 20);
scene.add(light);
var light1 = new THREE.AmbientLight(0x808080);
light1.position.set(20, 20, 20);
scene.add(light1);

var sphereGeom = new THREE.SphereGeometry(5, 16, 16);
for (var i = 0; i < sphereGeom.vertices.length; i++) {
  var v = sphereGeom.vertices[i];
  if (v.y < 0) v.y = 0;
}
sphereGeom.verticesNeedUpdate = true;
sphereGeom.computeFaceNormals();
sphereGeom.computeVertexNormals();

var material = new THREE.MeshLambertMaterial({
  color: 0x808080
});
var mesh = new THREE.Mesh(sphereGeom, material);
scene.add(mesh);
renderer.setClearColor(0xdddddd, 1);

// create a canvas element
var canvas1 = document.createElement('canvas');
var context1 = canvas1.getContext('2d');
context1.font = "Bold 20px Arial";
context1.fillStyle = "rgba(0,0,0,0.95)";
context1.fillText('Hello, world!', 0, 20);

// canvas contents will be used for a texture
var texture1 = new THREE.Texture(canvas1)
texture1.needsUpdate = true;

// use the texture as material
var spriteMaterial = new THREE.SpriteMaterial({
  map: texture1,
  useScreenCoordinates: false
});

// create the sprite and add it tho the scene
var sprite1 = new THREE.Sprite(spriteMaterial);
sprite1.scale.set(40, 20, 1.0);
sprite1.position.set(-5, 0, -5);
scene.add(sprite1);

var i = 0;

(function animate() {
  requestAnimationFrame(animate);
  controls.update();
  renderer.render(scene, camera);



  context1.clearRect(0, 0, canvas1.width, canvas1.height);
  var message = 'test' + i++;
  context1.fillText(message, 4, 20);
  texture1.needsUpdate = true;

})();
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/controls/OrbitControls.js"></script>