// Returns meshes in meters, in the proper basis, with proper winding static IEnumerable <ModelMesh> GetModelMeshesFromGameObject(GameObject obj, SceneStatePayload payload, bool reverseWinding) { int i = -1; string exportName = obj.name; foreach (MeshData data in VisitMeshes(obj)) { i++; var mesh = data.mesh; for (int sm = 0; sm < mesh.subMeshCount; sm++) { var exportableMaterial = GetMaterialForMeshData(data); // TODO: The geometry pools could be aggregated, for faster downstream rendering. var geo = new GeometryPool(); geo.Layout = exportableMaterial.VertexLayout; geo.Append(mesh, geo.Layout); // Important: This transform should only be applied once, since the pools are shared, and // cannot include any mesh-local transformations. ExportUtils.ConvertToMetersAndChangeBasis(geo, ExportUtils.GetBasisMatrix(payload)); if (reverseWinding) { // Note: this triangle flip intentionally un-does the Unity FBX import flip. ExportUtils.ReverseTriangleWinding(geo, 1, 2); } var objectMesh = new ModelMesh { model = null, // The model is only used for uniquefying the texture names. name = exportName + "_" + i + "_" + sm, id = data.renderer.gameObject.GetInstanceID(), pool = geo, xform = ExportUtils.ChangeBasisNonUniformScale(payload, data.renderer.localToWorldMatrix), exportableMaterial = exportableMaterial, meshIndex = i }; yield return(objectMesh); } } }
// Unused and untested #if false /// Converts the existing payload to the new color space and vector basis. /// Note that scale is never converted and only gamma -> linear is currently supported. public static void ConvertPayload(ColorSpace newColorSpace, Vector3[] newVectorBasis, SceneStatePayload payload) { // We don't handle uninitialized color spaces or linear -> srgb conversions. // This is just not currently part of the export logic, so it's not implemented here. if (newColorSpace == ColorSpace.Uninitialized || payload.colorSpace == ColorSpace.Uninitialized || (payload.colorSpace == ColorSpace.Linear && newColorSpace == ColorSpace.Gamma)) { throw new NotImplementedException(); } if (newColorSpace != payload.colorSpace) { ExportUtils.ConvertToLinearColorspace(payload.env); ExportUtils.ConvertToLinearColorspace(payload.lights); foreach (var group in payload.groups) { ExportUtils.ConvertToLinearColorspace(group.brushMeshes); } ExportUtils.ConvertToLinearColorspace(payload.modelMeshes); } if (newVectorBasis[0] != payload.vectorBasis[0] || newVectorBasis[1] != payload.vectorBasis[1] || newVectorBasis[2] != payload.vectorBasis[2]) { // Never apply a scale change when changing basis. Matrix4x4 basis = ExportUtils.GetBasisMatrix(payload); foreach (var group in payload.groups) { ExportUtils.ChangeBasis(group.brushMeshes, basis); } ExportUtils.ChangeBasis(payload.modelMeshes, basis); ExportUtils.ChangeBasis(payload.referenceImages, basis); ExportUtils.ChangeBasis(payload.referenceModels, basis); } payload.colorSpace = newColorSpace; payload.vectorBasis = newVectorBasis; }
/// Returns a matrix: /// - with units converted by the scale specified in the payload /// - with basis changed by the axis convention in the payload /// - with the scene transform subtracted out (so, converts from room to scene), but /// only if the app is running. /// This version also handles non-uniform scale (but stemming from what? the scene xf?) public static Matrix4x4 ChangeBasisNonUniformScale(SceneStatePayload payload, Matrix4x4 root) { Matrix4x4 basis = ExportUtils.GetBasisMatrix(payload); // Pre- and post-multiplying by the following matrix operations is the equivalent of // .TransformBy(TrTransform.S(payload.exportUnitsFromAppUnits)). Matrix4x4 xfScale = Matrix4x4.Scale(Vector3.one * payload.exportUnitsFromAppUnits); Matrix4x4 xfScaleInverse = Matrix4x4.Scale(Vector3.one / payload.exportUnitsFromAppUnits); if (Application.isPlaying) { // The world to scene matrix here performs the equivalent of App.Scene.AsScene[root] // but works for non-uniform scale. Matrix4x4 worldToSceneMatrix = App.Scene.transform.worldToLocalMatrix; return(xfScale * basis * worldToSceneMatrix * root * basis.inverse * xfScaleInverse); } else { return(xfScale * basis * root * basis.inverse * xfScaleInverse); } }
public static SceneStatePayload GetExportPayloadForGameObject(GameObject gameObject, AxisConvention axes, Environment env) { var payload = new SceneStatePayload(axes); payload.env.skyCubemap = env == null ? null : env.m_RenderSettings.m_SkyboxCubemap; payload.lights = new ExportUtils.LightsPayload(); // unused test code #if TEST_ENVIRONMENTS_WITH_SCENE_LIGHTS { var lights = payload.lights; lights.ambientColor = RenderSettings.ambientLight; #if true // Scene lights from Standard enviroment lights.elements.Add(new ExportUtils.Light { name = "SceneLight0", id = 0, type = LightType.Directional, lightColor = new Color32(198, 208, 253), xform = ExportUtils.ChangeBasisNonUniformScale( payload, Matrix4x4.TRS( new Vector3(0f, 0.21875f, -.545875f), Quaternion.Euler(60, 0, 26), Vector3.one)) }); lights.elements.Add(new ExportUtils.Light { name = "SceneLight1", id = 1, type = LightType.Directional, lightColor = new Color32(109, 107, 88), xform = ExportUtils.ChangeBasisNonUniformScale( payload, Matrix4x4.TRS( new Vector3(0f, 0.21875f, -.545875f), Quaternion.Euler(140, 0, 40), Vector3.one)), }); #else // Scene lights from Dress Form environment lights.elements.Add(new ExportUtils.Light { name = "SceneLight0", id = 0, type = LightType.Directional, lightColor = new Color32(255, 234, 198), xform = ExportUtils.ChangeBasisNonUniformScale( payload, Matrix4x4.TRS( new Vector3(0f, 0.7816665f, -.220875f), Quaternion.Euler(50, 42, 26), Vector3.one)) }); lights.elements.Add(new ExportUtils.Light { name = "SceneLight1", id = 1, type = LightType.Directional, lightColor = new Color32(91, 90, 74), xform = ExportUtils.ChangeBasisNonUniformScale( payload, Matrix4x4.TRS( new Vector3(0f, .636532f, -.6020539f), Quaternion.Euler(140, 47, 40), Vector3.one)), }); #endif } #endif // The determinant can be used to detect if the basis-change has a mirroring. // This matters because a mirroring turns the triangles inside-out, requiring // us to flip their winding to preserve the surface orientation. bool reverseTriangleWinding = (ExportUtils.GetBasisMatrix(payload).determinant < 0); BuildModelMeshesFromGameObject(gameObject, payload, reverseTriangleWinding); return(payload); }