Trouble with multiple basic shapes

I’ve been banging my head against such a basic problem for most of the day. I really am lost as to what the issue might be.



I am using jme3 on android 2.2

I have two shapes that I am trying to add to my scene but nothing is being drawn.



Cylinder shape = new Cylinder(16, 16, 0.0f, 2.0f, true);

Geometry geom = new Geometry(“cone”,shape);

cone.setLocalTranslation(0.0f, 1.0f, 0.0f);

Box shape2 = new Box(Vector3f.ZERO, 0.3f, 0.3f, 0.3f);

Geometry geom2 = new Geometry(“box”,shape2);

Node group = new Node();

group.addChild(geom);

group.addChild(geom2);



If I use either the cone or the box it renders without a problem, but if I use both nothing is rendered. Am I missing something obvious?

Are the materials on the geom different?

I think i read that the rendering fail on Android if there are 2 shaders sent to the GPU?

The materials are the same. I have even tried loading the same material into two variables to see if it makes a difference. I have however noticed that at some angles one of the shapes will appear and at other angles the other will appear, leading me to believe that it may be a culling/zbuffering issue.

try update model bounds

I have tried the following in the initialiser and during every upate and no improvement.



geom.updateModelBound();

geom.updateGeometricState();

geom.updateLogicalState(0.0f);

geom2.updateModelBound();

geom2.updateGeometricState();

geom2.updateLogicalState(0.0f);

group.updateModelBound();

group.updateGeometricState();

group.updateLogicalState(0.0f);

No, you dont need these calls, its something else.

Can you provide a test case that shows the issue?

Been out for a couple of days. As requested see below for an example.



import java.util.List;

import java.util.ArrayList;



import com.jme3.app.SimpleApplication;



import com.jme3.asset.TextureKey;



import com.jme3.material.Material;



import com.jme3.math.Transform;

import com.jme3.math.ColorRGBA;

import com.jme3.math.Vector3f;



import com.jme3.scene.Mesh;

import com.jme3.scene.Node;

import com.jme3.scene.Geometry;

import com.jme3.scene.shape.Cylinder;

import com.jme3.scene.shape.Sphere;

import com.jme3.scene.shape.Box;



import com.jme3.texture.Texture;



import com.jme3.light.PointLight;



import com.jme3.util.TangentBinormalGenerator;



import jme3tools.converters.model.ModelConverter;





public class JME3TestMultipleShapes extends SimpleApplication {



private static final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(JME3TestMultipleShapes.class.getName());





private Node group = new Node(“group”);

private Geometry geom;

private Geometry geom2;





@Override

public void simpleInitApp() {



guiNode.detachAllChildren();



Material material = new Material(assetManager, “Common/MatDefs/Misc/SolidColor.j3md”);

material.setColor(“m_Color”, ColorRGBA.Red);



//Sphere shape = new Sphere(16, 16, .5f);

Cylinder shape = new Cylinder(16, 16, 0.0f, 2.0f, true);

shape.setHalfAngle(0.7853f/2f);

TangentBinormalGenerator.generate(shape);



Box shape2 = new Box(Vector3f.ZERO, 0.3f, 0.3f, 0.3f);

TangentBinormalGenerator.generate(shape2);





geom = new Geometry(“cone”, shape);

geom.setLocalTranslation(0.0f, 0.0f, 1.5f);

geom.setMaterial(material);



geom2 = new Geometry(“box”,shape2);

geom2.setMaterial(material);



group.attachChild(geom);

group.attachChild(geom2);



group.setLocalTranslation(new Vector3f(0, 0, -4f));

group.setLocalScale(2.0f);



rootNode.attachChild(group);



PointLight pointLight = new PointLight();



pointLight.setColor(new ColorRGBA(0.7f, 0.7f, 1.0f, 1.0f));



pointLight.setPosition(new Vector3f(0f, 0f, 0f));

pointLight.setRadius(8);



rootNode.addLight(pointLight);

}



@Override

public void simpleUpdate(float tpf) {



if (secondCounter == 0)

logger.info("Frames per second: " + timer.getFrameRate());



group.rotate(0.2f * tpf, 0.4f * tpf, 0.8f * tpf);

geom.updateModelBound();

geom.updateGeometricState();

geom.updateLogicalState(tpf);

geom2.updateModelBound();

geom2.updateGeometricState();

geom2.updateLogicalState(tpf);

group.updateModelBound();

group.updateGeometricState();

group.updateLogicalState(tpf);



}



}

Are you using an HTC android device by any chance?

Samsung Galaxy S

Hello,



I’ve already tried on Samsung S and Tab: working with more than one mesh type and more than one material is NOT working.

You are trying to add more than one mesh type: a cylinder and a Box.

I’ve already notified Anton (The main Android Developper at JMonkey) about that.

I don’t know if it’s the same bug than the shader’s one see: http://hub.jmonkeyengine.org/groups/android/forum/topic/current-android-renderer-status/ but you should wait for the shaders fix before giving any other try…



Hope this helps !

I have been playing around with the renderer for a few days and was finally able to render more than one mesh and more than one material by using vertex arrays only, no VBO.



I would be nice if any of you could test this, i have tested on a Samsung Galaxy S under Android 2.2.1



The patch for the renderer to turn off VBO:



[patch]

Index: src/android/com/jme3/renderer/android/OGLESShaderRenderer.java

===================================================================

— src/android/com/jme3/renderer/android/OGLESShaderRenderer.java (revision 6806)

+++ src/android/com/jme3/renderer/android/OGLESShaderRenderer.java (working copy)

@@ -130,6 +130,7 @@



private static final Logger logger = Logger.getLogger(OGLESShaderRenderer.class.getName());

private static final boolean VALIDATE_SHADER = false;

  • private static final boolean USE_VBO = false;



    private final ByteBuffer nameBuf = BufferUtils.createByteBuffer(250);

    private final StringBuilder stringBuf = new StringBuilder(250);

    @@ -1923,9 +1924,9 @@

    GLES20.glBindTexture(type, texId);

    textures[unit] = image;


  •         statistics.onTextureUse(tex, true);<br />
    
  •         statistics.onTextureUse(tex.getImage(), true);<br />
    

}else{

  •         statistics.onTextureUse(tex, false);<br />
    
  •         statistics.onTextureUse(tex.getImage(), false);<br />
    

}



setupTextureParams(tex);

@@ -2510,35 +2511,53 @@

}

}


  • private void renderMeshVertexArray(Mesh mesh, int lod, int count){
  • /**
  • * renderMeshVertexArray renders a mesh using vertex arrays<br />
    
  • * @param mesh<br />
    
  • * @param lod<br />
    
  • * @param count<br />
    
  • */<br />
    
  • private void renderMeshVertexArray(Mesh mesh, int lod, int count)
  • {
  •    if (verboseLogging)<br />
    
  •        logger.info(&quot;renderMeshVertexArray&quot;);<br />
    

- if (verboseLogging)
- logger.info("renderMeshVertexArray");
+ IntMap<VertexBuffer> buffers = mesh.getBuffers();
+ for (Entry<VertexBuffer> entry : buffers){
+ VertexBuffer vb = entry.getValue();

- if (mesh.getId() == -1){
- updateVertexArray(mesh);
- }
+ if (vb.getBufferType() == Type.InterleavedData
+ || vb.getUsage() == Usage.CpuOnly // ignore cpu-only buffers
+ || vb.getBufferType() == Type.Index)
+ continue;

- if (context.boundVertexArray != mesh.getId()){
- // ARBVertexArrayObject.glBindVertexArray(mesh.getId());
- // GLES20.glBindVertexArray(mesh.getId());
- context.boundVertexArray = mesh.getId();
+ if (vb.getStride() == 0){
+ // not interleaved
+ setVertexAttrib_Array(vb);
+ }else{
+ // interleaved
+ VertexBuffer interleavedData = mesh.getBuffer(Type.InterleavedData);
+ setVertexAttrib_Array(vb, interleavedData);
+ }
}

- IntMap<VertexBuffer> buffers = mesh.getBuffers();
VertexBuffer indices = null;
- if (mesh.getNumLodLevels() > 0){
+ if (mesh.getNumLodLevels() > 0)
+ {
indices = mesh.getLodLevel(lod);
- }else{
+ }
+ else
+ {
indices = buffers.get(Type.Index.ordinal());
}
- if (indices != null){
- drawTriangleList(indices, mesh, count);
- }else{
-// throw new UnsupportedOperationException("Cannot render without index buffer");
-
- if (verboseLogging)
- logger.info("GLES20.glDrawArrays(" + mesh.getMode() + ", " + 0 + ", " + mesh.getVertexCount() + ")");
+ if (indices != null)
+ {
+ drawTriangleList_Array(indices, mesh, count);
+ }
+ else
+ {
+ if (verboseLogging)
+ logger.info("GLES20.glDrawArrays(" + mesh.getMode() + ", " + 0 + ", " + mesh.getVertexCount() + ")");

GLES20.glDrawArrays(convertElementMode(mesh.getMode()), 0, mesh.getVertexCount());
}
@@ -2613,7 +2632,10 @@
// if (GLContext.getCapabilities().GL_ARB_vertex_array_object){
// renderMeshVertexArray(mesh, lod, count);
// }else{
+ if (USE_VBO)
renderMeshDefault(mesh, lod, count);
+ else
+ renderMeshVertexArray(mesh, lod, count);
// }
}

@@ -2630,4 +2652,176 @@
return true;
}

+ /**
+ * drawTriangleList_Array uses Vertex Array
+ * @param indexBuf
+ * @param mesh
+ * @param count
+ */
+ public void drawTriangleList_Array(VertexBuffer indexBuf, Mesh mesh, int count)
+ {
+ if (verboseLogging)
+ logger.info("drawTriangleList_Array(Count = " + count + ")");
+
+ if (indexBuf.getBufferType() != VertexBuffer.Type.Index)
+ throw new IllegalArgumentException("Only index buffers are allowed as triangle lists.");
+
+ boolean useInstancing = count > 1 && caps.contains(Caps.MeshInstancing);
+ if (useInstancing)
+ {
+ throw new IllegalArgumentException("Caps.MeshInstancing is not supported.");
+ }
+
+ int vertCount = mesh.getVertexCount();
+ Buffer indexData = indexBuf.getData();
+ indexData.clear();
+
+ if (mesh.getMode() == Mode.Hybrid)
+ {
+ int[] modeStart = mesh.getModeStart();
+ int[] elementLengths = mesh.getElementLengths();
+
+ int elMode = convertElementMode(Mode.Triangles);
+ int fmt = convertFormat(indexBuf.getFormat());
+ int elSize = indexBuf.getFormat().getComponentSize();
+ int listStart = modeStart[0];
+ int stripStart = modeStart[1];
+ int fanStart = modeStart[2];
+ int curOffset = 0;
+ for (int i = 0; i < elementLengths.length; i++)
+ {
+ if (i == stripStart)
+ {
+ elMode = convertElementMode(Mode.TriangleStrip);
+ }
+ else if (i == fanStart)
+ {
+ elMode = convertElementMode(Mode.TriangleStrip);
+ }
+ int elementLength = elementLengths;
+
+ indexBuf.getData().position(curOffset);
+ if (verboseLogging)
+ logger.info("glDrawElements(): " + elementLength + ", " + curOffset);
+
+ GLES20.glDrawElements(elMode, elementLength, fmt, indexBuf.getData());
+
+ curOffset += elementLength * elSize;
+ }
+ }
+ else //if (mesh.getMode() == Mode.Hybrid)
+ {
+ if (verboseLogging)
+ logger.info("glDrawElements(), indexBuf.capacity (" + indexBuf.getData().capacity() + "), vertCount (" + vertCount + ")");
+
+ GLES20.glDrawElements(
+ convertElementMode(mesh.getMode()),
+ indexBuf.getData().capacity(),
+ convertFormat(indexBuf.getFormat()),
+ indexBuf.getData()
+ );
+ }
+ }
+
+ /**
+ * setVertexAttrib_Array uses Vertex Array
+ * @param vb
+ * @param idb
+ */
+ public void setVertexAttrib_Array(VertexBuffer vb, VertexBuffer idb)
+ {
+ if (verboseLogging)
+ logger.info("setVertexAttrib_Array(" + vb + ", " + idb + ")");
+
+ if (vb.getBufferType() == VertexBuffer.Type.Index)
+ throw new IllegalArgumentException("Index buffers not allowed to be set to vertex attrib");
+
+ // Get shader
+ int programId = context.boundShaderProgram;
+ if (programId > 0)
+ {
+ VertexBuffer[] attribs = context.boundAttribs;
+
+ Attribute attrib = boundShader.getAttribute(vb.getBufferType().name());
+ int loc = attrib.getLocation();
+ if (loc == -1)
+ {
+ //throw new IllegalArgumentException("Location is invalid for attrib: [" + vb.getBufferType().name() + "]");
+ if (verboseLogging)
+ logger.warning("attribute is invalid in shader: [" + vb.getBufferType().name() + "]");
+ return;
+ }
+ else if (loc == -2)
+ {
+ String attributeName = "in" + vb.getBufferType().name();
+
+ if (verboseLogging)
+ logger.info("GLES20.glGetAttribLocation(" + programId + ", " + attributeName + ")");
+
+ loc = GLES20.glGetAttribLocation(programId, attributeName);
+ if (loc < 0)
+ {
+ attrib.setLocation(-1);
+ if (verboseLogging)
+ logger.warning("attribute is invalid in shader: [" + vb.getBufferType().name() + "]");
+ return; // not available in shader.
+ }
+ else
+ {
+ attrib.setLocation(loc);
+ }
+
+ } // if (loc == -2)
+
+ if ((attribs[loc] != vb) || vb.isUpdateNeeded())
+ {
+ // NOTE: Use data from interleaved buffer if specified
+ VertexBuffer avb = idb != null ? idb : vb;
+ avb.getData().clear();
+ avb.getData().position(vb.getOffset());
+
+ if (verboseLogging)
+ logger.info("GLES20.glVertexAttribPointer(" +
+ "location=" + loc + ", " +
+ "numComponents=" + vb.getNumComponents() + ", " +
+ "format=" + vb.getFormat() + ", " +
+ "isNormalized=" + vb.isNormalized() + ", " +
+ "stride=" + vb.getStride() + ", " +
+ "data.capacity=" + avb.getData().capacity() + ")"
+ );
+
+
+ // Upload attribute data
+ GLES20.glVertexAttribPointer(loc,
+ vb.getNumComponents(),
+ convertFormat(vb.getFormat()),
+ vb.isNormalized(),
+ vb.getStride(),
+ avb.getData());
+ checkGLError();
+
+ GLES20.glEnableVertexAttribArray(loc);
+
+ attribs[loc] = vb;
+ } // if (attribs[loc] != vb)
+ }
+ else
+ {
+ throw new IllegalStateException("Cannot render mesh without shader bound");
+ }
+ }
+
+ /**
+ * setVertexAttrib_Array uses Vertex Array
+ * @param vb
+ */
+ public void setVertexAttrib_Array(VertexBuffer vb)
+ {
+ setVertexAttrib_Array(vb, null);
+ }
+
+ public void setAlphaToCoverage(boolean value)
+ {
+ // TODO Auto-generated method stub
+ }
}
[/patch]