@needle-tools/usd 0.0.2-next.d90870e → 1.0.0-next.d536d99
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -1
- package/README.md +52 -9
- package/package.json +42 -10
- package/src/bindings/emHdBindings.js +5 -12227
- package/src/bindings/emHdBindings.wasm +0 -0
- package/src/bindings/index.js +130 -47
- package/src/bindings/openusd-build-info.json +40 -0
- package/src/create.three.js +362 -53
- package/src/hydra/ThreeJsRenderDelegate.js +959 -73
- package/src/plugins/index.js +1 -2
- package/src/plugins/needle.js +37 -2
- package/src/types/bindings.d.ts +296 -3
- package/src/types/create.three.d.ts +78 -7
- package/src/types/hydra.d.ts +7 -5
- package/src/types/plugins.d.ts +2 -0
- package/src/types/usd-core-bindings.d.ts +240 -0
- package/src/utils.js +3 -3
- package/examples/index.html +0 -58
- package/examples/package-lock.json +0 -1548
- package/examples/package.json +0 -24
- package/examples/public/HttpReferences copy.usda +0 -46
- package/examples/public/HttpReferences.usda +0 -44
- package/examples/public/gingerbread/GingerbreadHouse.usda +0 -35
- package/examples/public/gingerbread/house/GingerBreadHouse.usdc +0 -0
- package/examples/public/gingerbread/house/textures/color.jpg +0 -0
- package/examples/public/gingerbread/house/textures/metallic_roughness.jpg +0 -0
- package/examples/public/gingerbread/house/textures/normal.jpg +0 -0
- package/examples/public/gingerbread/snowman/Snowman.usdc +0 -0
- package/examples/public/gingerbread/snowman/textures/color.jpg +0 -0
- package/examples/public/gingerbread/snowman/textures/metallic_roughness.jpg +0 -0
- package/examples/public/gingerbread/snowman/textures/normal.jpg +0 -0
- package/examples/public/test.usdz +0 -0
- package/examples/public/vite.svg +0 -1
- package/examples/src/fileHandling.ts +0 -256
- package/examples/src/main.ts +0 -167
- package/examples/src/three.ts +0 -140
- package/examples/src/vite-env.d.ts +0 -1
- package/examples/tsconfig.json +0 -23
- package/examples/vite.config.js +0 -21
- package/src/bindings/emHdBindings.data +0 -19331
- package/src/bindings/emHdBindings.worker.js +0 -124
package/examples/package.json
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@needle-tools/usd-example-three",
|
|
3
|
-
"private": true,
|
|
4
|
-
"version": "0.0.0",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"start": "npm run dev",
|
|
8
|
-
"dev": "vite",
|
|
9
|
-
"build": "tsc && vite build",
|
|
10
|
-
"preview": "vite preview"
|
|
11
|
-
},
|
|
12
|
-
"devDependencies": {
|
|
13
|
-
"typescript": "^5.2.2",
|
|
14
|
-
"vite": "^5.0.8",
|
|
15
|
-
"vite-plugin-static-copy": "^1.0.5"
|
|
16
|
-
},
|
|
17
|
-
"dependencies": {
|
|
18
|
-
"@needle-tools/usd": "file:..",
|
|
19
|
-
"@types/three": "^0.165.0",
|
|
20
|
-
"three": "^0.164.1",
|
|
21
|
-
"vite-plugin-top-level-await": "^1.4.1",
|
|
22
|
-
"vite-plugin-wasm": "^3.3.0"
|
|
23
|
-
}
|
|
24
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
#usda 1.0
|
|
2
|
-
(
|
|
3
|
-
customLayerData = {
|
|
4
|
-
string creator = "Mira Ly Herbst, Binh Minh Herbst, Felix Herbst, 2025"
|
|
5
|
-
}
|
|
6
|
-
defaultPrim = "Scenery"
|
|
7
|
-
metersPerUnit = 1
|
|
8
|
-
upAxis = "Z"
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
def Xform "Scenery"
|
|
12
|
-
{
|
|
13
|
-
def "GingerBreadHouse" (
|
|
14
|
-
prepend references = @https://cloud-staging.needle.tools/-/assets/Z23hmXB22WdG2-22WdG2/house/GingerBreadHouse.usdc@
|
|
15
|
-
displayName = "Gingerbread House"
|
|
16
|
-
)
|
|
17
|
-
{
|
|
18
|
-
quatf xformOp:orient = (0.5092794, 0, 0, -0.8606013)
|
|
19
|
-
float3 xformOp:scale = (1, 0.99999994, 0.9999998)
|
|
20
|
-
float3 xformOp:translate = (0.04039519, -0.0057177544, 0)
|
|
21
|
-
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:orient", "xformOp:scale"]
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
def "Snowman" (
|
|
25
|
-
prepend references = @gingerbread/snowman/Snowman.usdc@
|
|
26
|
-
displayName = "Snowman"
|
|
27
|
-
)
|
|
28
|
-
{
|
|
29
|
-
quatf xformOp:orient = (0.8868096, 0, 0, -0.46213505)
|
|
30
|
-
float3 xformOp:scale = (0.99999994, 0.99999994, 0.9999998)
|
|
31
|
-
float3 xformOp:translate = (-0.03819806, -0.0054023676, 0)
|
|
32
|
-
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:orient", "xformOp:scale"]
|
|
33
|
-
|
|
34
|
-
# make an over here with /root/_materials/material/Principled_BSDF
|
|
35
|
-
|
|
36
|
-
over "_materials" {
|
|
37
|
-
over "material" {
|
|
38
|
-
over "Principled_BSDF" {
|
|
39
|
-
color3f inputs:diffuseColor = (1.0, 0.0, 0.0)
|
|
40
|
-
float inputs:specular = 0.0
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
#usda 1.0
|
|
2
|
-
(
|
|
3
|
-
customLayerData = {
|
|
4
|
-
string creator = "Mira Ly Herbst, Binh Minh Herbst, Felix Herbst, 2025"
|
|
5
|
-
}
|
|
6
|
-
defaultPrim = "Scenery"
|
|
7
|
-
metersPerUnit = 1
|
|
8
|
-
upAxis = "Z"
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
def Xform "Scenery"
|
|
12
|
-
{
|
|
13
|
-
def "GingerBreadHouse" (
|
|
14
|
-
prepend references = @https://cloud-staging.needle.tools/-/assets/Z23hmXB22WdG2-22WdG2/house/GingerBreadHouse.usdc@
|
|
15
|
-
displayName = "Gingerbread House"
|
|
16
|
-
)
|
|
17
|
-
{
|
|
18
|
-
quatf xformOp:orient = (0.5092794, 0, 0, -0.8606013)
|
|
19
|
-
float3 xformOp:scale = (1, 0.99999994, 0.9999998)
|
|
20
|
-
float3 xformOp:translate = (0.04039519, -0.0057177544, 0)
|
|
21
|
-
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:orient", "xformOp:scale"]
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
def "Snowman" (
|
|
25
|
-
prepend references = @https://cloud-staging.needle.tools/-/assets/Z23hmXB22WdG2-22WdG2/snowman/Snowman.usdc@
|
|
26
|
-
displayName = "Snowman"
|
|
27
|
-
)
|
|
28
|
-
{
|
|
29
|
-
quatf xformOp:orient = (0.8868096, 0, 0, -0.46213505)
|
|
30
|
-
float3 xformOp:scale = (0.99999994, 0.99999994, 0.9999998)
|
|
31
|
-
float3 xformOp:translate = (-0.03819806, -0.0054023676, 0)
|
|
32
|
-
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:orient", "xformOp:scale"]
|
|
33
|
-
|
|
34
|
-
# make an over here with /root/_materials/material/Principled_BSDF
|
|
35
|
-
over "_materials" {
|
|
36
|
-
over "material" {
|
|
37
|
-
over "Principled_BSDF" {
|
|
38
|
-
color3f inputs:diffuseColor = (1.0, 0.0, 0.0)
|
|
39
|
-
float inputs:specular = 0.0
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
#usda 1.0
|
|
2
|
-
(
|
|
3
|
-
customLayerData = {
|
|
4
|
-
string creator = "Mira Ly Herbst, Binh Minh Herbst, Felix Herbst, 2025"
|
|
5
|
-
}
|
|
6
|
-
defaultPrim = "Scenery"
|
|
7
|
-
metersPerUnit = 1
|
|
8
|
-
upAxis = "Z"
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
def Xform "Scenery"
|
|
12
|
-
{
|
|
13
|
-
def "GingerBreadHouse" (
|
|
14
|
-
prepend references = @house/GingerBreadHouse.usdc@
|
|
15
|
-
displayName = "Gingerbread House"
|
|
16
|
-
)
|
|
17
|
-
{
|
|
18
|
-
quatf xformOp:orient = (0.5092794, 0, 0, -0.8606013)
|
|
19
|
-
float3 xformOp:scale = (1, 0.99999994, 0.9999998)
|
|
20
|
-
float3 xformOp:translate = (0.04039519, -0.0057177544, 0)
|
|
21
|
-
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:orient", "xformOp:scale"]
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
def "Snowman" (
|
|
25
|
-
prepend references = @snowman/Snowman.usdc@
|
|
26
|
-
displayName = "Snowman"
|
|
27
|
-
)
|
|
28
|
-
{
|
|
29
|
-
quatf xformOp:orient = (0.8868096, 0, 0, -0.46213505)
|
|
30
|
-
float3 xformOp:scale = (0.99999994, 0.99999994, 0.9999998)
|
|
31
|
-
float3 xformOp:translate = (-0.03819806, -0.0054023676, 0)
|
|
32
|
-
uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:orient", "xformOp:scale"]
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/examples/public/vite.svg
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
document.addEventListener("dragover", function (ev) {
|
|
2
|
-
ev.preventDefault();
|
|
3
|
-
});
|
|
4
|
-
|
|
5
|
-
document.addEventListener("drop", function (ev) {
|
|
6
|
-
ev.preventDefault();
|
|
7
|
-
|
|
8
|
-
if (ev.dataTransfer?.items)
|
|
9
|
-
{
|
|
10
|
-
/** @type {FileSystemEntry[]} */
|
|
11
|
-
const allEntries = [];
|
|
12
|
-
|
|
13
|
-
let haveGetAsFileSystemHandle = false;
|
|
14
|
-
let haveGetAsEntry = false;
|
|
15
|
-
if (ev.dataTransfer.items.length > 0) {
|
|
16
|
-
haveGetAsEntry = ("getAsEntry" in ev.dataTransfer.items[0]) || ("webkitGetAsEntry" in ev.dataTransfer.items[0]);
|
|
17
|
-
haveGetAsFileSystemHandle = ("getAsFileSystemHandle" in ev.dataTransfer.items[0]);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/*
|
|
21
|
-
async function* getFilesRecursively(entry) {
|
|
22
|
-
if (entry.kind === "file") {
|
|
23
|
-
const file = await entry.getFile();
|
|
24
|
-
if (file !== null) {
|
|
25
|
-
file.relativePath = getRelativePath(entry);
|
|
26
|
-
yield file;
|
|
27
|
-
}
|
|
28
|
-
} else if (entry.kind === "directory") {
|
|
29
|
-
for await (const handle of entry.values()) {
|
|
30
|
-
yield* getFilesRecursively(handle);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (haveGetAsFileSystemHandle) {
|
|
36
|
-
for (var i = 0; i < ev.dataTransfer.items.length; i++)
|
|
37
|
-
{
|
|
38
|
-
let item = ev.dataTransfer.items[i];
|
|
39
|
-
let handle = item.getAsFileSystemHandle();
|
|
40
|
-
allEntries.push(handle);
|
|
41
|
-
}
|
|
42
|
-
handleFilesystemEntries(allEntries);
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
*/
|
|
46
|
-
|
|
47
|
-
if (haveGetAsEntry) {
|
|
48
|
-
for (var i = 0; i < ev.dataTransfer.items.length; i++)
|
|
49
|
-
{
|
|
50
|
-
let item = ev.dataTransfer.items[i];
|
|
51
|
-
/** @type {FileSystemEntry} */
|
|
52
|
-
let entry = ("getAsEntry" in item) ? item.getAsEntry() : item.webkitGetAsEntry();
|
|
53
|
-
allEntries.push(entry);
|
|
54
|
-
}
|
|
55
|
-
handleFilesystemEntries(allEntries);
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
for (var i = 0; i < ev.dataTransfer.items.length; i++)
|
|
60
|
-
{
|
|
61
|
-
let item = ev.dataTransfer.items[i];
|
|
62
|
-
|
|
63
|
-
// API when there's no "getAsEntry" support
|
|
64
|
-
console.log(item.kind, item, entry);
|
|
65
|
-
if (item.kind === 'file')
|
|
66
|
-
{
|
|
67
|
-
var file = item.getAsFile();
|
|
68
|
-
testAndLoadFile(file);
|
|
69
|
-
}
|
|
70
|
-
// could also be a directory
|
|
71
|
-
else if (item.kind === 'directory')
|
|
72
|
-
{
|
|
73
|
-
var dirReader = item.createReader();
|
|
74
|
-
dirReader.readEntries(function(entries) {
|
|
75
|
-
for (var i = 0; i < entries.length; i++) {
|
|
76
|
-
console.log(entries[i].name);
|
|
77
|
-
var entry = entries[i];
|
|
78
|
-
if (entry.isFile) {
|
|
79
|
-
entry.file(function(file) {
|
|
80
|
-
testAndLoadFile(file);
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
} else {
|
|
88
|
-
for (var i = 0; i < ev.dataTransfer.files.length; i++) {
|
|
89
|
-
let file = ev.dataTransfer.files[i];
|
|
90
|
-
testAndLoadFile(file);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* @param {FileSystemEntry[]} entries
|
|
97
|
-
*/
|
|
98
|
-
async function handleFilesystemEntries(entries) {
|
|
99
|
-
/** @type {FileSystemEntry[]} */
|
|
100
|
-
const allFiles = [];
|
|
101
|
-
const fileIgnoreList = [
|
|
102
|
-
'.gitignore',
|
|
103
|
-
'README.md',
|
|
104
|
-
'.DS_Store',
|
|
105
|
-
]
|
|
106
|
-
const dirIgnoreList = [
|
|
107
|
-
'.git',
|
|
108
|
-
'node_modules',
|
|
109
|
-
]
|
|
110
|
-
const debugFileHandling = false;
|
|
111
|
-
|
|
112
|
-
for (let entry of entries) {
|
|
113
|
-
if (debugFileHandling) console.log("file entry", entry)
|
|
114
|
-
if (entry.isFile) {
|
|
115
|
-
if (debugFileHandling) console.log("single file", entry);
|
|
116
|
-
if (fileIgnoreList.includes(entry.name)) {
|
|
117
|
-
continue;
|
|
118
|
-
}
|
|
119
|
-
allFiles.push(entry);
|
|
120
|
-
}
|
|
121
|
-
else if (entry.isDirectory) {
|
|
122
|
-
if (dirIgnoreList.includes(entry.name)) {
|
|
123
|
-
continue;
|
|
124
|
-
}
|
|
125
|
-
const files = await readDirectory(entry);
|
|
126
|
-
if (debugFileHandling) console.log("all files", files);
|
|
127
|
-
for (const file of files) {
|
|
128
|
-
if (fileIgnoreList.includes(file.name)) {
|
|
129
|
-
continue;
|
|
130
|
-
}
|
|
131
|
-
allFiles.push(file);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// determine which of these is likely the root file
|
|
137
|
-
let rootFileCandidates = [];
|
|
138
|
-
let usdaCandidates = [];
|
|
139
|
-
|
|
140
|
-
// sort so shorter paths come first
|
|
141
|
-
allFiles.sort((a, b) => {
|
|
142
|
-
const diff = a.fullPath.split('/').length - b.fullPath.split('/').length;
|
|
143
|
-
if (diff !== 0) return diff;
|
|
144
|
-
return a.fullPath.localeCompare(b.fullPath);
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
// console.log("path candidates", allFiles);
|
|
148
|
-
|
|
149
|
-
for (const file of allFiles) {
|
|
150
|
-
let ext = file.name.split('.').pop();
|
|
151
|
-
if(ext == 'usd' || ext == 'usdz' || ext == 'usda' || ext == 'usdc') {
|
|
152
|
-
rootFileCandidates.push(file);
|
|
153
|
-
}
|
|
154
|
-
if(ext == 'usda') {
|
|
155
|
-
usdaCandidates.push(file);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
let rootFile = undefined;
|
|
160
|
-
|
|
161
|
-
// if there's multiple, use the first usda
|
|
162
|
-
if (rootFileCandidates.length > 1) {
|
|
163
|
-
if (usdaCandidates.length > 0) {
|
|
164
|
-
rootFile = usdaCandidates[0];
|
|
165
|
-
}
|
|
166
|
-
else {
|
|
167
|
-
rootFile = rootFileCandidates[0];
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
else {
|
|
171
|
-
// find the first usda file
|
|
172
|
-
for (const file of allFiles) {
|
|
173
|
-
let ext = file.name.split('.').pop();
|
|
174
|
-
if(ext == 'usda' || ext == 'usdc' || ext == 'usdz' || ext == 'usd') {
|
|
175
|
-
rootFile = file;
|
|
176
|
-
break;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
if (!rootFile && allFiles.length > 0) {
|
|
182
|
-
// use first file
|
|
183
|
-
rootFile = allFiles[0];
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// TODO if there are still multiple candidates we should ask the user which one to use
|
|
187
|
-
console.log("Assuming this is the root file: " + rootFile?.name); // + ". Total: " + allFiles.length, allFiles.map(f => f.fullPath).join('\n'));
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
async function getFile(fileEntry) {
|
|
191
|
-
try {
|
|
192
|
-
return new Promise((resolve, reject) => fileEntry.file(resolve, reject));
|
|
193
|
-
} catch (err) {
|
|
194
|
-
console.log(err);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
console.log("All files", allFiles);
|
|
199
|
-
|
|
200
|
-
allDroppedFiles = allFiles;
|
|
201
|
-
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* @param {FileSystemDirectoryEntry} directory
|
|
207
|
-
*/
|
|
208
|
-
async function readDirectory(directory) {
|
|
209
|
-
let entries = [];
|
|
210
|
-
|
|
211
|
-
let getAllDirectoryEntries = async (dirReader) => {
|
|
212
|
-
let entries = [];
|
|
213
|
-
let readEntries = async () => {
|
|
214
|
-
let result = await new Promise((resolve, reject) => dirReader.readEntries(resolve, reject));
|
|
215
|
-
if (result.length === 0)
|
|
216
|
-
return entries;
|
|
217
|
-
else
|
|
218
|
-
return entries.concat(result, await readEntries());
|
|
219
|
-
}
|
|
220
|
-
return await readEntries();
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* @param {FileSystemDirectoryReader} dirReader
|
|
225
|
-
* @param {FileSystemDirectoryEntry} directory
|
|
226
|
-
* @returns {Promise<number>}
|
|
227
|
-
*/
|
|
228
|
-
let getEntries = async (directory) => {
|
|
229
|
-
let dirReader = directory.createReader();
|
|
230
|
-
await new Promise(async (resolve, reject) => {
|
|
231
|
-
// Call the reader.readEntries() until no more results are returned.
|
|
232
|
-
|
|
233
|
-
const results = await getAllDirectoryEntries(dirReader);
|
|
234
|
-
|
|
235
|
-
if (results.length) {
|
|
236
|
-
// entries = entries.concat(results);
|
|
237
|
-
for (let entry of results) {
|
|
238
|
-
if (entry.isDirectory) {
|
|
239
|
-
const foundFiles = await getEntries(entry);
|
|
240
|
-
if (foundFiles === 100)
|
|
241
|
-
console.warn("Found more than 100 files in directory", entry);
|
|
242
|
-
}
|
|
243
|
-
else {
|
|
244
|
-
entries.push(entry);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
resolve(results.length);
|
|
249
|
-
});
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
await getEntries(directory);
|
|
253
|
-
return entries;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
export let allDroppedFiles: FileSystemFileEntry[] = [];
|
package/examples/src/main.ts
DELETED
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { getUsdModule, createThreeHydra, USD, createThreeHydraReturnType } from '@needle-tools/usd';
|
|
3
|
-
import { loadEnvMap, run } from './three';
|
|
4
|
-
import { Object3D, Scene, WebGLRenderer } from 'three';
|
|
5
|
-
|
|
6
|
-
import { allDroppedFiles } from './fileHandling';
|
|
7
|
-
|
|
8
|
-
let hydraDelegate: createThreeHydraReturnType | null;
|
|
9
|
-
let scene: Scene;
|
|
10
|
-
let usdContent: Object3D;
|
|
11
|
-
let usd: USD;
|
|
12
|
-
let app: { fitCamera: () => void };
|
|
13
|
-
|
|
14
|
-
getUsdModule({
|
|
15
|
-
debug: true,
|
|
16
|
-
urlModifier: async (url: string) => {
|
|
17
|
-
// Resolve GitHub-specific URLs
|
|
18
|
-
// rewrite GitHub links in the form https://github.com/usd-wg/assets/blob/main/full_assets/ElephantWithMonochord/SoC-ElephantWithMonochord.usdc
|
|
19
|
-
// to the raw version https://raw.githubusercontent.com/usd-wg/assets/main/full_assets/ElephantWithMonochord/SoC-ElephantWithMonochord.usdc
|
|
20
|
-
if (url.startsWith("https://github.com")) {
|
|
21
|
-
url = url.replace("github.com", "raw.githubusercontent.com");
|
|
22
|
-
url = url.replace("/blob/", "/");
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
console.log(url);
|
|
26
|
-
|
|
27
|
-
// Check if we find this URL in the dropped files, if there are any
|
|
28
|
-
if (allDroppedFiles && allDroppedFiles.length > 0) {
|
|
29
|
-
const found = allDroppedFiles.find(f => f.fullPath == url);
|
|
30
|
-
|
|
31
|
-
if (found) {
|
|
32
|
-
console.log("found file, returning handle", url, found);
|
|
33
|
-
if ("file" in found) {
|
|
34
|
-
return await new Promise((resolve, reject) => found.file(resolve, reject));
|
|
35
|
-
}
|
|
36
|
-
else if ("getFile" in found) {
|
|
37
|
-
return await found.getFile();
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
console.warn("File not found", url, allDroppedFiles);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// return "./gingerbread/house/" + url;
|
|
46
|
-
return url;
|
|
47
|
-
}
|
|
48
|
-
}).then(async (USD: USD) => {
|
|
49
|
-
|
|
50
|
-
const testUrls = [
|
|
51
|
-
{ label: "USDZ Cube", url: "/test.usdz" },
|
|
52
|
-
{ label: "Gingerbread House USDC", url: "/gingerbread/house/GingerBreadHouse.usdc" },
|
|
53
|
-
{ label: "Gingerbread House USDA", url: "/gingerbread/GingerbreadHouse.usda", },
|
|
54
|
-
{ label: "USDA file with HTTPS references", url: "/HttpReferences.usda" },
|
|
55
|
-
{ label: "Gingerbread House from Needle Cloud", url: "https://cloud-staging.needle.tools/-/assets/Z23hmXB22WdG2-22WdG2/file.usda" },
|
|
56
|
-
{ label: "Gingerbread House Subasset from Needle Cloud", url: "https://cloud-staging.needle.tools/-/assets/Z23hmXB22WdG2-22WdG2/house/GingerBreadHouse.usdc" },
|
|
57
|
-
{ label: "USD Kitchen from Needle Cloud", url: "https://cloud-staging.needle.tools/-/assets/Z23hmXBZCdB4p-ZCdB4p/file.usdz" },
|
|
58
|
-
{ label: "Car with Variants", url: "https://github.com/usd-wg/assets/blob/main/full_assets/Vehicles/USD_Mini_Car_Kit/assets/vehicles/vehicleVariants.usda" },
|
|
59
|
-
{ label: "Carbon Frame Bike USDZ", url: "https://github.com/usd-wg/assets/blob/jcowles/discoverability/full_assets/CarbonFrameBike/CarbonFrameBike.usdz" },
|
|
60
|
-
{ label: "Carbon Frame Bike USDA", url: "https://github.com/usd-wg/assets/blob/jcowles/discoverability/full_assets/CarbonFrameBike/index.usda" },
|
|
61
|
-
{ label: "McUsd USDA", url: "https://github.com/usd-wg/assets/blob/jcowles/discoverability/full_assets/McUsd/McUsd.usda" },
|
|
62
|
-
{ label: "Teapot USD", url: "https://github.com/usd-wg/assets/blob/main/full_assets/Teapot/Teapot.usd" },
|
|
63
|
-
];
|
|
64
|
-
|
|
65
|
-
const div = document.createElement("div");
|
|
66
|
-
div.className = "test-buttons";
|
|
67
|
-
|
|
68
|
-
for (const url of testUrls) {
|
|
69
|
-
const button = document.createElement("button");
|
|
70
|
-
button.innerText = url.label;
|
|
71
|
-
button.onclick = () => loadFile(url.url);
|
|
72
|
-
div.appendChild(button);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
document.body.appendChild(div);
|
|
76
|
-
|
|
77
|
-
const div2 = document.createElement("div");
|
|
78
|
-
div2.className = "options";
|
|
79
|
-
const frameButton = document.createElement("button");
|
|
80
|
-
frameButton.innerText = "Fit Camera";
|
|
81
|
-
frameButton.onclick = () => app.fitCamera();
|
|
82
|
-
div2.appendChild(frameButton);
|
|
83
|
-
div.appendChild(div2);
|
|
84
|
-
|
|
85
|
-
// const url = "test.usdz"; // local file
|
|
86
|
-
// const url = "/gingerbread/house/GingerBreadHouse.usdc";
|
|
87
|
-
// const url = "/gingerbread/GingerbreadHouse.usda";
|
|
88
|
-
const url = "/HttpReferences.usda";
|
|
89
|
-
// ... all the URLs
|
|
90
|
-
// --> put them all into the virtual file system
|
|
91
|
-
// --> load the first one (assume which one that actually is)
|
|
92
|
-
|
|
93
|
-
// const url = "https://cloud-staging.needle.tools/-/assets/Z23hmXB22WdG2-22WdG2/file.usda"; // remote file
|
|
94
|
-
// const url = "https://cloud-staging.needle.tools/-/assets/Z23hmXB22WdG2-22WdG2/house/GingerBreadHouse.usdc"; // remote file
|
|
95
|
-
|
|
96
|
-
// using a file/buffer
|
|
97
|
-
/*
|
|
98
|
-
const buffer = await fetch(url).then(response => response.arrayBuffer());
|
|
99
|
-
const file = new File([buffer], url, { type: "model/usd" });
|
|
100
|
-
file.path = url; // used to determine the directory structure
|
|
101
|
-
*/
|
|
102
|
-
|
|
103
|
-
const renderer = new WebGLRenderer({ antialias: true, alpha: true });
|
|
104
|
-
const envmapUrl = "https://dl.polyhaven.org/file/ph-assets/HDRIs/exr/1k/studio_small_09_1k.exr";
|
|
105
|
-
const envmap = await loadEnvMap(envmapUrl, renderer);
|
|
106
|
-
|
|
107
|
-
scene = new Scene();
|
|
108
|
-
scene.environment = envmap;
|
|
109
|
-
scene.background = envmap;
|
|
110
|
-
scene.backgroundBlurriness = 0.8;
|
|
111
|
-
scene.backgroundIntensity = 0.2;
|
|
112
|
-
|
|
113
|
-
usd = USD;
|
|
114
|
-
|
|
115
|
-
/*
|
|
116
|
-
usdContent = new Object3D();
|
|
117
|
-
scene.add(usdContent);
|
|
118
|
-
hydraDelegate = await createThreeHydra({
|
|
119
|
-
debug: true,
|
|
120
|
-
USD,
|
|
121
|
-
url: url,
|
|
122
|
-
// files: [file],
|
|
123
|
-
// @ts-ignore
|
|
124
|
-
scene: usdContent,
|
|
125
|
-
})
|
|
126
|
-
*/
|
|
127
|
-
|
|
128
|
-
// loadFile(url);
|
|
129
|
-
|
|
130
|
-
app = run({
|
|
131
|
-
renderer,
|
|
132
|
-
scene: scene,
|
|
133
|
-
onRender: (dt) => {
|
|
134
|
-
hydraDelegate?.update(dt);
|
|
135
|
-
}
|
|
136
|
-
});
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
async function loadFile(url: string) {
|
|
140
|
-
|
|
141
|
-
if (hydraDelegate)
|
|
142
|
-
hydraDelegate.dispose();
|
|
143
|
-
hydraDelegate = null;
|
|
144
|
-
|
|
145
|
-
if (usdContent) {
|
|
146
|
-
scene.remove(usdContent);
|
|
147
|
-
// TODO dispose as well
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
usdContent = new Object3D();
|
|
151
|
-
scene.add(usdContent);
|
|
152
|
-
|
|
153
|
-
const delegate = await createThreeHydra({
|
|
154
|
-
debug: true,
|
|
155
|
-
USD: usd,
|
|
156
|
-
url: url,
|
|
157
|
-
// @ts-ignore
|
|
158
|
-
scene: usdContent,
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
hydraDelegate = delegate;
|
|
162
|
-
|
|
163
|
-
console.log("Scene content", usdContent);
|
|
164
|
-
app.fitCamera();
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
window.loadFile = loadFile;
|