import * as THREE from 'three' function wordWrap(text, context, options) { const words = text.split(" ") const lines = [] let line = "" const maxWidth = options.width - (8 * 2) words.forEach(word => { const newLine = line+word+" " const metrics = context.measureText(newLine.trim()) let fontWidth = metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight if(fontWidth > maxWidth) { lines.push(line.trim()) line = word + " " } else { line = newLine } }) if (line != "") { lines.push(line.trim()) } return lines } export function buildCanvasText(text, inOptions = {}) { const options = {width: 512, height: 512, font: "86px Arial", textAlign: "center", lineWidth: 8} if(inOptions.width) options.width = inOptions.width if(inOptions.height) options.height = inOptions.height if(inOptions.font) options.font = inOptions.font if(inOptions.textAlign) options.textAlign = inOptions.textAlign if(inOptions.lineWidth) options.lineWidth = inOptions.lineWidth const texture = generateMap(text, options) const alphaMap = generateAlphaMap(text, options) const material = new THREE.MeshBasicMaterial({transparent: true, map: texture, side: THREE.DoubleSide, alphaMap: alphaMap, alphaTest: 0.1}) const geometry = new THREE.PlaneGeometry(4,4) const textMesh = new THREE.Mesh(geometry, material) textMesh.castShadow = true return textMesh } function generateMap(text, options) { const textCanvas = document.createElement('canvas') textCanvas.width = options.width textCanvas.height = options.height const context = textCanvas.getContext('2d') context.clearRect(0, 0, options.width, options.height) context.font = options.font context.textAlign = options.textAlign context.lineWidth = options.lineWidth context.lineCap = "round" context.lineJoin = "round" const lines = wordWrap(text, context, options) for(let i = 0; i < lines.length; i++) { const lineToDraw = lines[i] const metrics = context.measureText(lineToDraw) let fontHeight = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent // context.beginPath() // context.fillStyle = "rbga(0,0,0,0.5)" // context.rect(0,0, options.width, options.height) // context.fill() context.beginPath() context.strokeStyle = "black" context.strokeText(lineToDraw, options.width / 2, 8 + (fontHeight * (i + 1))) context.beginPath() context.fillStyle = "white" context.fillText(lineToDraw, options.width / 2, 8 + (fontHeight * (i + 1))) } const texture = new THREE.CanvasTexture(textCanvas) texture.minFilter = THREE.LinearFilter; texture.wrapS = THREE.ClampToEdgeWrapping; texture.wrapT = THREE.ClampToEdgeWrapping; texture.needsUpdate = true return texture } function generateAlphaMap(text, options) { const textCanvas = document.createElement('canvas') textCanvas.width = options.width textCanvas.height = options.height const context = textCanvas.getContext('2d') context.clearRect(0, 0, options.width, options.height) context.beginPath() context.fillStyle = "black" context.rect(0, 0, options.width, options.height) context.fill() // context.beginPath() // context.strokeStyle = "magenta" // context.rect(0,0, options.width, options.height) // context.stroke() context.font = options.font context.textAlign = options.textAlign context.lineWidth = options.lineWidth context.lineCap = "round" context.lineJoin = "round" const lines = wordWrap(text, context, options) for(let i = 0; i < lines.length; i++) { const lineToDraw = lines[i] const metrics = context.measureText(lineToDraw) let fontHeight = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent // context.beginPath() // context.fillStyle = "rbga(0,0,0,0.5)" // context.rect(0,0, options.width, options.height) // context.fill() context.beginPath() context.strokeStyle = "white" context.strokeText(lineToDraw, options.width / 2, 8 + (fontHeight * (i + 1))) context.beginPath() context.fillStyle = "white" context.fillText(lineToDraw, options.width / 2, 8 + (fontHeight * (i + 1))) } const texture = new THREE.CanvasTexture(textCanvas) texture.minFilter = THREE.LinearFilter; texture.wrapS = THREE.ClampToEdgeWrapping; texture.wrapT = THREE.ClampToEdgeWrapping; texture.needsUpdate = true return texture }