google-ar / sceneform-android-sdk

Sceneform SDK for Android
https://developers.google.com/sceneform/develop/
Apache License 2.0
1.23k stars 604 forks source link

Wrong offset in submesh triangles indices #77

Closed dyavil closed 6 years ago

dyavil commented 6 years ago

Hi, I tried to build a renderable from multiple meshes. One by one each meshes is well displayed but if i try to create a new renderable using them as submeshes it's not working well.

The material of the last (and with the greater number of vertices) submesh is applied to the whole renderable. Changing other materials do not change the renderable aspect. Plus there is some triangles which are missing (the last ones). The vertices list is a concatenation of each parts vertices in a a specific order. Each submesh is added in the same order as for the vertices and its triangle indices are changed accordingly.

It seems to me that the triangle indices offset must be wrong since it feels like each submesh is drawn from a common indices buffer but each draw start from the first element of that buffer. That would explain the missing lasts triangles and the common material (since the last and biggest submesh overwrite the previous triangles).

dsternfeld7 commented 6 years ago

Thanks for the report. Was this from loading a .sfb file or from using RenderableDefinition? If it is from a RenderableDefinition, can you provide sample code that reproduces the issue?

dyavil commented 6 years ago

It is using RenderableDefinition, i have several arrays of vertices and the corresponding indices. The code looks like that :

//First I create a global vertices buffer and specific indices buffer(for each submesh)
ArrayList<RenderableDefinition.Submesh> meshes = new ArrayList<>();
RenderableDefinition.Submesh[] modelSub = new 
RenderableDefinition.Submesh[mtlObjs.size()];
RenderableDefinition[] rendDef = new RenderableDefinition[1];
ArrayList<Vertex> verticesA = new ArrayList<>();
ArrayList<Integer>[] indicesList= new ArrayList[mtlObjs.size()];
int k = 0;
int count = 0;
Obj rendO = null;
for (Obj o : mtlObjs.values()){

     rendO = ObjUtils.convertToRenderable(o);

      float[] vertices0 = ObjData.getVerticesArray(rendO);
      float[] normals0 = ObjData.getNormalsArray(rendO);

       for (int l = 0; l < vertices0.length; l+=3){
             Vertex v = Vertex.builder().setPosition(new Vector3(vertices0[l], vertices0[l+1], vertices0[l+2])).setNormal(new Vector3(normals0[l], normals0[l+1], normals0[l+2])).build();
              verticesA.add(v);

        }

         int[] indicesO = ObjData.getFaceVertexIndicesArray(rendO);

         indicesList[k] = new ArrayList<>();

         for (int j = 0; j < indicesO.length; j++){
               indicesList[k].add((indicesO[j]+count));
          }
          //Updating id to get the geometry right
          count = verticesA.size();

          k++;
}

//then I create the renderable
Consumer<? super Material> action = (Consumer<Material>) material -> {
      for(int i = 0; i < mtlObjs.size(); i++){
          modelSub[i] = RenderableDefinition.Submesh.builder().setName("Model" + i).setTriangleIndices(indicesList[i]).setMaterial(material.makeCopy()).build();
          meshes.add(modelSub[i]);
       }
};

Consumer<? super Void> action2 = (Consumer<Void>) aVoid -> {
       rendDef[0] = RenderableDefinition.builder().setSubmeshes(meshes).setVertices(verticesA).build();
       try{
            ModelRenderable.builder()
              .setSource(rendDef[0])
              .build()
               .thenAccept(renderable ->{ models[2] = renderable;
                   })
                   .exceptionally(
                         throwable -> {
                              Toast toast =
                                   Toast.makeText(context, "Unable to load obj", Toast.LENGTH_LONG);
                                        toast.setGravity(Gravity.CENTER, 0, 0);
                                        toast.show();
                                        return null;
                                    });
        }catch (Exception e){
            e.printStackTrace();
        }
   };

MaterialFactory.makeOpaqueWithColor(context, new Color(0.5f, 0.3f, 0f, 0.8f)).thenAccept(action).thenAccept(action2);
dsternfeld7 commented 6 years ago

Thanks for the additional information! I've reproduced the bug, it will be fixed in an upcoming release.

dyavil commented 6 years ago

Thanks, then for the time beeing I will use a node tree.

dsternfeld7 commented 6 years ago

As a workaround until the fix is released, you can also deal with this by offsetting the indices in the indicesList by the sum of the length of all the indices list in previous submeshes.

malik-at-work commented 6 years ago

Fixed in Sceneform V1.3