BabylonJS - 动态纹理
Babylon.js - 动态纹理 (DynamicTexture)
Section titled “Babylon.js - 动态纹理 (DynamicTexture)”DynamicTexture 是 Babylon.js 中一种特殊的纹理类型,它允许你使用标准的 HTML5 2D Canvas API 在其上进行绘制。这对于动态生成纹理非常有用,例如显示文本、绘制形状、渲染 UI 元素或直接在材质上创建程序化图案。
你可以将其想象成纹理背后有一个隐藏的 2D canvas。你可以获取这个 canvas 的绘图上下文,使用熟悉的 API 方法,如 fillText、strokeRect、beginPath、bezierCurveTo、drawImage 等,然后更新纹理以在 3D 模型上显示你的绘制内容。
创建动态纹理
Section titled “创建动态纹理”通过提供名称、定义其大小(宽度和高度)的选项、场景以及可选的是否生成 mipmaps 来创建 DynamicTexture。
import * as BABYLON from '@babylonjs/core';
// 假设 'scene' 已定义const textureWidth = 512;const textureHeight = 256;const generateMipMaps = true; // 是否生成 mipmaps
const myDynamicTexture = new BABYLON.DynamicTexture( "dynamicTex", { width: textureWidth, height: textureHeight }, // 也可以只传递大小: 512 scene, generateMipMaps);DynamicTexture 提供了一个方便的 drawText 方法,用于快速在纹理上渲染文本。
const text = "Hello Babylon!";const x = 50; // 在纹理 canvas 上的 X 坐标const y = 100; // 在纹理 canvas 上的 Y 坐标const font = "bold 44px Arial"; // CSS 字体字符串const color = "white"; // 文本颜色const canvasColor = "blue"; // 文本区域的背景颜色 (可以是 'transparent' 透明)const invertY = true; // 如果为 true,Y 表示距顶部的距离;如果为 false,表示距底部的距离const update = true; // 如果为 true,立即更新纹理
myDynamicTexture.drawText(text, x, y, font, color, canvasColor, invertY, update);使用 Canvas 上下文
Section titled “使用 Canvas 上下文”对于更复杂的绘制,你可以使用 getContext() 方法获取纹理底层 canvas 的 2D 渲染上下文。这使得你可以访问完整的 HTML5 Canvas API。
// 获取 2D 上下文const ctx = myDynamicTexture.getContext();
// 现在使用标准的 canvas 方法ctx.fillStyle = "green";ctx.fillRect(10, 10, 100, 50);
ctx.strokeStyle = "yellow";ctx.lineWidth = 4;ctx.strokeRect(120, 10, 80, 80);
ctx.beginPath();ctx.moveTo(250, 30);ctx.lineTo(350, 130);ctx.lineTo(250, 130);ctx.closePath();ctx.fillStyle = "rgba(255, 0, 0, 0.7)"; // 半透明红色ctx.fill();ctx.stroke();
// 重要: 使用上下文绘制后,你必须调用 update()// 才能在 3D 模型上看到更改。myDynamicTexture.update();一旦创建并绘制完成,你可以将 DynamicTexture 应用于材质,就像应用任何其他纹理一样(例如,作为 diffuseTexture)。
// 假设 'mesh' 已定义const material = new BABYLON.StandardMaterial("dynamicMat", scene);material.diffuseTexture = myDynamicTexture;mesh.material = material;示例: 盒子上的文本
Section titled “示例: 盒子上的文本”<!DOCTYPE html><html><head> <meta charset="utf-8"/> <title>Babylon.js - Dynamic Texture Text</title> <script src="https://cdn.babylonjs.com/babylon.js"></script> <style> html, body { overflow: hidden; width: 100%; height: 100%; margin: 0; padding: 0; } #renderCanvas { width: 100%; height: 100%; touch-action: none; } </style></head><body> <canvas id="renderCanvas"></canvas> <script type="text/javascript"> const canvas = document.getElementById("renderCanvas"); const engine = new BABYLON.Engine(canvas, true);
const createScene = function () { const scene = new BABYLON.Scene(engine); scene.clearColor = new BABYLON.Color4(0.3, 0.3, 0.3, 1.0);
const camera = new BABYLON.ArcRotateCamera("Camera", -Math.PI / 2, Math.PI / 2.5, 10, BABYLON.Vector3.Zero(), scene); camera.attachControl(canvas, true);
const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene); light.intensity = 0.9;
const box = BABYLON.MeshBuilder.CreateBox("box", { size: 3 }, scene);
// Create Dynamic Texture const dynamicTexture = new BABYLON.DynamicTexture("dynamic texture", { width: 512, height: 256 }, scene, true);
// Apply texture to material const material = new BABYLON.StandardMaterial("Mat", scene); material.diffuseTexture = dynamicTexture; box.material = material;
// Draw text onto the texture const font = "bold 70px Arial"; dynamicTexture.drawText("Box Text", 80, 135, font, "green", "white", true, true); // Draw text requires an update, but the last param 'true' handles it here. // If drawing with context, call dynamicTexture.update() afterwards. // 绘制文本需要更新,但最后一个参数 'true' 在这里已经处理了。 // 如果使用上下文绘制,请在之后调用 dynamicTexture.update()。
return scene; };
const scene = createScene(); engine.runRenderLoop(function () { scene.render(); }); window.addEventListener("resize", function () { engine.resize(); }); </script></body></html>输出描述 (文本示例)
Section titled “输出描述 (文本示例)”这个示例展示了一个在中心旋转的简单立方体。立方体的表面应用了动态生成的纹理:一个白色背景上绘制着加粗绿色 Arial 字体的文本 “Box Text”。
示例: 地面上的 Canvas 绘制
Section titled “示例: 地面上的 Canvas 绘制”<!DOCTYPE html><html><head> <meta charset="utf-8"/> <title>Babylon.js - Dynamic Texture Canvas Drawing</title> <script src="https://cdn.babylonjs.com/babylon.js"></script> <style> html, body { overflow: hidden; width: 100%; height: 100%; margin: 0; padding: 0; } #renderCanvas { width: 100%; height: 100%; touch-action: none; } </style></head><body> <canvas id="renderCanvas"></canvas> <script type="text/javascript"> const canvas = document.getElementById("renderCanvas"); const engine = new BABYLON.Engine(canvas, true);
const createScene = function () { const scene = new BABYLON.Scene(engine); scene.clearColor = new BABYLON.Color4(0.1, 0.2, 0.3, 1.0);
const camera = new BABYLON.ArcRotateCamera("Camera", Math.PI / 2, Math.PI / 4, 25, BABYLON.Vector3.Zero(), scene); camera.attachControl(canvas, true);
const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene); light.intensity = 0.8;
const ground = BABYLON.MeshBuilder.CreateGround("ground", { width: 15, height: 15 }, scene);
// Create Dynamic Texture (square) const dynamicTexture = new BABYLON.DynamicTexture("dynamic texture", 512, scene, true);
// Apply texture to ground material const material = new BABYLON.StandardMaterial("Mat", scene); material.diffuseTexture = dynamicTexture; ground.material = material;
// Get context and draw using Canvas API const ctx = dynamicTexture.getContext();
// Clear background (optional) ctx.fillStyle = "#4488AA"; // 偏蓝色的背景 ctx.fillRect(0, 0, 512, 512);
// Draw a bezier curve (e.g., a heart shape) // 绘制一条贝塞尔曲线 (例如,心形) ctx.beginPath(); ctx.moveTo(256, 150); // 起始点略微偏离中心顶部 ctx.bezierCurveTo(256, 130, 230, 100, 190, 100); // 左上方曲线 ctx.bezierCurveTo(120, 100, 120, 180, 120, 180); // 左侧曲线 ctx.bezierCurveTo(120, 250, 190, 310, 256, 350); // 底部点曲线 ctx.bezierCurveTo(322, 310, 392, 250, 392, 180); // 右侧曲线 ctx.bezierCurveTo(392, 180, 392, 100, 332, 100); // 右上方曲线 ctx.bezierCurveTo(290, 100, 256, 130, 256, 150); // 连接回到起始点附近 ctx.closePath();
ctx.fillStyle = "red"; ctx.fill(); ctx.strokeStyle = "darkred"; ctx.lineWidth = 5; ctx.stroke();
// Update the texture to show the drawing // 更新纹理以显示绘制内容 dynamicTexture.update();
return scene; };
const scene = createScene(); engine.runRenderLoop(function () { scene.render(); }); window.addEventListener("resize", function () { engine.resize(); }); </script></body></html>输出描述 (Canvas 绘制示例)
Section titled “输出描述 (Canvas 绘制示例)”这个示例显示了一个地面平面。应用到地面的纹理是动态生成的。它展示了一个偏蓝色的背景,中心有一个用贝塞尔曲线(通过 canvas 上下文绘制)绘制的大红色心形。
频繁地更新 DynamicTexture,特别是尺寸较大的纹理(例如,每帧更新),会影响性能,因为它涉及 CPU 侧的绘制和 GPU 的纹理上传。对于不经常变化的元素,或者通过优化更新频率来谨慎使用。对于高度动态的文本或 UI,可以考虑使用 Babylon.js GUI 系统,它通常性能更佳。