Last active
March 25, 2023 09:20
-
-
Save kyaroru/bdf66ecd599a19eeb3106bf74fc89193 to your computer and use it in GitHub Desktop.
This is an utility file for loading OBJ, FBX, GLTF models using expo-three & threejs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
onContextCreate = async (gl, data) => { | |
// const {setRenderer, setCamera, setScene} = data; | |
const { selected } = data; | |
const { drawingBufferWidth: width, drawingBufferHeight: height } = gl; | |
const sceneColor = 0xabd2c3; | |
// Create a WebGLRenderer without a DOM element | |
const renderer = new Renderer({ gl }); | |
renderer.setSize(width, height); | |
renderer.setClearColor(sceneColor); | |
const camera = new PerspectiveCamera(75, width / height, 0.1, 1000); | |
camera.position.set(0, 0, 10); | |
const scene = new Scene(); | |
const pointLight = new PointLight(0xffffff, 2, 1000, 1); | |
pointLight.position.set(0, 30, 100); | |
// scene.add(pointLight); | |
// HemisphereLight - color feels nicer | |
const hemisphereLight = new HemisphereLight(0xffffbb, 0x080820, 1); | |
scene.add(hemisphereLight); | |
// AmbientLight - add more brightness? | |
const ambientLight = new AmbientLight(0x404040); // soft white light | |
scene.add(ambientLight); | |
const icebear = { | |
type: 'fbx', | |
name: 'icebear', | |
isometric: false, | |
model: require('../models/icebear/source/icebear.fbx'), | |
textures: [ | |
{ | |
name: 'axepCube3', | |
image: require('../models/icebear/textures/TXaxe.xjpg'), | |
}, | |
{ | |
name: 'polySurface10', | |
image: require('../models/icebear/textures/TXpolar.xjpg'), | |
}, | |
], | |
scale: { | |
x: 1, | |
y: 1, | |
z: 1, | |
}, | |
position: { | |
x: 0, | |
y: 0, | |
z: -2, | |
}, | |
animation: { | |
rotation: { | |
y: 0.01, // to animate horizontally | |
}, | |
}, | |
}; | |
const model = await loadModel(icebear); | |
scene.add(model); | |
function update() { | |
// define your own update here | |
// eg. if (model) model.rotation.y += icebear.animation.rotation.y; | |
} | |
// Setup an animation loop | |
const render = () => { | |
requestAnimationFrame(render); | |
update(); | |
renderer.render(scene, camera); | |
gl.endFrameEXP(); | |
}; | |
render(); | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { loadObjAsync, loadTextureAsync } from 'expo-three'; | |
import { resolveAsync } from 'expo-asset-utils'; | |
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader'; | |
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; | |
import { FileSystem } from 'react-native-unimodules'; | |
import { decode } from 'base64-arraybuffer'; | |
async function loadFileAsync({ asset, funcName }) { | |
if (!asset) { | |
throw new Error(`ExpoTHREE.${funcName}: Cannot parse a null asset`); | |
} | |
return (await resolveAsync(asset)).localUri ?? null; | |
} | |
export async function loadFbxAsync({ asset, onAssetRequested }) { | |
const uri = await loadFileAsync({ | |
asset, | |
funcName: 'loadFbxAsync', | |
}); | |
if (!uri) return; | |
const base64 = await FileSystem.readAsStringAsync(uri, { | |
encoding: FileSystem.EncodingType.Base64, | |
}); | |
const arrayBuffer = decode(base64); | |
const loader = new FBXLoader(); | |
return loader.parse(arrayBuffer, onAssetRequested); | |
} | |
export async function loadGLTFAsync({ asset, onAssetRequested }) { | |
const uri = await loadFileAsync({ | |
asset, | |
funcName: 'loadGLTFAsync', | |
}); | |
if (!uri) return; | |
const base64 = await FileSystem.readAsStringAsync(uri, { | |
encoding: FileSystem.EncodingType.Base64, | |
}); | |
const arrayBuffer = decode(base64); | |
const loader = new GLTFLoader(); | |
return new Promise((resolve, reject) => { | |
loader.parse( | |
arrayBuffer, | |
onAssetRequested, | |
result => { | |
resolve(result); | |
}, | |
err => { | |
reject(err); | |
}, | |
); | |
}); | |
} | |
export const loadModel = async function(item) { | |
const texturesLength = item.textures?.length || 0; | |
console.log(`[loadModel] -> Textures length: ${texturesLength}`); | |
const textures = []; | |
for (let i = 0; i < texturesLength; i++) { | |
const texture = await loadTextureAsync({ | |
asset: item.textures[i].image, | |
}); | |
if (item.type === 'glb') { | |
texture.flipY = false; | |
} | |
textures.push({ name: item.textures[i]?.name || '-', map: texture }); | |
} | |
console.log(`[loadModel] -> Textures done loading`); | |
// console.log(textures); | |
let obj = null; | |
if (item.type === 'obj') { | |
obj = await loadObjAsync({ | |
asset: item.model, | |
mtlAsset: item?.material || undefined, | |
}); | |
} else if (item.type === 'fbx') { | |
obj = await loadFbxAsync({ asset: item.model }); | |
} else if (item.type === 'gltf' || item.type === 'glb') { | |
const result = await loadGLTFAsync({ asset: item.model }); | |
console.log(result); | |
obj = result.scene; | |
} | |
console.log(`[loadModel] -> Model done loading, adding textures now...`); | |
if (texturesLength > 0) { | |
if (texturesLength === 1) { | |
obj.traverse(function(object) { | |
if (object instanceof THREE.Mesh) { | |
object.material.map = textures[0]?.map; | |
} | |
}); | |
} else { | |
obj.traverse(function(object) { | |
if (object instanceof THREE.Mesh) { | |
// console.log( | |
// `[loadModel] -> Traverse object name: ${object.name}`, | |
// ); | |
// console.log(object); | |
const selected = textures?.find(x => x.name === object.name); | |
object.material.map = selected?.map; | |
} | |
}); | |
} | |
} | |
console.log(`[loadModel] -> Textures done applied...`); | |
if (item.scale) { | |
obj.scale.set(item.scale.x, item.scale.y, item.scale.z); | |
} | |
if (item.position) { | |
obj.position.set(item.position.x, item.position.y, item.position.z); | |
} | |
if (item.rotation) { | |
obj.rotation.x = item.rotation.x; | |
obj.rotation.y = item.rotation.y; | |
obj.rotation.z = item.rotation.z; | |
} | |
return obj; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment