Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Messages - Promyclon

Pages: [1]
Support / Re: Environment reflection on a textured objects
« on: August 29, 2017, 03:56:40 pm »
Knowing that objects always have a texture was all I needed. Just adding environment to the second channel should does the job. Thank you!

Support / Environment reflection on a textured objects
« on: August 28, 2017, 01:33:51 pm »

I managed so far to write couple of shaders for my model. Some of them add environment reflection to plain color element and it looks fine. I'm trying to find a way to to the same with textured elements.

Even this wasn't easy. I added environment texture to materials (.mtl) to make it accessible in fragment shader and found that an object loaded from .obj loses its color information from Kd field, that was available in color attribute. Color was got from (I guess) left top pixel of the texture. This color I had to hardcode in shaders and I could because I have distinct shader for every material that needs a non-different one.  I got to the point where I'd like to add a reflection to textured elements.

I open .obj and .mtl files in Java on PC to serialize it and use on Android. I decided to put my processing here to feed model's elements with additional data. I've extracted texture ID from elements to replace it with TextureInfo containing original texture and reflection texture. But as I could get texture using PolygonManager, I cannot find how can I get a vertex color. I think putting it in the additionalColor would preserve this color and I could have .mtl colored elements back.

But I cannot find how to extract from Object3D a Kd color from .mtl. How to preserve Kd color when a texture is added to an object?

At the moment of converting objects I don't know which ones will be reflective - this depends on their shaders in apk. So I'd add environment texture to all of them and remove the texture from map_Kd in .mtl. It's overfluous for sure (I know the map id is assigned to every polygon), but is there another way? Could I inject env map into the shaders in some other way?

Support / Re: Transparency lost after deserialization
« on: August 28, 2017, 09:02:09 am »
I've re-exported the model, removed workarounds, launched the app and the scene still looks good. Thanks Egon, your betas work!

Support / Re: Large obj file issue > 5mb
« on: August 28, 2017, 08:26:45 am »
Take into account that Android puts some restriction on files larger than 5MB. The solution is to pack them into a zip. These files, as well as i.e. mp3, can be larger than 5MB. Then use ZipInputStream to read them as ZipEntries.

Reading .obj files uses much memory because an entire file is read to the buffer first and is kept until all objects it contains are constructed by parsing lots of strings to floating point data. Reading serialized objects is more merciful for memory and is faster, although some data is ignored during serialization (I've still to check the new beta).

Support / Re: Transparency lost after deserialization
« on: August 22, 2017, 12:25:50 pm »
Further test showed that the new jpct_ae.jar successfully loads the old .j3d.

I've also checked the new constructor
Code: [Select]
Texture(InputStream is, boolean useAlpha, boolean closeStream)
After reading the first texture the ZipInputStream was closed. I've found that the chain of passing closeStream parameter is broken here:
Code: [Select]
private void loadTexture(InputStream is, Bitmap img, boolean alpha, boolean closeStream) {
        this.isLoaded = false;
        Logger.log("Loading Texture...", 2);

        try {
            Bitmap image = img;
            boolean recycleMe = false;
            if(img == null) {
                image = BitmapHelper.loadImage(is); // closeStream defaults to true there :(
                recycleMe = true;

And, finally, my mistake: new .j3d has 16 366 092 bytes while the old is 16 364 764 bytes long, that's 1328 bytes more in new file (I took 1kB for 1B), 8 bytes more per each object.

Support / Re: Transparency lost after deserialization
« on: August 22, 2017, 09:54:06 am »
Hi Egon,

I appreciate so quick update. I've used new jpct.jar (429 037 bytes) in my Java transcoder and got serialized (.j3d) file just one byte bigger, having stored 166 object in this file.
I copied jpcr_ae.jar (388 667 bytes) into my Android project, invalidated Android Studio caches, rebuilt a project and tried to load my new .j3d file having the following message:
08-22 06:26:29.204 4388-4411/gov.nasa.iss E/jPCT-AE: [ 1503383189204 ] - ERROR: Can't deserialize object: float[] array expected (410)!
So, something went wrong and I have now only programatically generated surface in my scene.

Support / Re: Transparency lost after deserialization
« on: August 21, 2017, 03:31:05 pm »
Thank you, Egon! Material data is important and so small, compared to the geometry, that adding it cannot harm :)

Support / Re: Transparency lost after deserialization
« on: August 21, 2017, 12:52:35 pm »
When I load object florm .obj, the attributes are taken from .mtl, assigned to objects by material names when the parser finds o or g lines. The material name is 'forgotten' but material's attributes are kept in object. When serializing some of them, like texture names are exported but some are not. If the object is not bound to a material anymore, how can I retrieve it's attributes?

The point is, I have a nice looking model in .obj & .mtl and I want it look nicely when I load it, faster, from a serialized form. And I cannot rewrite code whenever I change a model. For now I have retrieved from .mtl transparency data like that:

Code: [Select]
Map<String, Float> transMap = new TreeMap<>(); // <MaterialName, d attribute>
transMap.put("glass", 0.34f);
transMap.put("windscreen", 0.44f);
transMap.put("lights", 0.52f);

Only because I split earlier all objects to face groups by material, adding material to group names (because transparency is assigned by object an I had multimaterial objects) I could strip the object name from the original name and _jPCTnn suffix and reassign transparency after importing serialized model.

Code: [Select]
for (Object3D element : elements) {
  String elementMaterial = extractMaterialName(element.getName());
  Float transparency = transMap.get(elementMaterial);
  if (null != transparency) element.setTransparency((int) (100f * transparency)); // is this formula correct?

This, however, is an workaround that I cannot use in production because each model would need some implementation.

Of course, I can add all needed material attributes to object names (is there a limitation on object length?) but if we went to binary serialization to avoid text parsing overhead, it's not the direction we'd like to go.

Support / Transparency lost after deserialization
« on: August 21, 2017, 10:52:25 am »

I used the DeSerializer to speed-up loading of the model I had in OBJ:

Code: [Select]
class SerializeEngine {
private Object3D[] objects;
private String sourceModelFileName;
private String sourceMaterialFileName;

SerializeEngine(final String obj, final String mtl) {
sourceModelFileName = obj;
sourceMaterialFileName = mtl;

int loadObj() throws IOException {
try (InputStream modelFile = new FileInputStream(sourceModelFileName);
InputStream materialsFile = new FileInputStream(sourceMaterialFileName)) {
objects = Loader.loadOBJ(modelFile, materialsFile, 1.0f);
for (Object3D o : objects);
return objects.length;

String serialize() throws FileNotFoundException, IOException {
if (null == objects) throw new NullPointerException("Object not loaded");
if (0 == objects.length) throw new IndexOutOfBoundsException("Object is empty");
int l = sourceModelFileName.lastIndexOf('.');
String destModelFileName = ((l <= 0) ? sourceModelFileName : sourceModelFileName.substring(0, l)) + ".j3d";
try (OutputStream dest = new FileOutputStream(destModelFileName)) {
(new DeSerializer()).serializeArray(objects, dest, true);
return destModelFileName;

Then, instead of slow loading from .obj:

Code: [Select]
elements = Loader.loadOBJ(modelStream, materialStream, 1.0f);
I loaded the model in Android from a serialized form:

Code: [Select]
elements = Loader.loadSerializedObjectArray(modelStream);
and got the model loaded in application in jus about one second. The dispalyed model looked fine except for transparent elements. They lost their transparency. Did I do something wrong or the transparency isn't written to/read from the serialized form? I was looking at the jPCT-AE DeSerializer's code and couldn't find any code related with transparency but It's hard to believe this information is just lost.

Support / Problem loading textures from ZIP - BitmapHelper closes file
« on: August 21, 2017, 09:09:12 am »

I'm using jPCT-AE. To load set of bitmaps I made a ZIP fie in raw resource folder. I'ts convenient and more space-efficient to load many textures from a ZipInputStream. When I change the model, i.e. in another flavor of the app it will still work event if I'll have completely different set of textures but the file will have the same name. Unfortunately, whenever I call the first new Texture(InputStream is) iterating through ZipEntries in ZipInputStream, the stream is being closed by the BitmapHelper that decodes the image data. In my opinion this is a bug.  Java's BitmapFactory.decodeStream doesnt't do that. Closing of the stream should be the responsibility of the caller, who opens the stream.

To workaround I found the following solution that works as long as I us textures in .png (and whatever else the BitmapFactory recognizes):

Code: [Select]
private void loadTexturesFromZip(final int resId) {
        ZipEntry txMetadata;
        TextureManager txMan = TextureManager.getInstance();
        try {
            // try-with-resources closes the file automatically when leaving its scope:
            try (ZipInputStream zipTx = new ZipInputStream(res.openRawResource(resId))) {
                while (null != (txMetadata = zipTx.getNextEntry())) {
                    String txName = txMetadata.getName();
                    if (!txMan.containsTexture(txName)) {
                        Log.d(getClass().getSimpleName(), "Loading tx: " + txName);
                        Bitmap tx = BitmapFactory.decodeStream(zipTx);
                        if (null == tx) {
                            Log.e(getClass().getSimpleName(), "failed, bitmap is null");
                        } else {
                            txMan.addTexture(txName, new Texture(tx));
        } catch (Exception e) {
            Log.e(getClass().getCanonicalName(), "Texture loading failed: " + e.toString());

Pages: [1]