Fitur dan Fungsionalitas

Aspose.3D FOSS untuk TypeScript adalah perpustakaan Node.js berlisensi MIT untuk memuat, membangun, dan mengekspor adegan 3D. Ia dilengkapi dengan definisi tipe TypeScript lengkap, satu ketergantungan runtime (xmldom).

Instalasi dan Penyiapan

Instal paket dari npm menggunakan satu perintah:

npm install @aspose/3d

Paket ini menargetkan CommonJS dan memerlukan Node.js 18 atau lebih baru. Setelah instalasi, verifikasi bahwa tsconfig.json menyertakan opsi kompilator berikut untuk kompatibilitas penuh:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "strict": true
  }
}

Impor utama Scene kelas dari akar paket. Kelas opsi khusus format diimpor dari sub‑path masing‑masing:

import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';

Fitur dan Fungsionalitas

Dukungan Format

Aspose.3D FOSS for TypeScript membaca dan menulis enam format file 3D utama. Deteksi format otomatis berdasarkan nomor magis biner saat memuat, sehingga Anda tidak perlu menyebutkan format sumber secara eksplisit.

FormatBacaTulisCatatan
OBJ (Wavefront)YaYaMembaca/menulis .mtl material; gunakan ObjLoadOptions.enableMaterials untuk impor
glTF 2.0YaYaformat teks JSON; material PBR
GLBYaYaBinary glTF; setel GltfSaveOptions.binaryMode = true
STLYaYaBiner dan ASCII; putaran penuh terverifikasi
3MFYaYa3D Manufacturing Format with color and material metadata
FBXTidak*Tidak*Importer/exporter ada tetapi deteksi otomatis format tidak terhubung
COLLADA (DAE)YaYaSkala unit, geometri, material, dan klip animasi

Memuat OBJ dengan material:

import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';

const scene = new Scene();
const options = new ObjLoadOptions();
options.enableMaterials = true;
options.flipCoordinateSystem = false;
options.scale = 1.0;
options.normalizeNormal = true;
scene.open('model.obj', options);

Menyimpan ke GLB (binary glTF):

import { Scene } from '@aspose/3d';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';

const scene = new Scene();
// ... build or load scene content

const opts = new GltfSaveOptions();
opts.binaryMode = true;
scene.save('output.glb', GltfFormat.getInstance(), opts);

Graf Adegan

Semua konten 3D diatur sebagai pohon dari Node objek yang berakar di scene.rootNode. Setiap node dapat membawa sebuah Entity (sebuah Mesh, Camera, Light, atau lainnya SceneObject) dan sebuah Transform yang menempatkannya relatif terhadap induknya.

Kelas utama dalam grafik adegan:

  • Scene: kontainer tingkat atas; menampung rootNode dan animationClips
  • Node: node pohon bernama dengan childNodes, entity, transform, dan materials
  • Entity: kelas dasar untuk objek yang dapat dilampirkan (Mesh, Camera, Light)
  • SceneObject: kelas dasar yang dibagikan oleh Node dan Entity
  • A3DObject: kelas dasar akar dengan name dan kantong properti
  • Transform: translasi lokal, rotasi (Euler dan Quaternion), dan skala

Menelusuri grafik adegan:

import { Scene, Node, Mesh } from '@aspose/3d';

const scene = new Scene();
scene.open('model.obj');

function visit(node: Node, depth: number = 0): void {
  const indent = '  '.repeat(depth);
  console.log(`${indent}Node: ${node.name}`);
  if (node.entity) {
    console.log(`${indent}  Entity: ${node.entity.constructor.name}`);
  }
  for (const child of node.childNodes) {
    visit(child, depth + 1);
  }
}

visit(scene.rootNode);

Membuat hierarki adegan secara programatis:

import { Scene, Node } from '@aspose/3d';

const scene = new Scene();
const parent = scene.rootNode.createChildNode('chassis');
const wheel = parent.createChildNode('wheel_fl');
wheel.transform.translation.set(0.9, -0.3, 1.4);

Geometri dan Mesh

Mesh adalah tipe geometri utama. Ini memperluas Geometry dan mengekspos titik kontrol (vertex), indeks poligon, serta elemen vertex untuk normal, UV, dan warna vertex.

Kelas geometri utama:

  • Mesh: mesh poligon dengan controlPoints dan polygonCount
  • Geometry: kelas dasar dengan manajemen elemen-vertex
  • VertexElementNormal: normal per-vertex atau per-polygon-vertex
  • VertexElementUV: koordinat tekstur (satu atau lebih saluran UV)
  • VertexElementVertexColor: data warna per-vertex
  • MappingMode: mengontrol bagaimana data elemen dipetakan ke poligon (CONTROL_POINT, POLYGON_VERTEX, POLYGON, EDGE, ALL_SAME)
  • ReferenceMode: mengontrol strategi pengindeksan (DIRECT, INDEX, INDEX_TO_DIRECT)
  • VertexElementType: mengidentifikasi semantik elemen vertex
  • TextureMapping: enumerasi saluran tekstur

Membaca data mesh dari adegan yang dimuat:

import { Scene, Mesh, VertexElementType } from '@aspose/3d';

const scene = new Scene();
scene.open('model.stl');

for (const node of scene.rootNode.childNodes) {
  if (node.entity instanceof Mesh) {
    const mesh = node.entity as Mesh;
    console.log(`Mesh "${node.name}": ${mesh.controlPoints.length} vertices, ${mesh.polygonCount} polygons`);

    const normals = mesh.getElement(VertexElementType.NORMAL);
    if (normals) {
      console.log(`  Normal mapping: ${normals.mappingMode}`);
    }
  }
}

Sistem Material

Aspose.3D FOSS untuk TypeScript mendukung tiga tipe material yang mencakup seluruh rentang dari shading Phong warisan hingga rendering berbasis fisika:

  • LambertMaterial: warna difus dan warna ambient; memetakan ke material OBJ/DAE sederhana
  • PhongMaterial: menambahkan warna spekular, kilap, dan emisif; tipe material OBJ default
  • PbrMaterial: model kekasaran/logam berbasis fisika; digunakan untuk impor dan ekspor glTF 2.0

Membaca material dari scene OBJ yang dimuat:

import { Scene, PhongMaterial, LambertMaterial } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';

const scene = new Scene();
const options = new ObjLoadOptions();
options.enableMaterials = true;
scene.open('model.obj', options);

for (const node of scene.rootNode.childNodes) {
  for (const mat of node.materials) {
    if (mat instanceof PhongMaterial) {
      const phong = mat as PhongMaterial;
      console.log(`  Phong: diffuse=${JSON.stringify(phong.diffuseColor)}, shininess=${phong.shininess}`);
    } else if (mat instanceof LambertMaterial) {
      console.log(`  Lambert: diffuse=${JSON.stringify((mat as LambertMaterial).diffuseColor)}`);
    }
  }
}

Menerapkan material PBR saat membangun scene glTF:

import { Scene, Node, PbrMaterial } from '@aspose/3d';
import { Vector3 } from '@aspose/3d';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';

const scene = new Scene();
const node = scene.rootNode.createChildNode('sphere');
const mat = new PbrMaterial();
mat.albedo = new Vector3(0.8, 0.2, 0.2);   // red-tinted albedo; albedo starts null, must assign
mat.metallicFactor = 0.0;
mat.roughnessFactor = 0.5;
node.material = mat;

const opts = new GltfSaveOptions();
opts.binaryMode = false;
scene.save('output.gltf', GltfFormat.getInstance(), opts);

Utilitas Matematika

Pustaka ini dilengkapi dengan satu set lengkap tipe matematika 3D, semuanya berjenis penuh:

  • Vector3: vektor 3-komponen; mendukung minus(), times(), dot(), cross(), normalize(), length, angleBetween()
  • Vector4: vektor 4-komponen untuk koordinat homogen
  • Matrix4: matriks transformasi 4×4 dengan concatenate(), transpose, decompose, setTRS
  • Quaternion: kuaternion rotasi dengan fromEulerAngle() (statik, tunggal), eulerAngles() (metode instance), slerp(), normalize()
  • BoundingBox: kotak pembatas yang sejajar sumbu dengan minimum, maximum, center, size, merge
  • FVector3: varian presisi tunggal dari Vector3 digunakan dalam data elemen vertex

Menghitung kotak pembatas dari vertex mesh:

import { Scene, Mesh, Vector3, BoundingBox } from '@aspose/3d';

const scene = new Scene();
scene.open('model.obj');

let box = new BoundingBox();
for (const node of scene.rootNode.childNodes) {
  if (node.entity instanceof Mesh) {
    for (const pt of (node.entity as Mesh).controlPoints) {
      box.merge(new Vector3(pt.x, pt.y, pt.z));
    }
  }
}
console.log('Center:', box.center);
console.log('Extents:', box.size);

Membangun transformasi dari sudut Euler:

import { Quaternion, Vector3, Matrix4 } from '@aspose/3d';

const rot = Quaternion.fromEulerAngle(0, Math.PI / 4, 0); // 45° around Y
const mat = new Matrix4();
mat.setTRS(new Vector3(0, 0, 0), rot, new Vector3(1, 1, 1));

Sistem Animasi

API animasi memodelkan klip, node, kanal, dan urutan keyframe:

  • AnimationClip: koleksi bernama dari node animasi; diakses melalui scene.animationClips; mengekspos animations: AnimationNode[]
  • AnimationNode: grup bernama dari BindPoints; dibuat melalui clip.createAnimationNode(name), diakses melalui clip.animations
  • BindPoint: mengikat sebuah AnimationNode ke properti tertentu pada objek scene; mengekspos property dan channelsCount
  • AnimationChannel:memperluas KeyframeSequence; menyimpan terpisah keyframeSequence; diakses melalui bindPoint.getChannel(name)
  • KeyFrame: satu pasangan waktu/nilai; membawa per-keyframe interpolation: Interpolation
  • KeyframeSequence: daftar terurut dari KeyFrame objek melalui keyFrames; memiliki preBehavior dan postBehavior (Extrapolation)
  • Interpolation: enum: LINEAR, CONSTANT, BEZIER, B_SPLINE, CARDINAL_SPLINE, TCB_SPLINE
  • Extrapolation: kelas dengan type: ExtrapolationType dan repeatCount: number
  • ExtrapolationType: enum: CONSTANT, GRADIENT, CYCLE, CYCLE_RELATIVE, OSCILLATE

Membaca data animasi dari scene yang dimuat:

import { Scene, AnimationNode, BindPoint } from '@aspose/3d';

const scene = new Scene();
scene.open('animated.dae');   // COLLADA animation import is supported

for (const clip of scene.animationClips) {
  console.log(`Clip: "${clip.name}"`);
  for (const animNode of clip.animations) {          // clip.animations, not clip.nodes
    console.log(`  AnimationNode: ${animNode.name}`);
    for (const bp of animNode.bindPoints) {           // animNode.bindPoints, not animNode.channels
      console.log(`  BindPoint: property="${bp.property.name}", channels=${bp.channelsCount}`);
    }
  }
}

Dukungan Stream dan Buffer

Gunakan scene.openFromBuffer() untuk memuat adegan 3D langsung dari memori Buffer. Ini adalah pola yang direkomendasikan untuk fungsi serverless, pipeline streaming, dan pemrosesan aset yang diambil melalui HTTP tanpa menulis ke disk.

import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
import * as fs from 'fs';

// Load file into memory, then parse from buffer
const buffer: Buffer = fs.readFileSync('model.obj');
const scene = new Scene();
const options = new ObjLoadOptions();
options.enableMaterials = true;
scene.openFromBuffer(buffer, options);

for (const node of scene.rootNode.childNodes) {
  if (node.entity) {
    console.log(node.name, node.entity.constructor.name);
  }
}

Deteksi otomatis format dari magic number biner berlaku saat memuat dari buffer, sehingga file GLB, STL binary, dan 3MF dikenali tanpa perlu menyebutkan parameter format.

Contoh Penggunaan

Contoh 1: Muat OBJ dan Ekspor ke GLB

Contoh ini memuat file Wavefront OBJ dengan material, kemudian mengekspor ulang scene sebagai file glTF biner (GLB) yang cocok untuk penggunaan web dan mesin game.

import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';

function convertObjToGlb(inputPath: string, outputPath: string): void {
  const scene = new Scene();

  const loadOpts = new ObjLoadOptions();
  loadOpts.enableMaterials = true;
  loadOpts.flipCoordinateSystem = false;
  loadOpts.normalizeNormal = true;
  scene.open(inputPath, loadOpts);

  // Report what was loaded
  for (const node of scene.rootNode.childNodes) {
    if (node.entity) {
      console.log(`Loaded: ${node.name} (${node.entity.constructor.name})`);
    }
  }

  const saveOpts = new GltfSaveOptions();
  saveOpts.binaryMode = true; // write .glb instead of .gltf + .bin
  scene.save(outputPath, GltfFormat.getInstance(), saveOpts);

  console.log(`Exported GLB to: ${outputPath}`);
}

convertObjToGlb('input.obj', 'output.glb');

Contoh 2: Putar Balik STL dengan Validasi Normal

Contoh ini memuat file STL biner, mencetak informasi normal per-vertex, kemudian mengekspor ulang scene sebagai STL ASCII dan memverifikasi proses putar balik.

import { Scene, Mesh, VertexElementNormal, VertexElementType } from '@aspose/3d';
import { StlLoadOptions, StlSaveOptions } from '@aspose/3d/formats/stl';

const scene = new Scene();
const loadOpts = new StlLoadOptions();
scene.open('model.stl', loadOpts);

let totalPolygons = 0;
for (const node of scene.rootNode.childNodes) {
  if (node.entity instanceof Mesh) {
    const mesh = node.entity as Mesh;
    totalPolygons += mesh.polygonCount;

    const normElem = mesh.getElement(VertexElementType.NORMAL) as VertexElementNormal | null;
    if (normElem) {
      console.log(`  Normals: ${normElem.data.length} entries, mapping=${normElem.mappingMode}`);
    }
  }
}
console.log(`Total polygons: ${totalPolygons}`);

// Re-export as ASCII STL
const saveOpts = new StlSaveOptions();
saveOpts.binaryMode = false; // ASCII output
scene.save('output_ascii.stl', saveOpts);

Contoh 3: Bangun Adegan Secara Programatis dan Simpan sebagai glTF

Contoh ini membangun sebuah adegan dengan material PBR dari awal dan menyimpannya sebagai file glTF JSON.

import { Scene, Mesh, PbrMaterial, Vector4, Vector3 } from '@aspose/3d';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';

const scene = new Scene();
const node = scene.rootNode.createChildNode('floor');

// Build a simple quad mesh (two triangles)
// controlPoints are Vector4 (x, y, z, w) where w=1 for positions
const mesh = new Mesh();
mesh.controlPoints.push(
  new Vector4(-1, 0, -1, 1),
  new Vector4( 1, 0, -1, 1),
  new Vector4( 1, 0,  1, 1),
  new Vector4(-1, 0,  1, 1),
);
mesh.createPolygon([0, 1, 2]);
mesh.createPolygon([0, 2, 3]);
node.entity = mesh;

// Apply a PBR material
const mat = new PbrMaterial();
mat.albedo = new Vector3(0.6, 0.6, 0.6);   // albedo starts null, must assign
mat.metallicFactor = 0.0;
mat.roughnessFactor = 0.8;
node.material = mat;

// Save as JSON glTF
const opts = new GltfSaveOptions();
opts.binaryMode = false;
scene.save('floor.gltf', GltfFormat.getInstance(), opts);
console.log('Scene written to floor.gltf');

Tips dan Praktik Terbaik

  • Gunakan ObjLoadOptions.enableMaterials = true kapanpun Anda membutuhkan data material dari file .mtl. Tanpa itu, daftar material pada setiap node akan kosong.
  • Lebih disarankan binaryMode = true untuk GLB saat menghasilkan aset untuk web atau mesin game. GLB biner adalah satu file mandiri tunggal dan memuat lebih cepat di peramban dan mesin dibandingkan dengan pemisahan JSON + .bin.
  • Gunakan openFromBuffer() di lingkungan serverless untuk menghindari I/O file sementara. Ambil aset, lewati Buffer langsung, dan tulis output ke aliran atau buffer lain.
  • Periksa node.entity sebelum casting: tidak semua node membawa entitas. Selalu lindungi dengan sebuah instanceof cek sebelum mengakses Meshproperti khusus - seperti controlPoints.
  • Atur normalizeNormal = true di ObjLoadOptions ketika file OBJ sumber Anda berasal dari sumber yang tidak tepercaya. Ini mencegah normal yang cacat menyebar ke proses rendering atau langkah validasi hilir.
  • Pertahankan strict: true di tsconfig.json: pustaka ini ditulis dengan noImplicitAny dan strictNullChecks. Menonaktifkan strict menyembunyikan kesalahan tipe yang sebenarnya dan mengurangi nilai API yang bertipe.
  • Telusuri via childNodes, bukan loop indeks: the childNodes properti mengembalikan iterable; hindari bergantung pada pengindeksan numerik untuk kompatibilitas ke depan.

Masalah Umum

GejalaPenyebab KemungkinanPerbaikan
Daftar material kosong setelah pemuatan OBJenableMaterials tidak disetelAtur options.enableMaterials = true
File GLB berisi sidecar .bin terpisahbinaryMode menggunakan default ke falseAtur opts.binaryMode = true
Normal vertex tidak ada dalam output STLMode STL ASCII menghilangkan normal per-faceBeralih ke binaryMode = true atau hitung normal sebelum ekspor
node.entity selalu nullHanya menelusuri rootNode, bukan anaknyaMerekur ke node.childNodes
Kesalahan TypeScript: properti tidak adaLama @types cacheJalankan npm install @aspose/3d lagi; tidak terpisah @types paket diperlukan
openFromBuffer melempar kesalahan formatFormat tidak dapat dideteksi otomatis dari magicBerikan kelas opsi format eksplisit sebagai argumen kedua

Pertanyaan yang Sering Diajukan

Apakah perpustakaan memerlukan addon native atau paket sistem apa pun? Tidak. Aspose.3D FOSS untuk TypeScript memiliki satu dependensi runtime: xmldom, yang merupakan JavaScript murni dan dipasang secara otomatis oleh npm. Tidak ada .node addon native dan tidak ada paket sistem yang harus dipasang.

Versi Node.js mana yang didukung? Node.js 18, 20, dan 22 LTS. Perpustakaan menargetkan output CommonJS dan menggunakan fitur bahasa ES2020 secara internal.

Bisakah saya menggunakan perpustakaan ini dalam bundel browser (webpack/esbuild)? Perpustakaan menargetkan Node.js dan menggunakan Node.js fs dan Buffer API. Penggabungan di browser tidak didukung secara resmi. Untuk penggunaan di browser, muat adegan di sisi server dan kirimkan hasilnya (mis., sebagai GLB) ke klien.

Apa perbedaan antara GltfSaveOptions.binaryMode = true dan false? binaryMode = false menghasilkan sebuah .gltf file JSON plus sebuah terpisah .bin sidecar buffer biner. binaryMode = true menghasilkan satu yang mandiri .glb file. Gunakan true untuk pengiriman aset produksi.

Apakah saya dapat memuat file dari respons HTTP tanpa menyimpannya ke disk? Ya. Ambil respons sebagai a Buffer (misalnya, menggunakan node-fetch atau built-in fetch di Node 18+), lalu panggil scene.openFromBuffer(buffer, options).

Apakah dukungan FBX lengkap? Tidak. Kelas impor dan ekspor FBX ada di perpustakaan, tetapi FBX tidak terhubung ke Scene.open() atau Scene.save() deteksi otomatis. Memanggil scene.open('file.fbx') tidak akan memanggil importer FBX; file akan diproses oleh jalur cadangan STL. Gunakan kelas importer/ekspor khusus FBX secara langsung jika Anda memerlukan I/O FBX. Lihat tabel dukungan format di atas yang menandai FBX sebagai No*.

Apakah perpustakaan mendukung TypeScript 4.x? TypeScript 5.0+ disarankan. TypeScript 4.7+ seharusnya berfungsi dalam praktik, tetapi perpustakaan ini diuji dan ditulis terhadap 5.0+.

Ringkasan Referensi API

KelasModulTujuan
Scene@aspose/3dKontainer adegan tingkat atas; open(), openFromBuffer(), save(), rootNode, animationClips
Node@aspose/3dNode grafik-skena; childNodes, entity, transform, materials, createChildNode()
Entity@aspose/3dKelas dasar untuk objek yang dapat dilampirkan pada skena
SceneObject@aspose/3dKelas dasar yang dibagikan oleh Node dan Entity
A3DObject@aspose/3dBasis akar dengan name dan property bag
Transform@aspose/3dTranslasi, rotasi, dan skala lokal
Mesh@aspose/3dMesh poligon; controlPoints, polygonCount, createPolygon(), elemen vertex
Geometry@aspose/3dKelas dasar untuk tipe geometri
Camera@aspose/3dEntitas kamera dengan field-of-view dan pengaturan proyeksi
Light@aspose/3dEntitas cahaya (point, directional, spot)
LambertMaterial@aspose/3dModel shading Diffuse + ambient
PhongMaterial@aspose/3dShading Phong dengan specular dan emissive
PbrMaterial@aspose/3dModel berbasis fisik roughness/metallic untuk glTF
Vector3@aspose/3d3-component double-precision vector
Vector4@aspose/3d4-component vector for homogeneous math
Matrix4@aspose/3d4×4 transformation matrix
Quaternion@aspose/3dQuaternion rotasi
BoundingBox@aspose/3dKotak pembatas yang sejajar sumbu
FVector3@aspose/3dVarian presisi tunggal dari Vector3
VertexElementNormal@aspose/3dNormal per-vertex atau per-polygon-vertex
VertexElementUV@aspose/3dElemen vertex koordinat tekstur
VertexElementVertexColor@aspose/3dElemen vertex warna per-vertex
MappingMode@aspose/3dEnum: CONTROL_POINT, POLYGON_VERTEX, POLYGON, ALL_SAME
ReferenceMode@aspose/3dEnum: DIRECT, INDEX, INDEX_TO_DIRECT
AnimationClip@aspose/3dAnimasi bernama; mengekspose animations: AnimationNode[]; dibuat melalui scene.createAnimationClip(name)
AnimationNode@aspose/3dGrup bernama dari BindPoints; dibuat melalui clip.createAnimationNode(name)
BindPoint@aspose/3dMengikat sebuah AnimationNode ke properti objek adegan; mengekspose property dan channelsCount
AnimationChannel@aspose/3dMemperluas KeyframeSequence; menyimpan sebuah keyframeSequence; diakses melalui bindPoint.getChannel(name)
KeyFrame@aspose/3dPasangan keyframe waktu/nilai tunggal; membawa interpolation: Interpolation
KeyframeSequence@aspose/3dTerurut keyFrames daftar; preBehavior/postBehavior adalah Extrapolation objek
Interpolation@aspose/3dEnum: LINEAR, CONSTANT, BEZIER, B_SPLINE, CARDINAL_SPLINE, TCB_SPLINE
Extrapolation@aspose/3dKelas dengan type: ExtrapolationType dan repeatCount: number
ExtrapolationType@aspose/3dEnum: CONSTANT, GRADIENT, CYCLE, CYCLE_RELATIVE, OSCILLATE
ObjLoadOptions@aspose/3d/formats/objOpsi impor OBJ: enableMaterials, flipCoordinateSystem, scale, normalizeNormal
GltfSaveOptions@aspose/3d/formats/gltfOpsi ekspor glTF/GLB: binaryMode
GltfFormat@aspose/3d/formats/gltfInstansi format untuk glTF/GLB; lewati ke scene.save()
StlLoadOptions@aspose/3d/formats/stlOpsi impor STL
StlSaveOptions@aspose/3d/formats/stlOpsi ekspor STL: binaryMode
StlImporter@aspose/3d/formats/stlPembaca STL tingkat rendah
StlExporter@aspose/3d/formats/stlPenulis STL tingkat rendah
 Bahasa Indonesia