// This function stores the data into an .obj file static bool save_geometry_to_file(ISimplygonSDK sdk, spScene scene, string filepath) { // create the wavefront exporter spWavefrontExporter exp = sdk.CreateWavefrontExporter(); spGeometryData geom = Utils.SimplygonCast <spSceneMesh>(scene.GetRootNode().GetChild(0), false).GetGeometry(); // set the geometry exp.SetSingleGeometry(geom); // set file path exp.SetExportFilePath(filepath); // export to file return(exp.RunExport()); }
static void RunHighQualityReduction(ISimplygonSDK sdk, string readFrom, string writeTo) { spWavefrontImporter objReader = sdk.CreateWavefrontImporter(); objReader.SetExtractGroups(false); //This makes the .obj reader import into a single geometry object instead of multiple objReader.SetImportFilePath(readFrom); if (!objReader.RunImport()) { Console.WriteLine("Failed to read: " + readFrom); return; } spGeometryData originalGeom = objReader.GetFirstGeometry(); //Only contains a single geom, so "first" is fine spMaterialTable originalMaterials = objReader.GetMaterials(); //Create a copy of the original geometry on which we will run the reduction spGeometryData lodGeom = originalGeom.NewCopy(true); // Create the reduction-processor, and set the geometry to reduce spReductionProcessor reductionProcessor = sdk.CreateReductionProcessor(); reductionProcessor.SetGeometry(lodGeom); /////////////////////////////////////////////////////////////////////////////////////////////// // SETTINGS - Most of these are set to the same value by default, but are set anyway for clarity // The reduction settings object contains settings pertaining to the actual decimation spReductionSettings reductionSettings = reductionProcessor.GetReductionSettings(); reductionSettings.SetEnablePreprocessing(true); //This enables the pre-processing block, which contains welding and t-junction removal reductionSettings.SetEnablePostprocessing(true); //This enables the post-processing block, which contains normal recalculation and mapping image generation reductionSettings.SetKeepSymmetry(true); //Try, when possible to reduce symmetrically reductionSettings.SetUseAutomaticSymmetryDetection(true); //Auto-detect the symmetry plane, if one exists. Can, if required, be set manually instead. reductionSettings.SetUseHighQualityNormalCalculation(true); //Drastically increases the quality of the LODs normals, at the cost of extra processing time. reductionSettings.SetReductionHeuristics((uint)ReductionHeuristics.SG_REDUCTIONHEURISTICS_CONSISTENT); //Choose between "fast" and "consistent" processing. Fast will look as good, but may cause inconsistent //triangle counts when comparing MaxDeviation targets to the corresponding percentage targets. // The reducer uses a feature flags mask to tell it what kind of borders to respect during reduction. FeatureFlags featureFlagsMask = 0; featureFlagsMask |= FeatureFlags.SG_FEATUREFLAGS_GROUP; //Respect borders between group ids featureFlagsMask |= FeatureFlags.SG_FEATUREFLAGS_MATERIAL; //Respect borders between material ids featureFlagsMask |= FeatureFlags.SG_FEATUREFLAGS_TEXTURE0; //Respect discontinuities in the first texcoord field featureFlagsMask |= FeatureFlags.SG_FEATUREFLAGS_SHADING; //Respect hard shading borders reductionSettings.SetFeatureFlags((uint)featureFlagsMask); // The reducer uses importance weights for all features to decide where and how to reduce. // These are advanced settings and should only be changed if you have some specific reduction requirement /*reductionSettings.SetShadingImportance(2.f); //This would make the shading twice as important to the reducer as the other features.*/ // The actual reduction triangle target are controlled by these three settings reductionSettings.SetStopCondition((uint)StopCondition.SG_STOPCONDITION_EITHER_IS_REACHED); //The reduction stops when either of the targets is reached reductionSettings.SetReductionRatio(0.5f); //Stops at 50% of the original triangle count reductionSettings.SetMaxDeviation(SimplygonSDK.REAL_MAX); //Stops when an error of the specified size has been reached. As set here it never happens. //This condition corresponds to the on-screen size target presented in the Simplygon GUI, with a simple formula to convert between the two. // The repair settings object contains settings for the pre-processing block spRepairSettings repairSettings = reductionProcessor.GetRepairSettings(); repairSettings.SetTjuncDist(0.0f); //Removes t-junctions with distance 0.0f repairSettings.SetWeldDist(0.0f); //Welds overlapping vertices // The normal calculation settings deal with the normal-specific reduction settings spNormalCalculationSettings normalSettings = reductionProcessor.GetNormalCalculationSettings(); normalSettings.SetReplaceNormals(false); //If true, this will turn off normal handling in the reducer and recalculate them all afterwards instead. //If false, the reducer will try to preserve the original normals as well as possible /*normalSettings.SetHardEdgeAngle( 60.f ); //If the normals are recalculated, this sets the hard-edge angle.*/ //END SETTINGS /////////////////////////////////////////////////////////////////////////////////////////////// // Run the actual processing. After this, the set geometry will have been reduced according to the settings reductionProcessor.RunProcessing(); //Create an .obj exporter to save our result spWavefrontExporter objExporter = sdk.CreateWavefrontExporter(); // Do the actual exporting objExporter.SetExportFilePath(writeTo + ".obj"); objExporter.SetSingleGeometry(lodGeom); //This is the geometry we set as the processing geom of the reducer objExporter.SetMaterials(originalMaterials); //Same material set as input if (!objExporter.RunExport()) { Console.WriteLine("Failed to write target file"); } //Done! LOD created. }
static void RunCascadedLodChainReduction(ISimplygonSDK sdk, string readFrom, string writeToLod1, string writeToLod2, string writeToLod3) { // Load input geometry from file spWavefrontImporter objReader = sdk.CreateWavefrontImporter(); objReader.SetExtractGroups(false); //This makes the .obj reader import into a single geometry object instead of multiple objReader.SetImportFilePath(readFrom); if (!objReader.RunImport()) { return; } // Get geometry and materials from importer spGeometryData originalGeometry = objReader.GetFirstGeometry(); //Only contains a single geom, so "first" is fine spMaterialTable originalMaterialTable = objReader.GetMaterials(); //Create a copy of the original geometry on which we will run the reduction spGeometryData lodGeometry = originalGeometry.NewCopy(true); // Create the reduction-processor, and set the geometry to reduce spReductionProcessor reductionProcessor = sdk.CreateReductionProcessor(); reductionProcessor.SetGeometry(lodGeometry); /////////////////////////////////////////////////////////////////////////////////////////////// // SETTINGS // The reduction settings object contains settings pertaining to the actual decimation spReductionSettings reductionSettings = reductionProcessor.GetReductionSettings(); reductionSettings.SetReductionHeuristics((uint)ReductionHeuristics.SG_REDUCTIONHEURISTICS_FAST); //Choose between "fast" and "consistent" processing. // The normal calculation settings deal with the normal-specific reduction settings spNormalCalculationSettings normalSettings = reductionProcessor.GetNormalCalculationSettings(); normalSettings.SetReplaceNormals(true); //If true, this will turn off normal handling in the reducer and recalculate them all afterwards instead. normalSettings.SetHardEdgeAngle(70.0f); //If the normals are recalculated, this sets the hard-edge angle. // The actual reduction triangle target are controlled by these three settings reductionSettings.SetStopCondition((uint)StopCondition.SG_STOPCONDITION_EITHER_IS_REACHED); //The reduction stops when either of the targets is reached reductionSettings.SetReductionRatio(0.0f); //Never stop at a triangle percentage, will hit MaxDeviation instead. //END SETTINGS /////////////////////////////////////////////////////////////////////////////////////////////// //Create an .obj exporter to save our result spWavefrontExporter objExporter = sdk.CreateWavefrontExporter(); objExporter.SetSingleGeometry(lodGeometry); //This is the geometry we set as the processing geom of the reducer objExporter.SetMaterials(originalMaterialTable); //Same materials as original //Set reduction targets using on-screen size to set the maximum deviation originalGeometry.CalculateExtents(true); //This calculates the bounds of the geometry float[] geometryInf = new float[3]; float[] geometrySup = new float[3]; originalGeometry.GetInf(geometryInf); originalGeometry.GetSup(geometrySup); float geometryDiagonalLength = (float)Math.Sqrt((double)((geometrySup[0] - geometryInf[0]) * (geometrySup[0] - geometryInf[0]) + (geometrySup[1] - geometryInf[1]) * (geometrySup[1] - geometryInf[1]) + (geometrySup[2] - geometryInf[2]) * (geometrySup[2] - geometryInf[2]))); float[] maxDeviationTargets = new float[3]; //To find an approximate MaxDeviation for a pixelsize on screen, we just divide the diagonal by our wanted pixelsize maxDeviationTargets[0] = geometryDiagonalLength / 500.0f; //Gives a deviation of max 1 pixel at ~500 pixels on-screen maxDeviationTargets[1] = geometryDiagonalLength / 100.0f; //Gives a deviation of max 1 pixel at ~100 pixels on-screen maxDeviationTargets[2] = geometryDiagonalLength / 50.0f; //Gives a deviation of max 1 pixel at ~50 pixels on-screen //Generate the output filenames string[] outputGeomFilename = new string[3]; outputGeomFilename[0] = writeToLod1 + ".obj"; outputGeomFilename[1] = writeToLod2 + ".obj"; outputGeomFilename[2] = writeToLod3 + ".obj"; // Run the iterative processing, saving the output geometry after every process for (int reductionIteration = 0; reductionIteration < 3; ++reductionIteration) { // The geometry still uses the same pointer, so it does not need to be re-set for the exporter or reducer after each pass. reductionSettings.SetMaxDeviation(maxDeviationTargets[reductionIteration]); //Stops when an error of the specified size has been reached. reductionProcessor.RunProcessing(); // Do the exporting objExporter.SetMaterialFilePath(null); //Reset the material file path so it's set by ExportFilePath objExporter.SetExportFilePath(outputGeomFilename[reductionIteration]); if (!objExporter.RunExport()) { Console.WriteLine("Failed to write target file"); } } //Done! 3 cascaded LODs created. }
static void RunReductionWithTextureCasting(ISimplygonSDK sdk, string readFrom, string writeTo) { // Load input geometry from file spWavefrontImporter objReader = sdk.CreateWavefrontImporter(); objReader.SetExtractGroups(false); //This makes the .obj reader import into a single geometry object instead of multiple objReader.SetImportFilePath(readFrom); if (!objReader.RunImport()) { Console.WriteLine("Failed to read: " + readFrom); return; } // Get geometry and materials from importer spGeometryData originalGeom = objReader.GetFirstGeometry(); //Only contains a single geom, so "first" is fine spMaterialTable originalMaterialTable = objReader.GetMaterials(); // Create a copy of the original geometry on which we will run the reduction spGeometryData lodGeometry = originalGeom.NewCopy(true); // Create the reduction-processor, and set the geometry to reduce spReductionProcessor reductionProcessor = sdk.CreateReductionProcessor(); reductionProcessor.SetGeometry(lodGeometry); /////////////////////////////////////////////////////////////////////////////////////////////// // SETTINGS - Most of these are set to the same value by default, but are set anyway for clarity // The reduction settings object contains settings pertaining to the actual decimation spReductionSettings reductionSettings = reductionProcessor.GetReductionSettings(); reductionSettings.SetReductionHeuristics((uint)ReductionHeuristics.SG_REDUCTIONHEURISTICS_FAST); //Choose between "fast" and "consistent" processing. // The actual reduction triangle target are controlled by these three settings reductionSettings.SetStopCondition((uint)StopCondition.SG_STOPCONDITION_EITHER_IS_REACHED); //The reduction stops when either of the targets is reached reductionSettings.SetReductionRatio(0.5f); //Stops at 50% of the original triangle count reductionSettings.SetMaxDeviation(SimplygonSDK.REAL_MAX); //Stops when an error of the specified size has been reached. As set here it never happens. // The normal calculation settings deal with the normal-specific reduction settings spNormalCalculationSettings normalSettings = reductionProcessor.GetNormalCalculationSettings(); normalSettings.SetReplaceNormals(true); //If true, this will turn off normal handling in the reducer and recalculate them all afterwards instead. normalSettings.SetHardEdgeAngle(70.0f); //If the normals are recalculated, this sets the hard-edge angle. // The Image Mapping Settings, specifically needed for the texture baking we are doing later spMappingImageSettings mappingSettings = reductionProcessor.GetMappingImageSettings(); mappingSettings.SetGenerateMappingImage(true); //Without this we cannot fetch data from the original geometry, and thus not generate diffuse and normal-maps later on. mappingSettings.SetGenerateTexCoords(true); //Set to generate new texture coordinates. mappingSettings.SetMaxStretch(0.4f); //The higher the number, the fewer texture-borders. mappingSettings.SetGutterSpace(2); //Buffer space for when texture is mip-mapped, so color values don't blend over. Greatly influences packing efficiency mappingSettings.SetTexCoordLevel(0); //Sets the output texcoord level. For this asset, this will overwrite the original coords mappingSettings.SetWidth(1024); mappingSettings.SetHeight(1024); mappingSettings.SetMultisamplingLevel(2); //END SETTINGS /////////////////////////////////////////////////////////////////////////////////////////////// // Run the actual processing. After this, the set geometry will have been reduced according to the settings reductionProcessor.RunProcessing(); /////////////////////////////////////////////////////////////////////////////////////////////// // CASTING // Now, we need to retrieve the generated mapping image and use it to cast the old materials into a new one, for each channel. spMappingImage mappingImage = reductionProcessor.GetMappingImage(); // Now, for each channel, we want to cast the 9 input materials into a single output material, with one texture per channel. // First, create a new material table. spMaterialTable lodMaterialTable = sdk.CreateMaterialTable(); // Create new material for the table. spMaterial lodMaterial = sdk.CreateMaterial(); lodMaterial.SetName("SimplygonBakedMaterial"); lodMaterialTable.AddMaterial(lodMaterial); // Cast diffuse and specular texture data with a color caster { // Set the material properties lodMaterial.SetColor(SimplygonSDK.SG_MATERIAL_CHANNEL_AMBIENT, 0, 0, 0, 0); lodMaterial.SetColor(SimplygonSDK.SG_MATERIAL_CHANNEL_DIFFUSE, 1, 1, 1, 1); lodMaterial.SetColor(SimplygonSDK.SG_MATERIAL_CHANNEL_SPECULAR, 1, 1, 1, 128); //Note the 128 on the specular channels alpha. Simplygon bakes shininess //to the alpha channel of the specular map if the caster is set to 4 channel //output, and it is scaled between 0 and 1 internally. To get the correct //scale on the output, it should be multiplied by 128. // Cast the data using a color caster spColorCaster colorCaster = sdk.CreateColorCaster(); colorCaster.SetSourceMaterials(originalMaterialTable); colorCaster.SetDestMaterial(lodMaterial); //This modulates the cast color with the base colors set for the dest material above. //It means the internal shininess is multiplied by 128 before baking to texture. colorCaster.SetMappingImage(mappingImage); //The mapping image we got from the reduction process. colorCaster.SetOutputChannelBitDepth(8); //8 bits per channel. So in this case we will have 24bit colors RGB. colorCaster.SetDilation(10); //To avoid mip-map artifacts, the empty pixels on the map needs to be filled to a degree as well. colorCaster.SetColorType(SimplygonSDK.SG_MATERIAL_CHANNEL_DIFFUSE); colorCaster.SetOutputChannels(3); //RGB, 3 channels! (1 would be for grey scale, and 4 would be for RGBA.) colorCaster.SetOutputFilePath("combinedDiffuseMap.png"); //Where the texture map will be saved to file. colorCaster.CastMaterials(); //Do the actual casting and write to texture. colorCaster.SetColorType(SimplygonSDK.SG_MATERIAL_CHANNEL_SPECULAR); colorCaster.SetOutputChannels(4); //RGBA, 4 channels! Stores spec power in A colorCaster.SetOutputFilePath("combinedSpecularMap.png"); //Where the texture map will be saved to file. colorCaster.CastMaterials(); //Do the actual casting and write to texture. lodMaterial.SetTexture(SimplygonSDK.SG_MATERIAL_CHANNEL_DIFFUSE, "combinedDiffuseMap.png"); //Set material to point to the texture we cast to above lodMaterial.SetTexture(SimplygonSDK.SG_MATERIAL_CHANNEL_SPECULAR, "combinedSpecularMap.png"); //Set material to point to the texture we cast to above } // Cast normal map texture data with the normal caster. This also compensates for any geometric errors that have appeared in the reduction process. { // cast the data using a normal caster spNormalCaster normalCaster = sdk.CreateNormalCaster(); normalCaster.SetSourceMaterials(originalMaterialTable); normalCaster.SetMappingImage(mappingImage); normalCaster.SetOutputChannels(3); // RGB, 3 channels! (But really the x, y and z values for the normal) normalCaster.SetOutputChannelBitDepth(8); normalCaster.SetDilation(10); normalCaster.SetOutputFilePath("combinedNormalMap.png"); normalCaster.SetFlipBackfacingNormals(false); normalCaster.SetGenerateTangentSpaceNormals(true); normalCaster.CastMaterials(); // Set normal map of the created material to point to the combined normal map lodMaterial.SetTexture(SimplygonSDK.SG_MATERIAL_CHANNEL_NORMALS, "combinedNormalMap.png"); } // END CASTING /////////////////////////////////////////////////////////////////////////////////////////////// //Create an .obj exporter to save our result spWavefrontExporter objExporter = sdk.CreateWavefrontExporter(); // Generate the output filenames // Do the actual exporting objExporter.SetExportFilePath(writeTo + ".obj"); objExporter.SetSingleGeometry(lodGeometry); //This is the geometry we set as the processing geom of the reducer objExporter.SetMaterials(lodMaterialTable); //Our new cast material if (!objExporter.RunExport()) { Console.WriteLine("Failed to write target file"); } //Done! LOD and material created. }
private static void RunHighQualityReduction(ISimplygonSDK SDK, string writeTo) { const int vertex_count = 12; const int triangle_count = 4; // 4 triangles x 3 indices ( or 3 corners ) int[] corner_ids = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; // 12 vertices with values for the x, y and z coordinates. float[] vertex_coordinates = { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 2.0f, 0.0f, 0.0f, 2.0f, 1.0f, 0.0f, 2.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f }; spGeometryData g = SDK.CreateGeometryData(); spRealArray coords = g.GetCoords(); spRidArray ids = g.GetVertexIds(); g.SetVertexCount(vertex_count); g.SetTriangleCount(triangle_count); for (int i = 0; i < vertex_count; ++i) { //coords.SetTuple(i, vertex_coordinates[i * 3]); //coords[i] = vertex_coordinates[i * 3]; float[] v = { 0.0f, 0.0f, 0.0f }; for (int j = 0; j < 3; ++j) { v[j] = vertex_coordinates[i * 3 + j]; } coords.SetTuple(i, v); } for (int i = 0; i < corner_ids.Length; ++i) { ids.SetItem(i, corner_ids[i]); } // Create the reduction-processor, and set which scene to reduce using (var reductionProcessor = SDK.CreateReductionProcessor()) { spScene scene = SDK.CreateScene(); spSceneNode root = scene.GetRootNode(); spSceneMesh meshNode = SDK.CreateSceneMesh(); meshNode.SetGeometry(g); //auto meshTransform = meshNode->GetRelativeTransform(); //meshTransform->SetToTranslationTransform(100, 0, 0); root.AddChild(meshNode); reductionProcessor.SetSceneRoot(root); /////////////////////////////////////////////////////////////////////////////////////////////// // SETTINGS - Most of these are set to the same value by default, but are set anyway for clarity // The reduction settings object contains settings pertaining to the actual decimation var reductionSettings = reductionProcessor.GetReductionSettings(); reductionSettings.SetKeepSymmetry(true); //Try, when possible to reduce symmetrically reductionSettings.SetUseAutomaticSymmetryDetection(true); //Auto-detect the symmetry plane, if one exists. Can, if required, be set manually instead. reductionSettings.SetUseHighQualityNormalCalculation(true); //Drastically increases the quality of the LODs normals, at the cost of extra processing time. reductionSettings.SetReductionHeuristics((uint)ReductionHeuristics.SG_REDUCTIONHEURISTICS_CONSISTENT); //Choose between "fast" and "consistent" processing. Fast will look as good, but may cause inconsistent //triangle counts when comparing MaxDeviation targets to the corresponding percentage targets. // The reducer uses importance weights for all features to decide where and how to reduce. // These are advanced settings and should only be changed if you have some specific reduction requirement //reductionSettings.SetShadingImportance(2.f); //This would make the shading twice as important to the reducer as the other features./ // The actual reduction triangle target are controlled by these settings reductionSettings.SetStopCondition((uint)StopCondition.SG_STOPCONDITION_EITHER_IS_REACHED); //The reduction stops when any of the targets below is reached reductionSettings.SetReductionRatio(0.5f); //Targets at 50% of the original triangle count reductionSettings.SetMaxDeviation(float.MaxValue); //Targets when an error of the specified size has been reached. As set here it never happens. // The repair settings object contains settings to fix the geometries var repairSettings = reductionProcessor.GetRepairSettings(); repairSettings.SetTjuncDist(0.0f); //Removes t-junctions with distance 0.0f repairSettings.SetWeldDist(0.0f); //Welds overlapping vertices // The normal calculation settings deal with the normal-specific reduction settings var normalSettings = reductionProcessor.GetNormalCalculationSettings(); normalSettings.SetReplaceNormals(false); //If true, this will turn off normal handling in the reducer and recalculate them all afterwards instead. //If false, the reducer will try to preserve the original normals as well as possible //normalSettings.SetHardEdgeAngle( 60.f ); //If the normals are recalculated, this sets the hard-edge angle./ //END SETTINGS /////////////////////////////////////////////////////////////////////////////////////////////// // Run the actual processing. After this, the set geometry will have been reduced according to the settings reductionProcessor.RunProcessing(); // For this reduction, the LOD will use the same material set as the original, and hence no further processing is required //Create an .obj exporter to save our result using (var objExporter = SDK.CreateWavefrontExporter()) { // Generate the output filenames string outputGeomFilename = writeTo + ".obj"; spSceneMesh topmesh = Utils.SimplygonCast <spSceneMesh>(scene.GetRootNode().GetChild(0), false); // Do the actual exporting objExporter.SetExportFilePath(outputGeomFilename); objExporter.SetSingleGeometry(topmesh.GetGeometry()); //This is the geometry we set as the processing geom of the reducer, retaining the materials in the original scene objExporter.RunExport(); //Done! LOD created. } } }
static void bend_geometry(ISimplygonSDK sdk, spScene scene) { // The two bones that influence the vertices //spMatrix4x4 sp_bone1; spGeometryData geom = Utils.SimplygonCast <spSceneMesh>(scene.GetRootNode().GetChild(0)).GetGeometry(); // get the bone weights field and ids spRealArray boneWeights = geom.GetBoneWeights(); spRidArray boneIds = geom.GetBoneIds(); // get the Coordinates field spRealArray Coords = geom.GetCoords(); // now, transform all vertices' coordinates using the bones for (int v = 0; v < Coords.GetTupleCount(); ++v) { Vector3D vtx = new Vector3D(Coords.GetItem(v * 3 + 0), Coords.GetItem(v * 3 + 1), Coords.GetItem(v * 3 + 2)); uint no = boneIds.GetItemCount(); int bone_id_1 = boneIds.GetItem(v * 2 + 0); int bone_id_2 = boneIds.GetItem(v * 2 + 1); spSceneBone bone_1; spSceneBone bone_2; Matrix4x4 b1gtMat; Matrix4x4 b2gtMat; Vector3D vtx1 = new Vector3D(vtx); Vector3D vtx2 = new Vector3D(vtx); if (bone_id_1 != -1) { bone_1 = scene.GetBoneTable().GetBone(bone_id_1); //retrieve the global transform of the bone in bind space spMatrix4x4 rootGlobalTransform = sdk.CreateMatrix4x4(); bone_1.EvaluateDefaultGlobalTransformation(rootGlobalTransform); //apply transfrom to animate bone spTransform3 bone1_transform = sdk.CreateTransform3(); bone1_transform.AddTransformation(rootGlobalTransform); bone1_transform.AddRotation(GetRadFromDegrees(-30), 1, 0, 0); rootGlobalTransform = bone1_transform.GetMatrix(); //apply transform b1gtMat = GetMatrix4x4FromIMatrix(rootGlobalTransform); vtx1 = b1gtMat.MultiplyPointVector(vtx); } if (bone_id_2 != -1) { bone_2 = scene.GetBoneTable().GetBone(bone_id_2); spMatrix4x4 boneGlobalTransform = sdk.CreateMatrix4x4(); bone_2.EvaluateDefaultGlobalTransformation(boneGlobalTransform); spTransform3 bone2_transform = sdk.CreateTransform3(); //transform into bone2's local space and apply transform bone2_transform.PreMultiply(); boneGlobalTransform.Invert(); bone2_transform.AddTransformation(boneGlobalTransform); bone2_transform.AddRotation(GetRadFromDegrees(-30), 1, 0, 0); bone2_transform.AddTranslation(0.0f, 17.5f, 0.0f); //apply transform of the first bone bone2_transform.AddRotation(GetRadFromDegrees(-30), 1, 0, 0); //get the global transform matrix for the animation pose boneGlobalTransform = bone2_transform.GetMatrix(); b2gtMat = GetMatrix4x4FromIMatrix(boneGlobalTransform); //apply transform to the vertex vtx2 = b2gtMat.MultiplyPointVector(vtx); } //get the bone weights from the geometry data float blend1 = boneWeights.GetItem(v * 2 + 0); float blend2 = boneWeights.GetItem(v * 2 + 1); // normalize the blend float blend_scale = 1.0f / (blend1 + blend2); blend1 *= blend_scale; blend2 *= blend_scale; // do a linear blend vtx = vtx1 * blend1 + vtx2 * blend2; // store in coordinates Coords.SetItem(v * 3 + 0, vtx.x); Coords.SetItem(v * 3 + 1, vtx.y); Coords.SetItem(v * 3 + 2, vtx.z); } }
//this function generates a fixed tube static spScene generate_simple_tube(ISimplygonSDK sdk) { const int vertex_count = 16; const int triangle_count = 24; const int corner_count = triangle_count * 3; //create a scene object spScene scene = sdk.CreateScene(); // triangles x 3 indices ( or 3 corners ) int[] corner_ids = { 0, 1, 4, 4, 1, 5, 5, 1, 6, 1, 2, 6, 6, 2, 3, 6, 3, 7, 7, 3, 0, 7, 0, 4, 4, 5, 8, 8, 5, 9, 9, 5, 10, 5, 6, 10, 10, 6, 7, 10, 7, 11, 11, 7, 4, 11, 4, 8, 8, 9, 12, 12, 9, 13, 13, 9, 14, 9, 10, 14, 14, 10, 11, 14, 11, 15, 15, 11, 8, 15, 8, 12 }; // vertices with values for the x, y and z coordinates. float[] vertex_coordinates = { 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, -1.0f, -1.0f, 0.0f, -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 15.0f, 1.0f, 1.0f, 15.0f, -1.0f, -1.0f, 15.0f, -1.0f, -1.0f, 15.0f, 1.0f, 1.0f, 20.0f, 1.0f, 1.0f, 20.0f, -1.0f, -1.0f, 20.0f, -1.0f, -1.0f, 20.0f, 1.0f, 1.0f, 35.0f, 1.0f, 1.0f, 35.0f, -1.0f, -1.0f, 35.0f, -1.0f, -1.0f, 35.0f, 1.0f }; spGeometryData geom = sdk.CreateGeometryData(); //add bone weights and ids to geometry data (per vertex) geom.AddBoneWeights(2); spRealArray coords = geom.GetCoords(); spRidArray vertex_ids = geom.GetVertexIds(); spRealArray BoneWeights = geom.GetBoneWeights(); spRidArray BoneIds = geom.GetBoneIds(); geom.SetVertexCount(vertex_count); geom.SetTriangleCount(triangle_count); //create the bone table spSceneBoneTable scn_bone_table = scene.GetBoneTable(); //create an array to store bone ids spRidArray bone_ids = sdk.CreateRidArray(); //create root bone for the scene spSceneBone root_bone = sdk.CreateSceneBone(); root_bone.SetName("root_bone"); //add the bone to the scene bone table and get a bone id int root_bone_id = scn_bone_table.AddBone(root_bone); //a bone_ids.AddItem(root_bone_id); spSceneBone parent_bone = root_bone; //create bones and populate the scene bone table for (uint bone_index = 1; bone_index < total_bone; bone_index++) { spSceneBone bone = sdk.CreateSceneBone(); bone.SetName("ChildBone"); spTransform3 boneTransform = sdk.CreateTransform3(); //SET UP BONE IN BIND POSE //translate the child bone to its corrent position relative to the parent bone boneTransform.AddTransformation(bone.GetRelativeTransform()); boneTransform.PreMultiply(); boneTransform.AddTranslation(0.0f, 17.5f, 0.0f); //store the relatvice transform bone.GetRelativeTransform().DeepCopy(boneTransform.GetMatrix()); //add bone to the scene bone table int bone_id = scn_bone_table.AddBone(bone); //link bone to parent bone parent_bone.AddChild(bone); bone_ids.AddItem(bone_id); parent_bone = bone; } float[] v = new float[3]; for (int i = 0; i < vertex_count; ++i) { v[0] = vertex_coordinates[i * 3]; v[1] = vertex_coordinates[i * 3 + 1]; v[2] = vertex_coordinates[i * 3 + 2]; coords.SetTuple(i, v); //real blend_val = real((rid(i)/rid(4)))/real(3); float blend_val = 0.5f; float blend1 = 1.0f - blend_val; float blend2 = blend_val; int bone_id_1 = 0; int bone_id_2 = 1; if (i < 4) { bone_id_2 = -1; blend2 = 0; blend1 = 1; } else if (i > 11) { bone_id_1 = -1; blend2 = 1; blend1 = 0; } blend1 *= blend1; blend2 *= blend2; //set the bone weights to perform skining BoneWeights.SetItem((i * 2) + 0, blend1); BoneWeights.SetItem((i * 2) + 1, blend2); //set the bone ids influencing the vertex. BoneIds.SetItem((i * 2) + 0, bone_id_1); BoneIds.SetItem((i * 2) + 1, bone_id_2); } for (int i = 0; i < corner_count; ++i) { vertex_ids.SetItem(i, corner_ids[i]); } //create a scene mesh spSceneMesh mesh = sdk.CreateSceneMesh(); mesh.SetGeometry(geom); mesh.SetName("mesh"); //get the root node of the scene and add the root_bone and mesh to the scene scene.GetRootNode().AddChild(mesh); scene.GetRootNode().AddChild(root_bone); return(scene); }
static bool run_remeshing_for_lod(ISimplygonSDK sdk, int lod_index, uint merge_distance) { string userProfileDirectory = System.Environment.GetEnvironmentVariable("USERPROFILE"); string assetRoot = userProfileDirectory + @"/Documents/SimplygonSDK/SourceCode/Assets/"; string tempRoot = @"../../../../../temp/"; string output_filename = string.Format(tempRoot + "wall_lod{0}_merge{1}.obj", lod_index + 1, merge_distance); string output_material_filename = string.Format(tempRoot + "wall_lod{0}_merge{1}.mtl", lod_index + 1, merge_distance); string output_diffuse_filename = string.Format(tempRoot + "wall_lod{0}_merge{1}_diffuse.png", lod_index + 1, merge_distance); string output_normals_filename = string.Format(tempRoot + "wall_lod{0}_merge{1}_normals.png", lod_index + 1, merge_distance); // Import source geometry spGeometryData geom; spMaterialTable materials; Console.WriteLine("Importing wavefront .obj file...\n"); { // Run import spWavefrontImporter importer = sdk.CreateWavefrontImporter(); importer.SetExtractGroups(false); // We only want one large geometry, no need to extract groups importer.SetImportFilePath(assetRoot + "wall.obj"); if (!importer.RunImport()) { Console.WriteLine("Could not open input test file"); return(false); } // Get the only geometry and the materials geom = importer.GetFirstGeometry(); materials = importer.GetMaterials(); } // Make a copy of the geometry, we need the original for texture casting later. // The remesher will replace the data of the geometry after it has processed it. spGeometryData red_geom = geom.NewCopy(true); // Create a Scene-object and a SceneMesh-object. // Place the red_geom into the SceneMesh, and then the SceneMesh as a child to the RootNode. spScene scene = sdk.CreateScene(); spSceneMesh mesh = sdk.CreateSceneMesh(); mesh.SetGeometry(red_geom); mesh.SetName(red_geom.GetName().GetText()); scene.GetRootNode().AddChild(mesh); spMappingImage mapping_image; // Remesh it Console.WriteLine("Running remesher...\n"); { spRemeshingProcessor remesher = sdk.CreateRemeshingProcessor(); // Set target on-screen size in pixels remesher.GetRemeshingSettings().SetOnScreenSize(lod_sizes[lod_index]); // Set the on-screen merge distance in pixels. Holes smaller than this will be sealed // and geometries closer to each other than this will be merged. remesher.GetRemeshingSettings().SetMergeDistance(merge_distance); // Disable the cutting plane remesher.GetRemeshingSettings().SetUseGroundPlane(false); // Set to generate mapping image for texture casting. remesher.GetMappingImageSettings().SetGenerateMappingImage(true); remesher.SetSceneRoot(scene.GetRootNode()); remesher.RemeshGeometry(); // Mapping image is needed later on for texture casting. mapping_image = remesher.GetMappingImage(); } spSceneMesh topmesh = Utils.SimplygonCast <spSceneMesh>(scene.GetRootNode().GetChild(0), false); // Cast diffuse texture and normal map data into a new material // Create new material table. spMaterialTable output_materials = sdk.CreateMaterialTable(); // Create new material for the table. spMaterial output_material = sdk.CreateMaterial(); output_materials.AddMaterial(output_material); // Cast diffuse texture data { // Cast the data using a color caster spColorCaster cast = sdk.CreateColorCaster(); cast.SetColorType(SimplygonSDK.SG_MATERIAL_CHANNEL_DIFFUSE); cast.SetSourceMaterials(materials); cast.SetMappingImage(mapping_image); // The mapping image we got from the remeshing process. cast.SetOutputChannels(3); // RGB, 3 channels! (1 would be for grey scale, and 4 would be for RGBA.) cast.SetOutputChannelBitDepth(8); // 8 bits per channel. So in this case we will have 24bit colors RGB. cast.SetDilation(10); // To avoid mip-map artifacts, the empty pixels on the map needs to be filled to a degree aswell. cast.SetOutputFilePath(output_diffuse_filename); // Where the texture map will be saved to file. cast.CastMaterials(); // Fetch! // set the material properties // Set the diffuse multiplier for the texture. 1 means it will not differ from original texture, // For example: 0 would ignore a specified color and 2 would make a color twice as pronounced as the others. output_material.SetDiffuseRed(1); output_material.SetDiffuseGreen(1); output_material.SetDiffuseBlue(1); // Set material to point to created texture filename. output_material.SetTexture(SimplygonSDK.SG_MATERIAL_CHANNEL_DIFFUSE, output_diffuse_filename); } // cast normal map texture data { // cast the data using a color caster spNormalCaster cast = sdk.CreateNormalCaster(); cast.SetSourceMaterials(materials); cast.SetMappingImage(mapping_image); cast.SetOutputChannels(3); // RGB, 3 channels! (But really the x, y and z values for the normal) cast.SetOutputChannelBitDepth(8); cast.SetDilation(10); cast.SetOutputFilePath(output_normals_filename); cast.CastMaterials(); // Set material to point to created texture filename. output_material.SetTexture(SimplygonSDK.SG_MATERIAL_CHANNEL_NORMALS, output_normals_filename); } // export the remeshed geometry to an OBJ file Console.WriteLine("Exporting wavefront .obj file...\n"); { spWavefrontExporter exporter = sdk.CreateWavefrontExporter(); exporter.SetExportFilePath(output_filename); exporter.SetSingleGeometry(topmesh.GetGeometry()); exporter.SetMaterials(output_materials); if (!exporter.RunExport()) { Console.WriteLine("Failed to write result"); return(false); } } return(true); }