如何解决无法在Autodesk Forge Viewer中显示文本精灵
我无法在Autodesk Forge Viewer中显示文本精灵。
我创建了一个示例项目ForgeTextSprite,该示例项目在加载的模型下方显示一个罗盘玫瑰。尽管指南针的度显示为“ OK”,但未显示基数(N,S,E,W)的文本。
下面的TextSprite.ts文件已从three-spritetext转换为Typescript。我注释了THREE.LinearFilter的用法,因为在Forge查看器中似乎不存在。
// Converted to Typescript from https://github.com/vasturiano/three-spritetext.
//
// Commented out usage to THREE.LinearFilter as that doesn't seem to be present in the
// Forge viewer.
export default class TextSprite extends THREE.Sprite {
_text: string;
_textHeight: number;
_color: string;
_backgroundColor: string;
_padding: number;
_borderWidth: number;
_borderColor: string;
_strokeWidth: number;
_strokeColor: string;
_fontFace: string;
_fontSize: number;
_fontWeight: string;
_canvas: HTMLCanvasElement;
_texture: THREE.Texture;
constructor(text = '',textHeight = 10,color = 'rgba(255,255,1)') {
super(new THREE.SpriteMaterial({ map: new THREE.Texture() }));
this._text = `${text}`;
this._textHeight = textHeight;
this._color = color;
this._backgroundColor = ''; // no background color
this._padding = 0;
this._borderWidth = 0;
this._borderColor = 'blue';
this._strokeWidth = 0;
this._strokeColor = 'green';
this._fontFace = 'Arial';
this._fontSize = 90; // defines text resolution
this._fontWeight = 'normal';
this._canvas = document.createElement('canvas');
if (this.material instanceof THREE.SpriteMaterial) {
this._texture = this.material.map;
}
// this._texture.minFilter = three.LinearFilter;
this._genCanvas();
}
get text() { return this._text; }
set text(text) { this._text = text; this._genCanvas(); }
get textHeight() { return this._textHeight; }
set textHeight(textHeight) { this._textHeight = textHeight; this._genCanvas(); }
get color() { return this._color; }
set color(color) { this._color = color; this._genCanvas(); }
get backgroundColor() { return this._backgroundColor; }
set backgroundColor(color) { this._backgroundColor = color; this._genCanvas(); }
get padding() { return this._padding; }
set padding(padding) { this._padding = padding; this._genCanvas(); }
get borderWidth() { return this._borderWidth; }
set borderWidth(borderWidth) { this._borderWidth = borderWidth; this._genCanvas(); }
get borderColor() { return this._borderColor; }
set borderColor(borderColor) { this._borderColor = borderColor; this._genCanvas(); }
get fontFace() { return this._fontFace; }
set fontFace(fontFace) { this._fontFace = fontFace; this._genCanvas(); }
get fontSize() { return this._fontSize; }
set fontSize(fontSize) { this._fontSize = fontSize; this._genCanvas(); }
get fontWeight() { return this._fontWeight; }
set fontWeight(fontWeight) { this._fontWeight = fontWeight; this._genCanvas(); }
get strokeWidth() { return this._strokeWidth; }
set strokeWidth(strokeWidth) { this._strokeWidth = strokeWidth; this._genCanvas(); }
get strokeColor() { return this._strokeColor; }
set strokeColor(strokeColor) { this._strokeColor = strokeColor; this._genCanvas(); }
_genCanvas() {
const canvas = this._canvas;
const ctx = canvas.getContext('2d');
const border = [this.borderWidth,this.borderWidth]; // x,y border
const relBorder = border.map(b => b * this.fontSize * 0.1); // border in canvas units
const padding = [this.padding,this.padding]; // x,y padding
const relPadding = padding.map(p => p * this.fontSize * 0.1); // padding in canvas units
const lines = this.text.split('\n');
const font = `${this.fontWeight} ${this.fontSize}px ${this.fontFace}`;
ctx.font = font; // measure canvas with appropriate font
const innerWidth = Math.max(...lines.map(line => ctx.measureText(line).width));
const innerHeight = this.fontSize * lines.length;
canvas.width = innerWidth + relBorder[0] * 2 + relPadding[0] * 2;
canvas.height = innerHeight + relBorder[1] * 2 + relPadding[1] * 2;
// paint border
if (this.borderWidth) {
ctx.strokeStyle = this.borderColor;
if (relBorder[0]) {
ctx.linewidth = relBorder[0] * 2;
ctx.beginPath();
ctx.moveto(0,0);
ctx.lineto(0,canvas.height);
ctx.moveto(canvas.width,0);
ctx.lineto(canvas.width,canvas.height);
ctx.stroke();
}
if (relBorder[1]) {
ctx.linewidth = relBorder[1] * 2;
ctx.beginPath();
ctx.moveto(relBorder[0],0);
ctx.lineto(canvas.width - relBorder[0],0);
ctx.moveto(relBorder[0],canvas.height);
ctx.lineto(canvas.width - relBorder[0],canvas.height);
ctx.stroke();
}
}
ctx.translate(relBorder[0],relBorder[1]);
// paint background
if (this.backgroundColor) {
ctx.fillStyle = this.backgroundColor;
ctx.fillRect(0,canvas.width - relBorder[0] * 2,canvas.height - relBorder[1] * 2);
}
ctx.translate(relPadding[0],relPadding[1]);
// paint text
ctx.font = font; // Set font again after canvas is resized,as context properties are reset
ctx.fillStyle = this.color;
ctx.textBaseline = 'bottom';
const drawTextstroke = this.strokeWidth > 0;
if (drawTextstroke) {
ctx.linewidth = this.strokeWidth * this.fontSize / 10;
ctx.strokeStyle = this.strokeColor;
}
lines.forEach((line,index) => {
const lineX = (innerWidth - ctx.measureText(line).width) / 2;
const lineY = (index + 1) * this.fontSize;
drawTextstroke && ctx.strokeText(line,lineX,lineY);
ctx.fillText(line,lineY);
});
// Inject canvas into sprite
this._texture.image = canvas;
this._texture.needsUpdate = true;
const yScale = this.textHeight * lines.length + border[1] * 2 + padding[1] * 2;
this.scale.set(yScale * canvas.width / canvas.height,yScale,0);
}
// clone(recursive?: boolean): this {
// return new SpriteText(this.text,this.textHeight,this.color).copy(this);
// }
copy(source: this,recursive?: boolean): this {
super.copy(source,recursive);
this.color = source.color;
this.backgroundColor = source.backgroundColor;
this.padding = source.padding;
this.borderWidth = source.borderWidth;
this.borderColor = source.borderColor;
this.fontFace = source.fontFace;
this.fontSize = source.fontSize;
this.fontWeight = source.fontWeight;
this.strokeWidth = source.strokeWidth;
this.strokeColor = source.strokeColor;
return this;
}
}
在CompassRose.ts中,将创建文本精灵,将其转换并旋转到适当的位置,然后将其添加到THREE.Group。
import TextSprite from './TextSprite';
const markerLength = 1;
const fifthMarkerLength = 5;
const tenthMarkerLength = 10;
const ordinalMarkerLength = 15;
const color = 0x444444;
const fontSize = 4;
const halfFontSize = fontSize / 2;
const radius = 100;
const cardinalOuter = radius + 10;
export default class CompassRose {
build(): THREE.Group {
const group = new THREE.Group();
const material = new THREE.LineBasicMaterial({
color: color
});
for (let degree = 0; degree < 360; degree++) {
const lineParent = new THREE.Group();
const lineAngle = (Math.PI * degree) / 180;
lineParent.rotateX(lineAngle);
const length = this.getMarkerLength(degree);
const line = this.buildLine(radius,length,material);
lineParent.add(line);
group.add(lineParent);
}
let sprite = this.createheadingTextSprite("N")
.translateX(cardinalOuter - fontSize)
.translateY(halfFontSize)
.rotateZ(-Math.PI / 2);
group.add(sprite);
sprite = this.createheadingTextSprite("S")
.translateX(-cardinalOuter)
.translateY(halfFontSize)
.rotateZ(-Math.PI / 2);
group.add(sprite);
sprite = this.createheadingTextSprite("W")
.translateY(cardinalOuter)
.translateX(-halfFontSize)
.rotateZ(-Math.PI / 2);
group.add(sprite);
sprite = this.createheadingTextSprite("E")
.translateY(-cardinalOuter + fontSize)
.translateX(-halfFontSize)
.rotateZ(-Math.PI / 2);
group.add(sprite);
return group;
}
private getMarkerLength(degree: number) {
let length: number;
if (degree % 90 === 0) {
length = ordinalMarkerLength;
} else if (degree % 10 === 0) {
length = tenthMarkerLength;
} else if (degree % 5 === 0) {
length = fifthMarkerLength;
} else {
length = markerLength;
}
return length;
}
private buildLine(radius: number,length: number,material: THREE.Material) {
const lineGeometry = new THREE.Geometry();
lineGeometry.vertices.push(new THREE.Vector3(0,radius,0));
lineGeometry.vertices.push(new THREE.Vector3(0,radius - length,0));
return new THREE.Line(lineGeometry,material);
}
private createheadingTextSprite(text: string): THREE.Sprite {
return new TextSprite(text,10,'#888888');
}
}
解决方法
请注意,Forge Viewer基于Three.js R71版本。在您的代码中,您似乎正在使用Three.js R103的类型定义,并且三个spritetext依赖项引用了Three.js R86。恐怕是这些版本的差异导致呈现文本精灵时无声的失败。
我建议:
- 使用THREE.TextGeometry(在R71中可用)代替以生成薄3D文本
- 在场景中添加简单的THREE.PlaneBufferGeometry并将表盘和标签添加为纹理
- 考虑将拨号盘/标签作为另一个Forge模型(例如从PDF或DWG文件)加载到查看器场景中
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。