A simple Python remeshing
Disclaimer: The code in this post is written on version 9.1 of Simplygon. If you encounter this post at a later stage, some of the API calls might have changed. However, the core concepts should still remain valid.
Introduction
This post will give you a simple starting point for a remeshing script. We'll show how to turn an glb asset, colorized by material parameters, into a textured proxy.
The asset
We are going to use these merged spheres as an example asset. They have different materials, and the diffuse color is a parameter rather than a texture.
The remeshing pipeline script
Starting point
As always, let's use this same template as a starting point for our script.
from simplygon import simplygon_loader
from simplygon import Simplygon
def main():
sg = simplygon_loader.init_simplygon()
process_file(sg, "spheres.glb", "output.glb")
del sg
if __name__== "__main__":
main()
Nothing fancy here. The process_file function will do the bulk of the work.
Process file
Our goal with the process function is that it should take the incoming asset file, run a remeshing processing where a diffuse and a normal map is created. Finally, it should write out the result to the output file.
Let's start by importing the incoming asset.
def process_file(sg, asset_file, output_file):
# Load the asset we want to process
scene_importer = sg.CreateSceneImporter()
scene_importer.SetImportFilePath(asset_file)
if scene_importer.RunImport():
scene = scene_importer.GetScene()
Now that we have a scene, let's create a remeshing pipeline that we can apply to it.
remeshing_pipeline = sg.CreateRemeshingPipeline()
remesher_settings = remeshing_pipeline.GetRemeshingSettings()
remesher_settings.SetOnScreenSize(300)
This sets up the pipeline to create a really coarse representation asset.
Material casting
We need to add the desired material casters to the pipeline as well. Before we do that, let's set up the texture size for the output asset. How about 512x512?
mapping_image_settings = remeshing_pipeline.GetMappingImageSettings()
material_settings = mapping_image_settings.GetOutputMaterialSettings(0)
material_settings.SetTextureWidth(512)
material_settings.SetTextureHeight(512)
Time for the material casters. First we will add the material caster for the diffuse channel.
caster = sg.CreateColorCaster()
caster_settings = caster.GetColorCasterSettings()
caster_settings.SetMaterialChannel(Simplygon.SG_MATERIAL_CHANNEL_BASECOLOR)
remeshing_pipeline.AddMaterialCaster( caster, 0 )
Since our input is a glb file, the channel name for the diffuse color is Basecolor, which is the value of the constant SG_MATERIAL_CHANNEL_BASECOLOR.
When remeshing assets, it's typically a good idea to also generate a normal map as that will allow Simplygon to transfer geometrical details that are removed into that map. So, let's do that.
caster = sg.CreateNormalCaster()
caster_settings = caster.GetNormalCasterSettings()
caster_settings.SetGenerateTangentSpaceNormals(True)
caster_settings.SetMaterialChannel(Simplygon.SG_MATERIAL_CHANNEL_NORMALS)
remeshing_pipeline.AddMaterialCaster( caster, 0 )
Metalness and Roughness
If you want the representation to be as close as possible and are willing to sacrifice a bit extra texture memory, you can add casters for metalness and roughness as well. They are added the same way as the caster for the diffuse color, like this:
caster = sg.CreateColorCaster()
caster_settings = caster.GetColorCasterSettings()
caster_settings.SetMaterialChannel(Simplygon.SG_MATERIAL_CHANNEL_METALNESS)
remeshing_pipeline.AddMaterialCaster( caster, 0 )
caster = sg.CreateColorCaster()
caster_settings = caster.GetColorCasterSettings()
caster_settings.SetMaterialChannel(Simplygon.SG_MATERIAL_CHANNEL_ROUGHNESS)
remeshing_pipeline.AddMaterialCaster( caster, 0 )
Running the pipeline
Everything is in place for us to run the remeshing process and output the results. Here's the code that does that.
remeshing_pipeline.RunScene(scene, Simplygon.EPipelineRunMode_RunInThisProcess)
scene_exporter = sg.CreateSceneExporter()
scene_exporter.SetExportFilePath(output_file)
scene_exporter.SetScene(scene)
scene_exporter.RunExport()
The results
Running the script on our example asset will produce the following output.
The produced texture now contains the colors from the original materials.
This is all you need to create your first simple remeshing pipeline.
The complete script
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.
from simplygon import simplygon_loader
from simplygon import Simplygon
def process_file(sg, asset_file, output_file):
# Load the asset we want to process
scene_importer = sg.CreateSceneImporter()
scene_importer.SetImportFilePath(asset_file)
if scene_importer.RunImport():
scene = scene_importer.GetScene()
remeshing_pipeline = sg.CreateRemeshingPipeline()
remesher_settings = remeshing_pipeline.GetRemeshingSettings()
remesher_settings.SetOnScreenSize(300)
mapping_image_settings = remeshing_pipeline.GetMappingImageSettings()
material_settings = mapping_image_settings.GetOutputMaterialSettings(0)
material_settings.SetTextureWidth(1024)
material_settings.SetTextureHeight(1024)
caster = sg.CreateColorCaster()
caster_settings = caster.GetColorCasterSettings()
caster_settings.SetMaterialChannel(Simplygon.SG_MATERIAL_CHANNEL_BASECOLOR)
remeshing_pipeline.AddMaterialCaster( caster, 0 )
caster = sg.CreateColorCaster()
caster_settings = caster.GetColorCasterSettings()
caster_settings.SetMaterialChannel(Simplygon.SG_MATERIAL_CHANNEL_METALNESS)
remeshing_pipeline.AddMaterialCaster( caster, 0 )
caster = sg.CreateColorCaster()
caster_settings = caster.GetColorCasterSettings()
caster_settings.SetMaterialChannel(Simplygon.SG_MATERIAL_CHANNEL_ROUGHNESS)
remeshing_pipeline.AddMaterialCaster( caster, 0 )
caster = sg.CreateNormalCaster()
caster_settings = caster.GetNormalCasterSettings()
caster_settings.SetGenerateTangentSpaceNormals(True)
caster_settings.SetMaterialChannel(Simplygon.SG_MATERIAL_CHANNEL_NORMALS)
remeshing_pipeline.AddMaterialCaster( caster, 0 )
print("Running remeshing process...")
remeshing_pipeline.RunScene(scene, Simplygon.EPipelineRunMode_RunInThisProcess)
scene_exporter = sg.CreateSceneExporter()
scene_exporter.SetExportFilePath(output_file)
scene_exporter.SetScene(scene)
scene_exporter.RunExport()
def main():
sg = simplygon_loader.init_simplygon()
print(sg.GetVersion())
process_file(sg, "spheres.glb", "remeshed_spheres.glb")
del sg
if __name__== "__main__":
main()