You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在服务器端向3D文件添加文本

Linux后端REST API中给OBJ模型添加文本并保存的实现方案

为什么Three.js在后端无法生效

Three.js依赖浏览器的WebGL渲染环境和DOM API,Linux服务器端没有这些运行环境,直接调用会因缺少相关API而报错,因此需要采用无头渲染方案或使用不依赖浏览器的3D模型处理库。

方案一:Node.js(Three.js + 无头浏览器)

通过无头浏览器模拟浏览器环境,运行Three.js代码完成模型修改,是最贴近前端开发习惯的方案。

  • 依赖安装:
    npm install three puppeteer
    
  • 核心实现逻辑:
    1. 启动无头Chrome实例,加载包含Three.js及相关加载器的页面。
    2. 在页面环境中加载OBJ模型、生成文本几何体,调整位置后合并到场景。
    3. 导出合并后的OBJ数据,保存到服务器本地。
  • 示例代码:
    const puppeteer = require('puppeteer');
    const fs = require('fs');
    const path = require('path');
    
    async function addTextToObj(inputObjPath, customText, outputObjPath) {
      const browser = await puppeteer.launch({ 
        headless: 'new',
        args: ['--no-sandbox', '--disable-setuid-sandbox'] // Linux环境需要的参数
      });
      const page = await browser.newPage();
    
      // 注入Three.js及所需加载器
      await page.setContent(`
        <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/loaders/OBJLoader.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/loaders/FontLoader.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/exporters/OBJExporter.js"></script>
        <script>
          window.processModel = async (objData, text) => {
            const scene = new THREE.Scene();
            const loader = new THREE.OBJLoader();
            const model = loader.parse(objData);
            
            // 加载字体生成文本网格
            const fontLoader = new THREE.FontLoader();
            const font = await fontLoader.loadAsync('https://cdn.jsdelivr.net/npm/three@0.128.0/examples/fonts/helvetiker_regular.typeface.json');
            const textGeo = new THREE.TextGeometry(text, {
              font: font,
              size: 0.5,
              height: 0.1,
              curveSegments: 12
            });
            const textMesh = new THREE.Mesh(textGeo);
            textMesh.position.set(0, 2, 0); // 调整文本位置到模型上方
            
            scene.add(model);
            scene.add(textMesh);
            
            // 导出OBJ
            const exporter = new THREE.OBJExporter();
            return exporter.parse(scene);
          };
        </script>
      `);
    
      // 读取本地OBJ文件内容
      const objContent = fs.readFileSync(inputObjPath, 'utf8');
      // 在浏览器环境中执行模型处理
      const resultObj = await page.evaluate((data, text) => window.processModel(data, text), objContent, customText);
      // 保存结果
      fs.writeFileSync(outputObjPath, resultObj);
    
      await browser.close();
    }
    
    // API接口中可直接调用此方法
    // addTextToObj('./models/input.obj', 'My Custom Text', './models/output.obj');
    
  • 注意事项:
    • 字体文件建议下载到本地,避免依赖外部CDN;
    • Linux服务器需安装无头Chrome依赖(如libnss3、libxss1等,puppeteer安装时会提示);
    • 需根据原模型尺寸调整文本的大小和位置,避免错位。

方案二:.NET Core(C#)

使用AssimpNet处理3D模型,结合字体库生成文本网格,适合.NET技术栈的项目。

  • NuGet包安装:
    Install-Package AssimpNet
    Install-Package SixLabors.Fonts
    
  • 核心实现逻辑:
    1. 用AssimpNet加载OBJ模型;
    2. 用SixLabors.Fonts将文本转换为矢量路径,再将路径拉伸为3D网格;
    3. 将文本网格合并到原模型场景,导出为新OBJ。
  • 示例代码片段:
    using Assimp;
    using SixLabors.Fonts;
    using SixLabors.Shapes;
    
    public static void AddTextToModel(string inputPath, string text, string outputPath)
    {
        // 加载原OBJ模型
        var importer = new AssimpContext();
        var scene = importer.ImportFile(inputPath, PostProcessSteps.Triangulate | PostProcessSteps.FlipUVs);
    
        // 生成文本矢量路径
        var font = SystemFonts.Get("Arial");
        var glyphs = font.CreateGlyphs(text, new RendererOptions(font, 24));
        var path = new PathBuilder().AddGlyphs(glyphs).Build();
    
        // 将2D路径转为3D拉伸网格
        var textMesh = CreateExtrudedMesh(path, 5f);
        textMesh.Name = "CustomText";
    
        // 添加到模型场景
        scene.Meshes.Add(textMesh);
    
        // 导出新OBJ
        importer.ExportFile(scene, outputPath, FileFormat.Obj);
    }
    
    // 辅助方法:将2D路径拉伸为3D网格
    private static Mesh CreateExtrudedMesh(IPath path, float thickness)
    {
        var mesh = new Mesh();
        // 此处需实现路径顶点的生成逻辑,包括上下表面和侧面的三角面
        // 可参考AssimpNet的Mesh结构,手动填充Vertices、Faces等属性
        return mesh;
    }
    
  • 注意事项:
    • AssimpNet默认使用左手坐标系,若原模型是右手系(如Three.js导出的),需添加PostProcessSteps.FlipWindingOrder处理;
    • 文本转3D网格的逻辑需要自己实现,或寻找第三方辅助库简化开发。

方案三:C++

基于Assimp和FreeType实现,性能最优,适合高并发、高性能需求的场景。

  • 依赖安装(Ubuntu/Debian):
    sudo apt-get install libassimp-dev libfreetype6-dev
    
  • 核心实现逻辑:
    1. 用Assimp加载OBJ模型;
    2. 用FreeType解析字体,生成文本的字形轮廓;
    3. 将2D轮廓拉伸为3D网格,合并到原模型;
    4. 导出新的OBJ文件。
  • 示例代码片段:
    #include <assimp/Importer.hpp>
    #include <assimp/scene.h>
    #include <assimp/postprocess.h>
    #include <assimp/Exporter.hpp>
    #include <ft2build.h>
    #include FT_FREETYPE_H
    #include <vector>
    #include <string>
    
    aiMesh* CreateTextMesh(FT_Face face, const std::string& text, float thickness) {
        aiMesh* mesh = new aiMesh();
        // 遍历每个字符,解析字形轮廓,生成3D网格的顶点和三角面
        // 需处理轮廓的每个点,生成上下表面和侧面的顶点数据
        return mesh;
    }
    
    void AddTextToObj(const std::string& inputPath, const std::string& text, const std::string& outputPath) {
        // 加载原模型
        Assimp::Importer importer;
        const aiScene* scene = importer.ReadFile(inputPath, aiProcess_Triangulate);
    
        // 初始化FreeType
        FT_Library ft;
        FT_Init_FreeType(&ft);
        FT_Face face;
        // 使用系统字体,路径需根据Linux环境调整
        FT_New_Face(ft, "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 0, &face);
        FT_Set_Pixel_Sizes(face, 0, 48);
    
        // 生成文本网格
        aiMesh* textMesh = CreateTextMesh(face, text, 2.0f);
    
        // 合并到原场景
        aiScene* editableScene = const_cast<aiScene*>(scene);
        editableScene->mMeshes = reinterpret_cast<aiMesh**>(realloc(editableScene->mMeshes, sizeof(aiMesh*) * (editableScene->mNumMeshes + 1)));
        editableScene->mMeshes[editableScene->mNumMeshes++] = textMesh;
    
        // 导出OBJ
        Assimp::Exporter exporter;
        exporter.Export(editableScene, "obj", outputPath);
    
        // 清理资源
        FT_Done_Face(face);
        FT_Done_FreeType(ft);
    }
    
  • 注意事项:
    • 需手动管理内存,避免内存泄漏;
    • FreeType的字形轮廓处理需要细致实现,确保网格拓扑正确;
    • 可封装为REST API(如用FastCGI或ASP.NET Core托管C++服务)。

内容的提问来源于stack exchange,提问作者cansado2930

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 15:54:59