Skip to content

Instantly share code, notes, and snippets.

@kyaroru
Last active March 25, 2023 09:20
Show Gist options
  • Save kyaroru/bdf66ecd599a19eeb3106bf74fc89193 to your computer and use it in GitHub Desktop.
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
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();
};
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