Skip to content

Instantly share code, notes, and snippets.

@chydee
Created August 31, 2020 14:08
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chydee/8e11e8c87e930136af19db46dda83f5b to your computer and use it in GitHub Desktop.
Save chydee/8e11e8c87e930136af19db46dda83f5b to your computer and use it in GitHub Desktop.
Render 3D Objects or Scene in android without ARCore
<com.google.ar.sceneform.SceneView
android:id="@+id/scene_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/deep_teal"/>
dependencies{
...
//sceneform
implementation 'com.google.ar.sceneform:core:1.17.1'
implementation 'com.google.ar.sceneform.ux:sceneform-ux:1.17.1'
implementation 'com.google.ar.sceneform:assets:1.17.1'
...
}
dependencies {
...
//To connect to firebase
classpath 'com.google.gms:google-services:4.3.3'
}
References:
//ARCore Cupcakes #1 — Render a Scene without AR for phones without ARCore
https://medium.com/@harivigneshjayapalan/arcore-cupcakes-1-render-a-scene-without-ar-for-phones-without-arcore-27d61a43a130
//Build and interact with a scene
https://developers.google.com/sceneform/develop/build-scene
//Getting started with firebase storage
https://firebase.google.com/docs/storage/android/start
//Classes declaration
private Node sketchNode;
private Scene scene;
private SceneView sceneView;
private StorageReference modelRef;
private FirebaseStorage storage;
private RelativeLayout sceneContainer;
private ModelRenderable renderable;
//End of Classes declaration
//Initialize FireBase App
FirebaseApp.initializeApp(this);
//TODO: Assign values or initialize the variables created above
//Get Scene
scene = sceneView.getScene();
// The scene's Camera node is placed at the origin (position 0,0,0) and facing forward (direction 0,0,-1).
// Because the camera's position and rotation is not tied to AR motion tracking, you can reposition or animate it like any other node.
Camera camera = sceneView.getScene().getCamera();
camera.setLocalRotation(Quaternion.axisAngle(Vector3.right(), -30.0f));
/**
* Downloads file from FirebaseStorage and pass it to the method that handles
* the rendering
*/
private void setUpRenderer(){String fileName){
//Get the storage refernce with the fileName
modelRef = storage.getReference().child(fileName.toLowerCase() + ".glb");
try {
//Create a Temporary File
File file = File.createTempFile("objects", "glb");
modelRef.getFile(file).addOnSuccessListener(new OnSuccessListener<FileDownloadTask.TaskSnapshot>() {
@Override
public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot) {
sceneContainer.setVisibility(View.VISIBLE); //Sets the container visible to Visible
buildModel(file); //Handle the rendering
}
});
} catch (IOException e) {
e.printStackTrace(); //catch the exception when something goes wrong
}
}
/**
* load the 3D model in the space
*
* @param uri - URI of the model, imported using Sceneform plugin
*/
private void buildModel(File uri) {
RenderableSource source = RenderableSource.builder()
.setSource(this, Uri.parse(uri.getPath()), RenderableSource.SourceType.GLB) // Does the conversion
.setRecenterMode(RenderableSource.RecenterMode.ROOT)
.build();
ModelRenderable.builder()
.setSource(this, source)
.build()
.thenAccept(modelRenderable -> {
Toast.makeText(getApplicationContext(), "Model Built", Toast.LENGTH_SHORT).show();
renderable = modelRenderable;
addToNode(renderable);
})
.exceptionally(exception -> {
new AlertDialog.Builder(this.getApplicationContext())
.setMessage(exception.getMessage())
.setTitle("Error!")
.create().show();
return null;
});
}
private void addToNode(ModelRenderable modelRenderable) {
sketchNode = new Node();
sketchNode.setParent(scene);
sketchNode.setLocalPosition(new Vector3(0f, -3f, -5f)); //Sets Object postion on the screen
sketchNode.setLocalScale(new Vector3(3f, 3f, 3f)); //Sets objects scale
sketchNode.setName("bucket");
sketchNode.setRenderable(modelRenderable);
scene.addChild(sketchNode);
}
//Then call setUpRenderer inside the onDetectClick() method
// This block checks for the probability with the highest value and then pass the label to
// the setUp Renderer as the fileName
if ((classifier.getProbability(index) * 100) > 50) {
//Toast.makeText(this, classifier.getLabel(index), Toast.LENGTH_SHORT).show();
setUpRenderer(classifier.getLabel(index));
}
//This method handles the release of resources and resetting everything to the default state
private void clear() {
if (sketchNode != null) {
sketchNode.setParent(null);
sketchNode.setRenderable(null);
sceneView.getScene().removeChild(sketchNode);
}
resetView(); // Refer to resetView(); in your code
}
//Close the modal and reset the resources
public void onCloseClick(View view) {
sceneContainer.setVisibility(View.GONE);
if (sketchNode != null) {
sketchNode.setParent(null);
sketchNode.setRenderable(null);
sceneView.getScene().removeChild(sketchNode);
}
}
//Override the following
@Override
public void onPause() {
super.onPause();
sceneView.pause();
}
@Override
public void onResume() {
super.onResume();
try {
sceneView.resume();
} catch (CameraNotAvailableException e) {
e.printStackTrace();
}
}
@Override
public void onDestroy() {
super.onDestroy();
sceneView.destroy();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment