我在场景中有一个BoxGeometry,我想在边缘添加边缘的大小,如下所示:
我找到this article,使用旧版本的three.js,其中包含以下代码段:
function makeTextSprite(message, opts) {
var parameters = opts || {};
var fontface = parameters.fontface || 'Helvetica';
var fontsize = parameters.fontsize || 70;
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
context.font = fontsize + "px " + fontface;
// get size data (height depends only on font size)
var metrics = context.measureText(message);
var textWidth = metrics.width;
// canvas contents will be used for a texture
var texture = new THREE.Texture(canvas)
texture.minFilter = THREE.LinearFilter;
texture.needsUpdate = true;
var spriteMaterial = new THREE.SpriteMaterial({
map: texture,
useScreenCoordinates: false
});
var sprite = new THREE.Sprite(spriteMaterial);
sprite.scale.set(100, 50, 1.0);
return sprite;
}
(好像在this answer中使用了相同的代码段)
但是,如果我正确地阅读了历史记录,那么根据this answer r.64
0,0,0
,这已经有效了一段时间。当我尝试设置精灵的位置时,位置似乎是在2d而不是3d中设置 - 当我旋转相机时,文本不会在画布上移动(当我将位置设置为r.91
时)。
stackoverflow回答链接到this demo,但我不确定如何调整他们的代码,因为他们加载图像纹理,而不是文本,似乎我的问题可能是创建一个合适的纹理,可以是分配给精灵并在3D空间中正确移动。
我很想看到更新版本的three.js上面的代码段的更新版本(我正在使用 sprite = makeTextSprite("Hello World", {});
sprite.position.set( 0,0,0 )
sprites.add( sprite );
)。我认为与上述代码片段相同的呼叫签名会很好,即
library(RcppRoll)
windows <- c(45,60)
multi_avg <- function(df, windows ) {
for(i in seq_along(windows)){
varname <- paste("avg", i , sep="_")
df[[varname]] <- with(df, roll_meanr(x, n = windows[i], fill = NA))
}
df
}
会在场景中创建一个以0,0,0为中心的精简版“Hello World”。
答案 0 :(得分:1)
我建议使用THREE.CSS2DObject。你可以设置它的3d位置并使用HTML控制它的内容(包括css,你可以用像素而不是世界单位来调整大小)。内容将始终面向相机(面向)。
let el = document.createElement("div");
el.className = cssClassName;
el.textContent = "blabla";
el.style.visibility = "visible";
let obj = new THREE.CSS2DObject(el);
obj.position.copy(...)
但是这种方法很慢(适用于&lt; 50个物体)。如果你需要很多这样的对象 - 你需要使用单独的渲染过程:使用相同的WebGL渲染器和特殊的HUD OrthographicCamera渲染额外的HUD场景,使用画布3d上下文程序纹理绘制:
...设置:
let self = this;
self.renderers.WebGL.autoClear = false;
let w = self.outputContainer.offsetWidth || self.parentElem.get(0).offsetWidth;
let h = self.outputContainer.offsetHeight || self.parentElem.get(0).offsetHeight;
let fov = 75;
let aspectRatio = w / h;
let near = 1;
let far = 20000000;
self.camera = new THREE.PerspectiveCamera(fov, aspectRatio, near, far);
let hw = w / 2;
let hh = h / 2;
self.cameraHUD = new THREE.OrthographicCamera(-hw, hw, hh, -hh, 0, w);
...绘图:
function updateHUD(callback: (context: CanvasRenderingContext2D) => void) {
let self = this;
self.sceneHUD.children.slice(0).forEach(obj => {
if (!(obj instanceof THREE.OrthographicCamera)) {
self.sceneHUD.remove(obj);
}
});
let canvasEl = self.renderers.WebGL.domElement;
let bounds = canvasEl.getBoundingClientRect(); //canvasEl.offsetLeft, canvasEl.offsetTop
let canvasElHUD = self.canvasElHUD;
if (!canvasElHUD) {
canvasElHUD = document.createElement("canvas");
self.canvasElHUD = canvasElHUD;
// Get 2D context and draw.
self.bitmapHUD = canvasElHUD.getContext("2d");
// Create texture from rendered graphics.
self.textureHUD = new THREE.Texture(canvasElHUD);
self.textureHUD.minFilter = THREE.NearestFilter;
// Create HUD material.
self.materialHUD = new THREE.MeshBasicMaterial({ map: self.textureHUD });
self.materialHUD.transparent = true;
}
//set dimensions to fit the screen.
if (canvasElHUD.width != bounds.width) {
canvasElHUD.width = bounds.width;
}
if (canvasElHUD.height != bounds.height) {
canvasElHUD.height = bounds.height;
}
if (callback) {
callback(self.bitmapHUD); //custom draw
}
self.textureHUD.needsUpdate = true;
// Create plane to render the HUD. This plane fill the whole screen.
let planeGeometry = new THREE.PlaneGeometry(bounds.width, bounds.height);
let planeMesh = new THREE.Mesh(planeGeometry, self.materialHUD);
self.sceneHUD.add(planeMesh);
return planeMesh;
}
...
self.updateHUD(bitmap => {
bitmap.clearRect(0, 0, bounds.width, bounds.height); //clear 2D canvas
bitmap.strokeStyle = "green";
bitmap.lineWidth = 1;
bitmap.beginPath();
let width = p2.x - p1.x;
let height = p2.y - p1.y;
bitmap.rect(p1.x, p1.y, width, height);
bitmap.stroke();
});
...和渲染:
self.renderers.WebGL.clear();
self.renderers.WebGL.render(self.scene, camera);
self.renderers.WebGL.clearDepth();
self.renderers.WebGL.render(self.sceneOverlay, camera);
self.renderers.WebGL.clearDepth();
self.renderers.WebGL.render(self.sceneHUD, self.cameraHUD);
self.renderers.CSS2D.render(self.scene, self.camera);
self.renderers.CSS2D.render(self.sceneOverlay, self.camera);
答案 1 :(得分:0)
我发现上面使用sprite的代码片段。
function makeTextSprite(message, opts) {
var parameters = opts || {};
var fontface = parameters.fontface || 'Helvetica';
var fontsize = parameters.fontsize || 120;
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
context.font = fontsize + "px " + fontface;
// get size data (height depends only on font size)
var metrics = context.measureText(message);
var textWidth = metrics.width;
// text color
context.fillStyle = 'rgba(0, 0, 0, 1.0)';
context.fillText(message, 0, fontsize);
// canvas contents will be used for a texture
var texture = new THREE.Texture(canvas)
texture.minFilter = THREE.LinearFilter;
texture.needsUpdate = true;
var spriteMaterial = new THREE.SpriteMaterial({ map: texture });
var sprite = new THREE.Sprite( spriteMaterial );
sprite.scale.set( 10, 5, 1.0 );
sprite.center.set( 0,1 );
return sprite;
}
关键线最终为sprite.center.set( 0,1 );
。
像这样使用:
sprite = makeTextSprite("bla");
sprite.position.copy( ... );
scene.add( sprite );
但是,此解决方案对SVGRenderer
不起作用,因为该渲染器不支持纹理,所以我现在正在寻找原始问题的THREE.js SVG解决方案