我正在尝试显示一个立方体,其中一侧显示我在其上绘制一些文本的图像。我尝试了几种方法,但是图像和文本始终总是被渲染为黑色。相反,如果我只是简单地使用ThreeJS文本加载器之类的东西直接加载图像,则可以看到图像很好(当然,上面没有文本)。我的代码有什么问题,以便在初始化期间看不到所需的图像以及在其上打印的文字?
var scene, camera, renderer;
var WIDTH = window.innerWidth;
var HEIGHT = window.innerHeight;
var SPEED = 0.01;
var cube = null;
var imgBackSide = null;
function init() {
// Create a document element to house the back side image for cards.
imgBackSide = document.createElement('img');
imgBackSide.src = '/images/cards/card-back-side-400x400.png';
scene = new THREE.Scene();
initCamera();
initRenderer();
initCube();
document.body.appendChild(renderer.domElement);
}
function initCamera() {
camera = new THREE.PerspectiveCamera(70, WIDTH / HEIGHT, 1, 10);
camera.position.set(0, 3.5, 5);
camera.lookAt(scene.position);
}
function initRenderer() {
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(WIDTH, HEIGHT);
}
function canvasDrawText(ctx, canvas, text, x, y) {
// if x isn't provided
if ( x === undefined || x === null ){
let textSize = ctx.measureText(text);
x = (canvas.width - textSize.width) / 2;
}
// if y isn't provided
if ( y === undefined || y === null ){
let textSize = ctx.measureText(text);
y = (canvas.height - textSize.height) / 2;
}
// actually draw the text
// ctx.fillStyle = fillStyle;
ctx.fillText(text, x, y);
}
function newCardBacksideTexture(cardBackSideText) {
// Create an IMG element to hold the card back side image and load it.
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
canvas.width = 400;
canvas.height = 400;
ctx.drawImage(imgBackSide, 0, 0);
// Draw the card label on top of the background.
ctx.font = 'bolder 90px Verdana';
canvasDrawText(ctx, canvas, cardBackSideText);
// dynamicTexture.texture.anisotropy = renderer.capabilities.getMaxAnisotropy();
return new THREE.CanvasTexture(canvas);
}
function initCube() {
let cubeGeometry = new THREE.BoxGeometry(2, 0.1, 2);
let loader = new THREE.TextureLoader();
let dummy = loader.load("/images/cards/white-square-400x400.png");
let materialArray = [
new THREE.MeshBasicMaterial( { map: loader.load('/images/cards/white-square-400x400.png') } ),
new THREE.MeshBasicMaterial( { map: loader.load('/images/cards/white-square-400x400.png') } ),
// Card face.
new THREE.MeshBasicMaterial( { map: loader.load('/images/card-face.jpg') } ),
// Card back side.
new THREE.MeshBasicMaterial( { map: newCardBacksideTexture('BACK SIDE OF CARD') } ),
//
new THREE.MeshBasicMaterial( { map: loader.load('/images/cards/white-square-400x400.png') } ),
new THREE.MeshBasicMaterial( { map: loader.load('/images/cards/white-square-400x400.png') } ),
];
cube = new THREE.Mesh( cubeGeometry, materialArray );
scene.add(cube);
}
function rotateCube() {
cube.rotation.x -= SPEED * 2;
cube.rotation.y -= SPEED;
cube.rotation.z -= SPEED * 3;
}
function render() {
requestAnimationFrame(render);
rotateCube();
renderer.render(scene, camera);
}
init();
render();
答案 0 :(得分:1)
代码有2个问题
它不会等待您在画布上绘制的图像加载,因此当它尝试绘制该图像时,什么也不会绘制。
将文本绘制到中心引用textSize.height
中的计算。没有这样的值,所以y
最终变成了NaN
并且没有绘制文本。
请注意,您可以通过要求画布来使文本居中。
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
将文字居中绘制位置
对于等待图像加载,您需要决定如何构建代码以等待。您可以等待图像加载后再开始。或者,您可以创建一个画布和一个CanvasTexture
。将其传递到多维数据集材质中,然后在图像下载完成后更新该画布,并将CanvasTexture
的{{1}}设置为true。
needsUpdate
var scene, camera, renderer;
var WIDTH = window.innerWidth;
var HEIGHT = window.innerHeight;
var SPEED = 0.01;
var cube = null;
var imgBackSide = null;
function init() {
scene = new THREE.Scene();
initCamera();
initRenderer();
initCube();
document.body.appendChild(renderer.domElement);
}
function initCamera() {
camera = new THREE.PerspectiveCamera(70, WIDTH / HEIGHT, 1, 10);
camera.position.set(0, 3.5, 5);
camera.lookAt(scene.position);
}
function initRenderer() {
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(WIDTH, HEIGHT);
}
function canvasDrawText(ctx, canvas, text, x, y) {
// if x isn't provided
if (x === undefined || x === null) {
x = canvas.width / 2;
ctx.textAlign = 'center';
} else {
ctx.textAlign = 'left';
}
// if y isn't provided
if ( y === undefined || y === null ) {
y = canvas.height / 2;
ctx.textBaseline = 'middle';
} else {
ctx.textBaseline = 'alphabetic';
}
// actually draw the text
// ctx.fillStyle = fillStyle;
ctx.fillText(text, x, y);
}
function newCardBacksideTexture(cardBackSideText) {
// Create an IMG element to hold the card back side image and load it.
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
canvas.width = 400;
canvas.height = 400;
const canvasTex = new THREE.CanvasTexture(canvas);
// Create a document element to house the back side image for cards.
imgBackSide = document.createElement('img');
imgBackSide.onload = () => {
ctx.drawImage(imgBackSide, 0, 0);
// Draw the card label on top of the background.
ctx.font = 'bolder 90px Verdana';
canvasDrawText(ctx, canvas, cardBackSideText);
// dynamicTexture.texture.anisotropy = renderer.capabilities.getMaxAnisotropy();
canvasTex.needsUpdate = true;
};
// this is needed only if the image
// comes from another domain
imgBackSide.crossOrigin = "anonymous";
imgBackSide.src = 'https://i.imgur.com/TSiyiJv.jpg';
return canvasTex;
}
function initCube() {
let cubeGeometry = new THREE.BoxGeometry(2, 0.1, 2);
let loader = new THREE.TextureLoader();
let dummy = loader.load("https://i.imgur.com/ZKMnXce.png");
let materialArray = [
new THREE.MeshBasicMaterial( { map: loader.load('https://i.imgur.com/ZKMnXce.png') } ),
new THREE.MeshBasicMaterial( { map: loader.load('https://i.imgur.com/ZKMnXce.png') } ),
// Card face.
new THREE.MeshBasicMaterial( { map: loader.load('https://i.imgur.com/ZKMnXce.png') } ),
// Card back side.
new THREE.MeshBasicMaterial( { map: newCardBacksideTexture('BACK SIDE OF CARD') } ),
//
new THREE.MeshBasicMaterial( { map: loader.load('https://i.imgur.com/ZKMnXce.png') } ),
new THREE.MeshBasicMaterial( { map: loader.load('https://i.imgur.com/ZKMnXce.png') } ),
];
cube = new THREE.Mesh( cubeGeometry, materialArray );
scene.add(cube);
}
function rotateCube() {
cube.rotation.x -= SPEED * 2;
cube.rotation.y -= SPEED;
cube.rotation.z -= SPEED * 3;
}
function render() {
requestAnimationFrame(render);
rotateCube();
renderer.render(scene, camera);
}
init();
render();