Fix material assignment to animation.js demo

This commit is contained in:
Syoyo Fujita
2025-12-02 10:02:27 +09:00
parent 3412e762f0
commit c838e898bc
6 changed files with 264 additions and 29 deletions

View File

@@ -8,6 +8,7 @@ list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../cmake)
option(TINYUSDZ_WASM64 "Use wasm64(memory64). Available only for Chrome and Firefox as of 2025 Jul" OFF)
option(TINYUSDZ_WASM_DEBUG "Enable WASM debug mode with source maps and assertions" OFF)
if (TINYUSDZ_WASM64)
set(BUILD_TARGET "tinyusdz_64")
@@ -25,12 +26,24 @@ set(CMAKE_CXX_EXTENSIONS OFF)
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
if (TINYUSDZ_WASM64)
set(CMAKE_CXX_FLAGS_DEBUG "-g4 -sMEMORY64")
set(CMAKE_C_FLAGS_DEBUG "-g4 -sMEMORY64")
if (TINYUSDZ_WASM_DEBUG)
# Enhanced debug mode with source maps
if (TINYUSDZ_WASM64)
set(CMAKE_CXX_FLAGS_DEBUG "-g -gsource-map -sMEMORY64")
set(CMAKE_C_FLAGS_DEBUG "-g -gsource-map -sMEMORY64")
else()
set(CMAKE_CXX_FLAGS_DEBUG "-g -gsource-map")
set(CMAKE_C_FLAGS_DEBUG "-g -gsource-map")
endif()
else()
set(CMAKE_CXX_FLAGS_DEBUG "-g4") # -sMEMORY64"
set(CMAKE_C_FLAGS_DEBUG "-g4") # -sMEMORY64"
# Standard debug mode
if (TINYUSDZ_WASM64)
set(CMAKE_CXX_FLAGS_DEBUG "-g4 -sMEMORY64")
set(CMAKE_C_FLAGS_DEBUG "-g4 -sMEMORY64")
else()
set(CMAKE_CXX_FLAGS_DEBUG "-g4")
set(CMAKE_C_FLAGS_DEBUG "-g4")
endif()
endif()
elseif (CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
@@ -109,18 +122,37 @@ endif()
# flags = try to lower heap memory use
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
set(TINYUSDZ_EMCC_LINK_FLAGS "-g4 -sENVIRONMENT='web,worker,node' \
-sMALLOC=emmalloc \
-sSTACK_SIZE=1024000 \
-sALLOW_MEMORY_GROWTH=1 \
-sFILESYSTEM=0 \
-sSAFE_HEAP=1 \
-sWASM_BIGINT=1 \
-sMODULARIZE=1 -sEXPORT_ES6 \
-sINVOKE_RUN=0 --bind \
-sDISABLE_EXCEPTION_CATCHING=0 \
-sNO_DISABLE_EXCEPTION_CATCHING \
--source-map-base http://localhost:5173/ ")
if (TINYUSDZ_WASM_DEBUG)
# Enhanced debug mode with source maps, stack traces, and runtime checks
set(TINYUSDZ_EMCC_LINK_FLAGS "-g -gsource-map -sENVIRONMENT='web,worker,node' \
-sMALLOC=emmalloc \
-sSTACK_SIZE=1024000 \
-sALLOW_MEMORY_GROWTH=1 \
-sFILESYSTEM=0 \
-sSAFE_HEAP=1 \
-sSTACK_OVERFLOW_CHECK=2 \
-sASSERTIONS=2 \
-sWASM_BIGINT=1 \
-sMODULARIZE=1 -sEXPORT_ES6 \
-sINVOKE_RUN=0 --bind \
-sDISABLE_EXCEPTION_CATCHING=0 \
-sNO_DISABLE_EXCEPTION_CATCHING \
--source-map-base http://localhost:5173/ ")
else()
# Standard debug mode
set(TINYUSDZ_EMCC_LINK_FLAGS "-g4 -sENVIRONMENT='web,worker,node' \
-sMALLOC=emmalloc \
-sSTACK_SIZE=1024000 \
-sALLOW_MEMORY_GROWTH=1 \
-sFILESYSTEM=0 \
-sSAFE_HEAP=1 \
-sWASM_BIGINT=1 \
-sMODULARIZE=1 -sEXPORT_ES6 \
-sINVOKE_RUN=0 --bind \
-sDISABLE_EXCEPTION_CATCHING=0 \
-sNO_DISABLE_EXCEPTION_CATCHING \
--source-map-base http://localhost:5173/ ")
endif()
else()
set(TINYUSDZ_EMCC_LINK_FLAGS "-Oz -sENVIRONMENT='web,worker,node' \
-sMALLOC=emmalloc \

123
web/DEBUG_SOURCEMAP.md Normal file
View File

@@ -0,0 +1,123 @@
# WASM Debug Mode with Source Maps
This document explains how to build TinyUSDZ WASM with source maps for better debugging.
## Quick Start
```bash
# Build with source maps
./bootstrap-linux-debug-sourcemap.sh
cd build_debug_sourcemap
make -j8
# The output will include:
# - js/src/tinyusdz/tinyusdz.js
# - js/src/tinyusdz/tinyusdz.wasm
# - js/src/tinyusdz/tinyusdz.wasm.map (source map)
```
## What You Get
When building with `-DTINYUSDZ_WASM_DEBUG=ON`, you get:
1. **Source Maps** (`-gsource-map`)
- Maps WASM code back to C++ source files
- Enables viewing C++ source in browser DevTools
2. **Enhanced Stack Traces** (`-sDEMANGLE_SUPPORT=1`)
- C++ function names are demangled
- Shows actual function names instead of mangled symbols
3. **Runtime Checks**
- `-sASSERTIONS=2` - Runtime assertion checks
- `-sSTACK_OVERFLOW_CHECK=2` - Detect stack overflows
- `-sSAFE_HEAP=1` - Detect memory access errors
## Browser Setup
1. Open Chrome DevTools (F12)
2. Go to Settings (⚙️) → Preferences
3. Enable "Enable JavaScript source maps"
4. When an abort/crash occurs, you'll see C++ source lines in the stack trace
## Example Output
### Without Source Maps:
```
RuntimeError: abort(Error) at Error
at abort (wasm-function[1234]:0x5678)
```
### With Source Maps:
```
RuntimeError: abort(MaterialX conversion failed) at Error
at abort (src/tydra/materialx.cc:142:5)
at convertOpenPBR (src/tydra/materialx.cc:89:12)
at setupMesh (binding.cc:345:3)
```
## Manual Build
If you prefer to configure manually:
```bash
mkdir build_debug_sourcemap
cd build_debug_sourcemap
emcmake cmake .. \
-DCMAKE_BUILD_TYPE=Debug \
-DTINYUSDZ_WASM_DEBUG=ON
make -j8
```
## CMake Options
- `TINYUSDZ_WASM_DEBUG=ON` - Enable source maps and enhanced debugging
- `TINYUSDZ_WASM64=ON` - Use WASM64/Memory64 (optional, requires newer browsers)
## File Size Impact
Source maps increase file sizes:
| Build Type | .wasm Size | .wasm.map Size |
|------------|------------|----------------|
| Release | ~2-5 MB | N/A |
| Debug | ~5-10 MB | N/A |
| Debug + SourceMap | ~5-10 MB | ~15-30 MB |
**Note:** The `.wasm.map` file is only loaded when DevTools is open, so it doesn't affect production performance.
## Troubleshooting
### Source maps not loading
1. Check that `.wasm.map` file exists next to `.wasm` file
2. Verify the web server serves `.map` files (check MIME type)
3. Check browser console for CORS errors
4. Verify `--source-map-base http://localhost:5173/` matches your server URL
### Source files not showing
1. The source map contains paths relative to the build directory
2. Ensure source files haven't moved since build
3. Check browser DevTools → Sources tab for file tree
### Different dev server port
Edit `web/CMakeLists.txt` line 141:
```cmake
--source-map-base http://localhost:YOUR_PORT/
```
## Production Builds
For production, use the standard build without source maps:
```bash
./bootstrap-linux.sh
cd build
make -j8
```
This produces optimized, small WASM files without debug overhead.

View File

@@ -0,0 +1,23 @@
#!/bin/bash
# Build TinyUSDZ WASM with source maps and enhanced debugging
# This enables C++ source line visibility in browser DevTools on abort/crash
rm -rf build_debug_sourcemap
mkdir build_debug_sourcemap
emcmake cmake \
-DCMAKE_BUILD_TYPE=Debug \
-DTINYUSDZ_WASM_DEBUG=ON \
-DCMAKE_VERBOSE_MAKEFILE=1 \
-Bbuild_debug_sourcemap
echo ""
echo "Build configured with source maps enabled."
echo "To build, run:"
echo " cd build_debug_sourcemap && make -j$(nproc)"
echo ""
echo "Output will include:"
echo " - tinyusdz.wasm.map (source map file)"
echo " - Enhanced stack traces with C++ source lines"
echo " - Additional runtime checks (SAFE_HEAP, STACK_OVERFLOW_CHECK)"
echo ""

View File

@@ -0,0 +1,24 @@
#!/bin/bash
# Build TinyUSDZ WASM with source maps and enhanced debugging
# This enables C++ source line visibility in browser DevTools on abort/crash
rm -rf build_debug_sourcemap_64
mkdir build_debug_sourcemap_64
emcmake cmake \
-DCMAKE_BUILD_TYPE=Debug \
-DTINYUSDZ_WASM_DEBUG=ON \
-DTINYUSDZ_WASM64=1 \
-DCMAKE_VERBOSE_MAKEFILE=1 \
-Bbuild_debug_sourcemap_64
echo ""
echo "Build configured with source maps enabled."
echo "To build, run:"
echo " cd build_debug_sourcemap_64 && make -j$(nproc)"
echo ""
echo "Output will include:"
echo " - tinyusdz.wasm.map (source map file)"
echo " - Enhanced stack traces with C++ source lines"
echo " - Additional runtime checks (SAFE_HEAP, STACK_OVERFLOW_CHECK)"
echo ""

View File

@@ -759,7 +759,7 @@ async function loadUSDModel() {
};
// Build Three.js node from USD with MaterialX/OpenPBR support
const threeNode = TinyUSDZLoaderUtils.buildThreeNode(usdRootNode, defaultMtl, usd_scene, options);
const threeNode = await TinyUSDZLoaderUtils.buildThreeNode(usdRootNode, defaultMtl, usd_scene, options);
// Store USD scene reference for material reloading
threeNode.traverse((child) => {
@@ -2277,7 +2277,7 @@ async function loadUSDFromArrayBuffer(arrayBuffer, filename) {
};
// Build Three.js node from USD with MaterialX/OpenPBR support
const threeNode = TinyUSDZLoaderUtils.buildThreeNode(usdRootNode, defaultMtl, usd_scene, options);
const threeNode = await TinyUSDZLoaderUtils.buildThreeNode(usdRootNode, defaultMtl, usd_scene, options);
// Store USD scene reference for material reloading
threeNode.traverse((child) => {

View File

@@ -641,7 +641,7 @@ class TinyUSDZLoaderUtils extends LoaderUtils {
return geometry;
}
static setupMesh(mesh /* TinyUSDZLoaderNative::RenderMesh */, defaultMtl, usdScene, options) {
static async setupMesh(mesh /* TinyUSDZLoaderNative::RenderMesh */, defaultMtl, usdScene, options) {
const geometry = this.convertUsdMeshToThreeMesh(mesh);
@@ -654,13 +654,47 @@ class TinyUSDZLoaderUtils extends LoaderUtils {
mtl = defaultMtl || normalMtl
} else {
const usdMaterial = usdScene.getMaterial(mesh.materialId);
//console.log("usdMaterial:", usdMaterial);
// Validate materialId before attempting to get material
// materialId can be undefined, -1 (no material), or out of range
const hasMaterial = mesh.materialId !== undefined && mesh.materialId >= 0;
const pbrMaterial = this.convertUsdMaterialToMeshPhysicalMaterial(usdMaterial, usdScene);
//console.log("pbrMaterial:", pbrMaterial);
// Get material data in JSON format to access OpenPBR/MaterialX data
// Using getMaterialWithFormat ensures we get the full material structure including OpenPBR
let usdMaterialData = null;
if (hasMaterial) {
if (typeof usdScene.getMaterialWithFormat === 'function') {
const result = usdScene.getMaterialWithFormat(mesh.materialId, 'json');
if (!result.error) {
usdMaterialData = JSON.parse(result.data);
} else {
console.warn(`Failed to get material ${mesh.materialId} with format: ${result.error}`);
}
} else {
// Fallback to getMaterial if getMaterialWithFormat is not available
usdMaterialData = usdScene.getMaterial(mesh.materialId);
}
}
console.log(`Mesh materialId: ${mesh.materialId}, hasMaterial: ${hasMaterial}, usdMaterial: ${usdMaterialData ? 'valid' : 'null'}`);
let pbrMaterial;
if (usdMaterialData) {
// Use smart convertMaterial to handle both OpenPBR and UsdPreviewSurface
pbrMaterial = await this.convertMaterial(usdMaterialData, usdScene, {
preferredMaterialType: options.preferredMaterialType || 'auto',
envMap: options.envMap || null,
envMapIntensity: options.envMapIntensity || 1.0,
textureCache: options.textureCache || new Map(),
doubleSided: geometry.userData['doubleSided']
});
} else {
// No valid material - create default material
pbrMaterial = defaultMtl || new THREE.MeshPhysicalMaterial({
color: 0x888888,
roughness: 0.5,
metalness: 0.0
});
}
// Setting envmap is required for PBR materials to work correctly(e.g. clearcoat)
pbrMaterial.envMap = options.envMap || null;
@@ -672,7 +706,6 @@ class TinyUSDZLoaderUtils extends LoaderUtils {
if (Object.prototype.hasOwnProperty.call(geometry.userData, 'doubleSided')) {
if (geometry.userData.doubleSided) {
console.log(` Setting material to DoubleSide (from USD doubleSided=true)`);
usdMaterial.side = THREE.DoubleSide;
pbrMaterial.side = THREE.DoubleSide;
} else {
console.log(` Setting material to FrontSide (from USD doubleSided=false)`);
@@ -712,7 +745,7 @@ class TinyUSDZLoaderUtils extends LoaderUtils {
// Supported options
// 'overrideMaterial' : Override usd material with defaultMtl.
static buildThreeNode(usdNode /* TinyUSDZLoader.Node */, defaultMtl = null, usdScene /* TinyUSDZLoader.Scene */ = null, options = {})
static async buildThreeNode(usdNode /* TinyUSDZLoader.Node */, defaultMtl = null, usdScene /* TinyUSDZLoader.Scene */ = null, options = {})
/* => THREE.Object3D */ {
var node = new THREE.Group();
@@ -742,7 +775,7 @@ class TinyUSDZLoaderUtils extends LoaderUtils {
// contentId is the mesh ID in the USD scene.
const mesh = usdScene.getMesh(usdNode.contentId);
const threeMesh = this.setupMesh(mesh, defaultMtl, usdScene, options);
const threeMesh = await this.setupMesh(mesh, defaultMtl, usdScene, options);
node = threeMesh;
// Apply transform to mesh nodes as well
@@ -774,7 +807,7 @@ class TinyUSDZLoaderUtils extends LoaderUtils {
// traverse children
for (const child of usdNode.children) {
const childNode = this.buildThreeNode(child, defaultMtl, usdScene, options);
const childNode = await this.buildThreeNode(child, defaultMtl, usdScene, options);
node.add(childNode);
}
}