mcneel / rhino3dm

Libraries based on OpenNURBS with a RhinoCommon style
MIT License
573 stars 135 forks source link

Exporting to 3DM format with three.js #579

Open GitHubDragonFly opened 5 months ago

GitHubDragonFly commented 5 months ago

I bothered creating a custom 3DMExporter that, in my opinion, does a decent job exporting meshes and points to 3dm format.

My question would be related to accessing rhino's material.textures array, which does not seem to exist but is included in the 3DMLoader.js code.

With the following code I can get all the necessary texture information, including base64 image strings, that can be used by the 3DM Loader, but cannot figure a way of passing it to rhino object to be written into the resulting file:

        // convert scene to JSON
        let json = JSON.stringify( scene.toJSON() );

        // parse metadata, geometries, materials, images, textures and object:
        let result = JSON.parse( json );

The above code can be seen in the link I provided to my exporter's code, which also shows a structure of the result variable for better understanding.

Just looking for any help I could get to try and improve the exporter by exporting textures together with the model.

GitHubDragonFly commented 5 months ago

Here is an example code that I am trying to make work and include in the exporter:

                        rhino_material = new Module.Material();
                        rhino_material.default();

                        // this textures array does get created and stores images
                        // but will not be included in the final output file

                        rhino_material.textures = [];

                        const texture_names = {};

                        function add_texture( map, map_type ) {

                            for ( const texture of result.textures ) {

                                if ( texture.uuid === map && ! texture_names[ texture.name ] ) {

                                    texture_names[ texture.name ] = texture.name;

                                    let tex = texture;

                                    tex.type = map_type;

                                    if ( texture.wrap !== undefined ) {

                                        tex.wrapU = texture.wrap[ 0 ] === 1000 ? 0 : 1;
                                        tex.wrapV = texture.wrap[ 1 ] === 1000 ? 0 : 1;

                                    }

                                    if ( texture.image ) {

                                        for ( const image of result.images ) {

                                            if ( image.uuid === texture.image ) {

                                                tex.image = image.url;

                                            }

                                        }

                                    }

                                    rhino_material.textures.push( tex );

                                }

                            }

                        }

                        if ( material.type === 'MeshStandardMaterial' || material.type === 'MeshPhysicalMaterial' ) {

                            if ( material.map ) add_texture( material.map, 'PBR_BaseColor' );
                            if ( material.aoMap ) add_texture( material.aoMap, 'PBR_AmbientOcclusion' );
                            if ( material.alphaMap ) add_texture( material.alphaMap, 'PBR_Alpha' );
                            if ( material.emissiveMap ) add_texture( material.emissiveMap, 'PBR_Emission' );
                            if ( material.anisotropyMap ) add_texture( material.anisotropyMap, 'PBR_Anisotropic' );
                            if ( material.clearcoatMap ) add_texture( material.clearcoatMap, 'PBR_Clearcoat' );
                            if ( material.clearcoatNormalMap ) add_texture( material.clearcoatNormalMap, 'PBR_ClearcoatBump' );
                            if ( material.clearcoatRoughnessMap ) add_texture( material.clearcoatRoughnessMap, 'PBR_ClearcoatRoughness' );
                            if ( material.displacementMap ) add_texture( material.displacementMap, 'PBR_Displacement' );
                            if ( material.metalnessMap ) add_texture( material.metalnessMap, 'PBR_Metallic' );
                            if ( material.roughnessMap ) add_texture( material.roughnessMap, 'PBR_Roughness' );
                            if ( material.sheenColorMap ) add_texture( material.sheenColorMap, 'PBR_Sheen' );
                            if ( material.specularColorMap ) add_texture( material.specularColorMap, 'PBR_Specular' );
                            if ( material.transmissionMap ) add_texture( material.transmissionMap, 'Opacity' );
                            if ( material.thicknessMap ) add_texture( material.thicknessMap, 'PBR_Subsurface' );

                        } else {

                            if ( material.map ) add_texture( material.map, 'Diffuse' );
                            if ( material.alphaMap ) add_texture( material.alphaMap, 'Transparency' );
                            if ( material.bumpMap ) add_texture( material.bumpMap, 'Bump' );
                            if ( material.envMap ) add_texture( material.envMap, 'Emap' );

                        }
fraguada commented 5 months ago

Hello! Thanks for sharing your exporter efforts. This is something that has been on my list to do, but have not yet come around to doing it.

I will take a look at your exporter implementation, but first I'd like to know what might be going wrong? I have a few ideas of some limitations, including adding embedded files (texture maps) into the 3dm. I am not sure we have exposed all of this properly in rhino3dm.js.

GitHubDragonFly commented 5 months ago

@fraguada thank you for responding.

Below you can see a screenshot of the browser console which shows the rhino material object and its properties.

The textures property is not available in the prototype of the object but is attached to the object as a property after my code is processed. Once this rhino material is added to the rhino object (File3dm) then it looks like that this textures property is just discarded.

This screenshot represents an attempt to export the Damaged Helmet example model.

Console - Rhino Material

GitHubDragonFly commented 5 months ago

@fraguada this is just an off topic FYI related to 3DM Loader available in the three.js repository. This is in case if you were the one to create it.

It contains typos for clearCoat properties (which should all be lowercase) and does not seem to be treating all the colors in the same way (dividing by 255.0).

On my end, I have included a modified version of 3DM Loader so you can check it if necessary.

I might also be wrong about some modifications.

GitHubDragonFly commented 4 months ago

@fraguada just as an FYI, eventually I figured out how to include textures and additional physical material properties by using user strings.

This is all a custom workaround but appears to be highly functional with three.js library, at least on my end.

You can close this issue at any time.