.obj/.gltf 3D model won't show in ARCore - java

I followed a tutorial online to create an AR app that could show my 3D models in AR.
I put my .obj and .gltf 3d model files in my assets folder,
when the I tap on a plane, the method placeObject() should run and put my model (selectObject) on the place.
but when I test it on my phone,after the plane was detected and I tapped the screen, nothing happened, I checked my logcat and it shows the error when I tapped:
2021-11-04 01:55:46.629 11172-12363/com.example.arcoretest E/ModelRenderable: Unable to load Renderable registryId='testscene.obj'
java.util.concurrent.CompletionException: java.lang.AssertionError: No RCB file at uri: testscene.obj
at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:278)
at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:284)
at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1629)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:920)
Caused by: java.lang.AssertionError: No RCB file at uri: testscene.obj
at com.google.ar.sceneform.rendering.LoadRenderableFromSfbTask.byteBufferToSfb(LoadRenderableFromSfbTask.java:191)
at com.google.ar.sceneform.rendering.LoadRenderableFromSfbTask.lambda$downloadAndProcessRenderable$0$com-google-ar-sceneform-rendering-LoadRenderableFromSfbTask(LoadRenderableFromSfbTask.java:121)
I'm not sure where the problem is, is it my uri is wrong or I should use other 3d model format?
(I tried .obj/.fbx/.gltf but none of them worked)
(I can't use .sfb or .sfa ,I can no longer use sceneform plugin to convert files into sfa/sfb because it was deprecated)
here is my grade dependencies:
{
implementation 'com.google.ar.sceneform.ux:sceneform-ux:1.15.0'
implementation 'com.google.ar:core:1.15.0'
implementation 'com.google.ar.sceneform:assets:1.15.0'
...
}
My mainActivity.java:
package com.example.arcoretest;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import com.google.ar.core.Anchor;
import com.google.ar.core.HitResult;
import com.google.ar.core.Plane;
import com.google.ar.sceneform.AnchorNode;
import com.google.ar.sceneform.rendering.ModelRenderable;
import com.google.ar.sceneform.rendering.Renderable;
import com.google.ar.sceneform.ux.ArFragment;
import com.google.ar.sceneform.ux.TransformableNode;
public class MainActivity extends AppCompatActivity {
private ArFragment fragment;
private Uri selectObject;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
selectObject = Uri.parse("testscene.obj");
fragment = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.sceneFormFragment);
//when tapped on a plane, code below will run
fragment.setOnTapArPlaneListener(
(HitResult hitResult, Plane plane, MotionEvent motionEvent)->{
Anchor anchor = hitResult.createAnchor();
placeObject(fragment,anchor,selectObject);
}
);
}
//this method put 3d model in scene
private void placeObject(ArFragment fragment, Anchor anchor,Uri model){
ModelRenderable.builder()
.setSource(fragment.getContext(),model)
.build()
.thenAccept( renderable -> addNodeToScene(fragment,anchor,renderable))
.exceptionally((throwable -> {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(throwable.getMessage())
.setTitle("Error!");
AlertDialog dialog = builder.create();
dialog.show();
return null;
}));
}
private void addNodeToScene(ArFragment fragment, Anchor anchor, Renderable renderable){
AnchorNode anchorNode = new AnchorNode(anchor);
TransformableNode node = new TransformableNode(fragment.getTransformationSystem());
node.setRenderable(renderable);
node.setParent(anchorNode);
fragment.getArSceneView().getScene().addChild(anchorNode);
node.select();
}
}
and I put my 3d model files in assets folder like this:

I would recommend to update to the latest version of SceneForm. This is a community maintained version, with the latest dependencies of ArCore, Filament and Android. For your usecase the 3d-model-viewer sample might be interesting.

Related

how to print a layout with Print Document Adapter in android

i want to preview a layout for printer and want to print that layout. i already searched a lot but didn't find any way. i dont want to print many pages of document i just want to print one page one layout.
the layout contains text information, one list view and one imageView of QR code.
I have tried the following code:
private void doPrint() {
// Get a PrintManager instance
PrintManager printManager = (PrintManager) getApplicationContext()
.getSystemService(Context.PRINT_SERVICE);
// Set job name, which will be displayed in the print queue
String jobName = getApplicationContext().getString(R.string.app_name) + " Document";
// Start a print job, passing in a PrintDocumentAdapter implementation
// to handle the generation of a print document
printManager.print(jobName, new MyPrintDocumentAdapter(getApplicationContext()),
null);
}
and this is my Adapter class
package com.example.haier.arksolsfollow;
import android.content.Context;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
import android.print.PageRange;
import android.print.PrintAttributes;
import android.print.PrintDocumentAdapter;
import android.widget.Toast;
class MyPrintDocumentAdapter extends PrintDocumentAdapter {
public MyPrintDocumentAdapter(Context applicationContext) {
}
#Override
public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras) {
computePageCount(oldAttributes);
}
#Override
public void onWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback) {
}
#Override
public void onStart() {
super.onStart();
}
#Override
public void onFinish() {
super.onFinish();
}
private int computePageCount(PrintAttributes printAttributes) {
int itemsPerPage = 4; // default item count for portrait mode
// default item count for portrait mode
PrintAttributes.MediaSize pageSize = printAttributes.getMediaSize();
if (!pageSize.isPortrait()) {
// Six items per page in landscape orientation
itemsPerPage = 6;
}
// Determine number of print items
int printItemCount = 1;
return (int) Math.ceil(printItemCount / itemsPerPage);
}
}
my app also get crashes in this line
printManager.print(jobName, new MyPrintDocumentAdapter(getApplicationContext()),
null);
kindly guide me how to use all call back methods in adapter and how to preview a layout for printer
If i understood correctly you simply want to take a printout of your current layout. Assuming that i can provide you with an alternative solution. What you can do is first generate a bitmap of the layout you want to print and then pass it to the Printer Helper. You can even preview the bitmap before printing by setting it to an ImageView.
You can convert the layout view directly to a bitmap using below code.
View v = THE_LAYOUT_TO_BE_PRINTED;
Bitmap bmp = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bmp);
v.draw(c);
Then you can print the bitmap using Print Helper
PrintHelper photoPrinter = new PrintHelper(getActivity());
photoPrinter.setScaleMode(PrintHelper.SCALE_MODE_FIT);
photoPrinter.printBitmap("layout.png", bmp);
Below information is as for the Android Developer Documentation.
After the printBitmap() method is called, no further action from your
application is required. The Android print user interface appears,
allowing the user to select a printer and printing options. The user
can then print the image or cancel the action. If the user chooses to
print the image, a print job is created and a printing notification
appears in the system bar.
Edit:
Above method can be used to get a print out of an simple image without using the PrintDocumentAdapter itself. But if someone still prefers to use a custom PrintDocumentAdapter as in the original question, well constructed following article in Github will give a clear idea.

New class Crashes app

I created a new class for my toolbars edittext. I have it for expansion animation but it crashes when you click the edittext. Heres the code used
import android.support.v7.app.AppCompatActivity;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;
import android.widget.EditText;
/**
* Created by on 2018-01-07.
*/
public class Toolbar extends AppCompatActivity {
EditText search;
public void onEdit(){
Animation scaleAnimation = new ScaleAnimation(0, -500, 1, 1);
scaleAnimation.setDuration(750);
scaleAnimation.setFillAfter(true);
search.startAnimation(scaleAnimation);
}
}
personally ive never used other class rather one large class so any helpfull tips is greatly appreciated. The code in the MainActivity currently is blank which i was going to fill with webview once i got there or possibly in another class....
Here the crash data:
01-07 05:09:41.007 943-1130/? E/OMX-VDEC-1080P: Does not handle dataspace request
01-07 05:09:41.007 943-1130/? E/OMXNodeInstance: getConfig(3af0069:qcom.decoder.avc, ??(0x7f000062)) ERROR: UnsupportedSetting(0x80001019)
01-07 05:09:41.009 943-2332/? E/OMX-VDEC-1080P: Does not handle dataspace request
01-07 05:09:41.009 943-2332/? E/OMXNodeInstance: getConfig(3af0069:qcom.decoder.avc, ??(0x7f000062)) ERROR: UnsupportedSetting(0x80001019)
You can not find edittext because you have not set a view for this class, i guess you will be using this class from another activity which has ContentView and that is associated with an XML file. To be able to findviewbyids of that activity from this class. You will need to do something like this.
public class testclass {
public void onEdit(Context context, Activity activity){
EditText search;
search = activity.findViewById(R.id.search_edt);
Animation scaleAnimation = new ScaleAnimation(0, -500, 1, 1);
scaleAnimation.setDuration(750);
scaleAnimation.setFillAfter(true);
search.startAnimation(scaleAnimation);
}
}
and from your main class call this class passing parameters of context and activity like this
a.onEdit(this,this);
now you will be able to retrieve the widgets of the UI of that activity from this class.
I hope i helped this explanation helped you.

How to get weather tile layer correctly?

I am trying to get a precipitation weather layer to appear in my Google Maps activity, but cannot understand why it is not showing on the map. I have implemented my Google Maps Key in app\src\debug\res\values\google_maps_api.xml, have installed Google Play Services in Android SDK manager, and I have set up an account with OpenWeatherMap for their API (which is taken out below).
The map loads fine, and when I search the layer in a separate browser with inputted zoom,x,y it shows up fine, but I cannot get the layer to appear on my Google Maps activity.
Do I need to define x,y,zoom or are these pulled from the URL?
Here is my java:
package com.example.user.project;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.TileOverlay;
import com.google.android.gms.maps.model.TileOverlayOptions;
import com.google.android.gms.maps.model.TileProvider;
import com.google.android.gms.maps.model.UrlTileProvider;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Locale;
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {
private GoogleMap mMap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
/**
* Manipulates the map once available.
* This callback is triggered when the map is ready to be used.
* This is where we can add markers or lines, add listeners or move the camera. In this case,
* we just add a marker near Sydney, Australia.
* If Google Play services is not installed on the device, the user will be prompted to install
* it inside the SupportMapFragment. This method will only be triggered once the user has
* installed Google Play services and returned to the app.
*/
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
// Move the camera
LatLng indy = new LatLng(39, -86.5);
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(indy, 8));
TileProvider tileProvider = new UrlTileProvider(256, 256) {
#Override
public URL getTileUrl(int x, int y, int zoom) {
/* Define the URL pattern for the tile images */
String s = String.format(Locale.US, "http://tile.openweathermap.org/map/precipitation/%d/%d/%d.png?appid={my_key}",
zoom, x, y);
if (!checkTileExists(x, y, zoom)) {
return null;
}
try {
return new URL(s);
} catch (MalformedURLException e) {
throw new AssertionError(e);
}
}
/*
* Check that the tile server supports the requested x, y and zoom.
* Complete this stub according to the tile range you support.
* If you support a limited range of tiles at different zoom levels, then you
* need to define the supported x, y range at each zoom level.
*/
private boolean checkTileExists(int x, int y, int zoom) {
int minZoom = 12;
int maxZoom = 16;
return !(zoom < minZoom || zoom > maxZoom);
}
};
TileOverlay tileOverlay = mMap.addTileOverlay(new TileOverlayOptions()
.tileProvider(tileProvider));
}
}
Here is the Android Studio generated layout:
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.user.project.MapsActivity"/>
I have followed tutorials and documentation offered from OpenWeatherMap, Google Maps API, and Android Developers, but do not understand why this is not working.
What am I missing?
You are setting level 8 as zoom level for your map but you are also limiting zoom levels to be between 12 and 16 for your TileProvider to be visible.
Remove this:
if (!checkTileExists(x, y, zoom)) {
return null;
}
If you don't need any scale restriction you can also remove the checkTileExists method.

multiple showcaseviews android

How can I add multiple showcaseviews to my layout...
I've tried this:
import com.github.amlcurran.showcaseview.sample.R;
import android.annotation.TargetApi;
import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
public class MultipleShowcaseSampleActivity extends Activity {
private static final float SHOWCASE_KITTEN_SCALE = 1.2f;
private static final float SHOWCASE_LIKE_SCALE = 0.5f;
//ShowcaseViews mViews;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample_legacy);
findViewById(R.id.buttonLike).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(getApplicationContext(), R.string.like_message, Toast.LENGTH_SHORT).show();
}
});
//mOptions.block = false;
// mViews = new ShowcaseViews(this,
// new ShowcaseViews.OnShowcaseAcknowledged() {
// #Override
// public void onShowCaseAcknowledged(ShowcaseView showcaseView) {
// Toast.makeText(MultipleShowcaseSampleActivity.this, R.string.dismissed_message, Toast.LENGTH_SHORT).show();
// }
// });
// mViews.addView( new ShowcaseViews.ItemViewProperties(R.id.image,
// R.string.showcase_image_title,
// R.string.showcase_image_message,
// SHOWCASE_KITTEN_SCALE));
// mViews.addView( new ShowcaseViews.ItemViewProperties(R.id.buttonLike,
// R.string.showcase_like_title,
// R.string.showcase_like_message,
// SHOWCASE_LIKE_SCALE));
// mViews.show();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
enableUp();
}
}
You can see the comment part, When I uncomment Showcaseview cant found those methods so maybe ShowcaseViews missing, anyway I tried to copy and create that class, but still need methods from showcaseview that cant be found.
Help Me.
Update: Ok according the answer below, I have a problem:
mViews = new ShowcaseView(this,
new ShowcaseView.setOnShowcaseEventListener() {
#Override
public void onShowCaseAcknowledged(ShowcaseView showcaseView) {
Toast.makeText(MultipleShowcaseSampleActivity.this, R.string.dismissed_message, Toast.LENGTH_SHORT).show();
}
});
mViews.addView( new ShowcaseView.ItemViewProperties(R.id.image,
R.string.showcase_image_title,
R.string.showcase_image_message,
SHOWCASE_KITTEN_SCALE));
mViews.addView( new ShowcaseView.ItemViewProperties(R.id.buttonLike,
R.string.showcase_like_title,
R.string.showcase_like_message,
SHOWCASE_LIKE_SCALE));
mViews.show();
On new ShowcaseView.setOnShowcaseEventListener() Cannot be resolve to a type
then new ShowcaseView.ItemViewProperties Cannot be resolve to a type too.
The library doesn't have any class called ShowCaseViews. It only has a class ShowCaseView.
If you are following this github example you have to have the class given in the link
EDIT Okay let me try and explain classes
There are 2 classes
ShowcaseView (in the library)
ShowcaseViews (in the example on Github)
You cannot say ShowcaseView.ItemProperties because ShowcaseView doesn't have them. They belong to ShowcaseViews. Hence they cannot be resolved or found.
OnShowcaseEventListener is a whole different class, contained in neither one of these but just exists separately and hence also when you say ShowcaseView.OnShowcaseEventListener it can't be resolved.
Change ShowcaseView.OnShowcaseEventListener to just OnShowcaseEventListener and ShowcaseView.ItemPropertiesto ShowcaseViews.ItemProperties

I can't seem to find android.R.id.radio0?(among others)

i'm dooing this tutorial and at one point he uses the R.id.xxxx where x is the name/id of a control I'm using, if I understood it correctly.
Now I have two of those R thing's -.-' and one is android.R and the other is dk.ilizane.android.temperatur.R which doesn't contain any id at all so I kinda figured I will be using android.R.id but i'm looking for editText1, radio0, radio1 and it doesn't contain any of those.
Is there anyone kind enough to try explain this to me? I'm trying to learn this so I would appreciate if the answer wasn't just the correct code but an answer which I can
My code:
package dk.ilizane.android.temperatur;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.Toast;
public class Omregn extends Activity
{
private EditText text;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
text = (EditText) findViewById(android.R.id.editText1);
}
public void myClickHandler(View view) {
switch (view.getId())
{
case android.R.id.button1:
RadioButton celsiusButton = (RadioButton) findViewById(dk.ilizane.android.temperatur.R);
RadioButton fahrenheitButton = (RadioButton) findViewById(android.R.id.radio1);
if (text.getText().length() == 0)
{
Toast.makeText(this, "Please enter a valid number", Toast.LENGTH_LONG).show();
return;
}
float inputValue = Float.parseFloat(text.getText().toString());
if(celsiusButton.isChecked()){
text.setText(String.valueOf(convertFahrenheitToCelsius(inputValue)));
}else {
text.setText(String.valueOf(convertCelsiusToFahrenheit(inputValue)));
}
if(fahrenheitButton.isChecked()){
fahrenheitButton.setChecked(false);
celsiusButton.setChecked(true);
}
else
{
fahrenheitButton.setChecked(true);
celsiusButton.setChecked(false);
}
break;
}
}
private float convertFahrenheitToCelsius(float fahrenheit){
return ((fahrenheit - 32) * 5 / 9);
}
private float convertCelsiusToFahrenheit(float celsius){
return ((celsius *9) / 5) + 32;
}
}
It should be in dk.ilizane.android.temperatur.R.id.radio1. If you look at the tutorial in the main.xml file the ids of the RadioButtons are radio0 and radio1. Your projects custom resources will be compiled into a class named R in your package. In Eclipse there should be a gen src directory that contains the java file.
Do you have a main.xml under /res/layout/? The R file you mentioned is generated as a way to reference your project resources. Check that you have the same resources defined as the ones in the tutorial. The R file will then exist as dk.ilizane.android.temperatur.R in the /gen directory.
I had this problem before, for some reason I had an import android.R; which causes conflict between import android.R; & com.packagename.R. If you delete the import android.R;, there will be no conflict & your code will compile.
But, if you really need the import android.R; then you have to specify which R you want.
For example, if you want to reference a View in you project you have to refer to the full path of the View like this com.packagename.R.id.viewName.

Categories

Resources