Skip to content

Instantly share code, notes, and snippets.

@bnjm
Created February 13, 2018 14:35
Show Gist options
  • Save bnjm/96e037129a08d93e3359c2861335869e to your computer and use it in GitHub Desktop.
Save bnjm/96e037129a08d93e3359c2861335869e to your computer and use it in GitHub Desktop.
Loading a 3d model in React Native Arkit
// @flow
import { ARKit } from 'react-native-arkit'
import { Text, View } from 'react-native'
import { compose, lifecycle, onlyUpdateForKeys } from 'recompose'
import { unzip } from 'react-native-zip-archive'
import RNFetchBlob from 'react-native-fetch-blob'
import React from 'react'
import type { Point3D } from '../../../types'
const getModelPath = productResourceId =>
`${RNFetchBlob.fs.dirs.CacheDir}/models/${productResourceId}`
const getModelFile = productResourceId =>
`${getModelPath(productResourceId)}/${productResourceId}/model.dae`
const getModelUrl = productResourceId =>
`https://homestory-furniture.s3.amazonaws.com/${productResourceId}.zip`
async function loadModel(productResourceId) {
console.log('loadModel', productResourceId)
try {
const path = getModelPath(productResourceId)
const modelFile = getModelFile(productResourceId)
const exists = await RNFetchBlob.fs.exists(modelFile)
if (exists) {
this.setState({ isLoading: false })
} else {
this.setState({ isLoading: true })
const result = await RNFetchBlob.config({
fileCache: true,
})
.fetch('GET', getModelUrl(productResourceId))
.progress((received, total) => {
console.log('progress', received, total, received / total)
})
console.log('The file saved to ', result.path())
const unzipPath = await unzip(result.path(), path)
console.log(`unzip completed at ${unzipPath}`)
this.setState({ isLoading: false })
}
} catch (error) {
this.setState({ isLoading: true, error })
}
}
// position is always position on the floor
const getBoxPosition = ({
position,
product,
}: {
position: Point3D,
product: any,
}) => ({
x: position.x,
y: position.y + (product.boundingBox ? product.boundingBox.height / 2 : 0),
z: position.z,
})
// swap length and width because of AR.Box / 3d.io discrepancy
const getBoxDimensions = ({ width = 1, length = 1, height = 1 } = {}) => ({
length: width,
width: length,
height,
})
const withModelDownload = compose(
lifecycle({
componentDidMount() {
loadModel.call(this, this.props.product.productResourceId)
},
componentWillReceiveProps(newProps) {
if (
newProps.product &&
newProps.product.productResourceId !==
this.props.product.productResourceId
) {
loadModel.call(this, newProps.product.productResourceId)
}
},
}),
)
const enhance = compose(
onlyUpdateForKeys(['position', 'eulerAngles']),
withModelDownload,
)
export default enhance(
({ id, position, eulerAngles, isLoading, product, debug = false }) =>
(<ARKit.Group>
{debug &&
<ARKit.Sprite position={position}>
<View
style={{
padding: 5,
backgroundColor: 'white',
width: 200,
left: -50,
borderRadius: 4,
opacity: 0.8,
}}
>
<Text
style={{
backgroundColor: 'transparent',
}}
>
{id}
{'\n'}
{product.productDisplayName}
{'\n'}
{JSON.stringify({ position, eulerAngles }, null, 2)}
</Text>
</View>
</ARKit.Sprite>}
<ARKit.Box
id={id}
material={{
diffuse: `rgba(120, 120, 120, ${isLoading ? 0.7 : 0.3})`,
}}
transition={{
duration: 0.1,
}}
eulerAngles={{
x: eulerAngles && eulerAngles.x,
y: eulerAngles && eulerAngles.y + Math.PI / 2,
z: eulerAngles && eulerAngles.z,
}}
position={getBoxPosition({ product, position })}
shape={{
...getBoxDimensions(product.boundingBox),
chamfer: 0.02,
}}
/>
{!isLoading &&
<ARKit.Model
position={position}
transition={{
duration: 0.1,
}}
eulerAngles={eulerAngles}
id={`${id}_model`}
model={{
scale: 1,
file: getModelFile(product.productResourceId),
}}
/*
material={{
shaders: {
[ARKit.ShaderModifierEntryPoint.Geometry]: `
float Amplitude = 0.04;
float Frequency = 5.0;
vec2 nrm = _geometry.position.xz;
float len = length(nrm)+0.0001; // for robustness
nrm /= len;
float a = len + Amplitude*sin(Frequency * _geometry.position.y + u_time * 10.0);
_geometry.position.xz = nrm * a;
`,
[ARKit.ShaderModifierEntryPoint.Fragment]: `
_output.color.rgba = vec4((sin(u_time*5)), (sin(u_time*4)),(sin(u_time*3)),0)*0.2+_output.color.rgba;
`,
},
}}
*/
/>}
</ARKit.Group>),
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment