public int RebuildBVH(BVHHandle bvhHandle) { // build baker context m_baker.m_sourcePaths = new string[] { AssetDatabase.GetAssetPath(bvhHandle.SourceMeshData.sharedMesh) }; m_baker.m_guids = new string[] { "" + m_baker.m_meshes[0].GetUniqueId() }; m_baker.m_meshRenderers = new MeshRenderer[] { bvhHandle.SourceMeshData.GetComponent <MeshRenderer>() }; // parse data and fill in missing context BakeContext.BuildSceneContext(new MeshFilter[] { bvhHandle.SourceMeshData }, m_baker); #if DDR_RUNTIME_DLL_LINKING_ int err = Invoke <int, _RebuildBVH>(bvhHandle.Ptr(), m_baker.m_meshIdsPtr, m_baker.m_vertexCountsPtr, m_baker.m_triangleCountPtr , m_baker.m_matDataPtr, m_baker.m_meshDataPtr, m_baker.m_triangleDataPtr, m_baker.m_bakeOptionsPtr, 1, m_baker.m_guids, m_baker.m_sourcePaths); #else int err = _RebuildBVH(bvhHandle.Ptr(), m_baker.m_meshIdsPtr, m_baker.m_vertexCountsPtr, m_baker.m_triangleCountPtr , m_baker.m_matDataPtr, m_baker.m_meshDataPtr, m_baker.m_triangleDataPtr, m_baker.m_bakeOptionsPtr, 1, m_baker.m_guids, m_baker.m_sourcePaths); #endif m_baker.FreeContext(); if (err != 0) { string error = GetLastError(); VertexBakerLib.LogError(error); } return(err); }
public int TessellateTriangles(BVHHandle bvhHandle, Vector3 startPoint, Vector3 endPoint) { m_baker.m_sourcePaths = new string[] { AssetDatabase.GetAssetPath(bvhHandle.SourceMeshData.sharedMesh) }; m_baker.m_guids = new string[] { "" + m_baker.m_meshes[0].GetUniqueId() }; m_baker.m_meshRenderers = new MeshRenderer[] { bvhHandle.SourceMeshData.GetComponent <MeshRenderer>() }; List <MeshFilter> meshes = new List <MeshFilter>() { bvhHandle.SourceMeshData }; m_baker.InitBakeContext(meshes, null); BakeContext.IVertex vertexFormat = new BakeContext.DefaultVertex(); BakeContext.BuildSceneContext(m_baker.m_meshes.ToArray(), m_baker, vertexFormat); int[] outIndex = new int[1]; outIndex[0] = -1; #if DDR_RUNTIME_DLL_LINKING_ bool success = Invoke <bool, _TessellateTriangles>(bvhHandle.Ptr() , m_baker.m_meshIdsPtr , m_baker.m_vertexCountsPtr , m_baker.m_triangleCountPtr , vertexFormat.ElementCount , vertexFormat.Definition.ToArray() , m_baker.m_matDataPtr , m_baker.m_meshDataPtr , m_baker.m_triangleDataPtr , m_baker.m_bakeOptionsPtr , m_baker.m_guids , m_baker.m_sourcePaths , m_baker.m_settingsPtrs); #else bool success = _TessellateTriangles(bvhHandle.Ptr() , m_baker.m_meshIdsPtr , m_baker.m_vertexCountsPtr , m_baker.m_triangleCountPtr , vertexFormat.ElementCount , vertexFormat.Definition.ToArray() , m_baker.m_matDataPtr , m_baker.m_meshDataPtr , m_baker.m_triangleDataPtr , m_baker.m_bakeOptionsPtr , m_baker.m_guids , m_baker.m_sourcePaths , m_baker.m_settingsPtrs); #endif if (!success) { string error = GetLastError(); VertexBakerLib.LogError(error); } return(outIndex[0]); }
public string BuildBVH(MeshFilter[] meshes, ref BVHHandle[] bvhHandles) { m_baker.m_guids = new string[meshes.Length]; m_baker.m_sourcePaths = new string[meshes.Length]; m_baker.m_meshRenderers = new MeshRenderer[meshes.Length]; for (int i = 0; i < meshes.Length; ++i) { m_baker.m_sourcePaths[i] = AssetDatabase.GetAssetPath(meshes[i].sharedMesh); m_baker.m_guids[i] = "" + meshes[i].GetUniqueId(); m_baker.m_meshRenderers[i] = meshes[i].GetComponent <MeshRenderer>(); } m_baker.m_meshCount = meshes.Length; BakeContext.BuildSceneContext(meshes, m_baker); IntPtr[] handles = new IntPtr[meshes.Length]; for (int i = 0; i < handles.Length; ++i) { handles[i] = IntPtr.Zero; } #if DDR_RUNTIME_DLL_LINKING_ string msg = Marshal.PtrToStringAnsi(Invoke <IntPtr, _BuildBVH>(m_baker.m_meshIdsPtr, m_baker.m_vertexCountsPtr, m_baker.m_triangleCountPtr, m_baker.m_matDataPtr , m_baker.m_meshDataPtr, m_baker.m_triangleDataPtr, m_baker.m_bakeOptionsPtr, m_baker.m_meshCount , m_baker.m_guids, m_baker.m_sourcePaths, m_baker.m_settingsIndicesPtr, m_baker.m_settingsPtrs, handles)); #else string msg = Marshal.PtrToStringAnsi(_BuildBVH(m_baker.m_meshIdsPtr, m_baker.m_vertexCountsPtr, m_baker.m_triangleCountPtr, m_baker.m_matDataPtr , m_baker.m_meshDataPtr, m_baker.m_triangleDataPtr, m_baker.m_bakeOptionsPtr, m_baker.m_meshCount , m_baker.m_guids, m_baker.m_sourcePaths, m_baker.m_settingsIndicesPtr, m_baker.m_settingsPtrs, handles)); #endif m_baker.FreeContext(); // output specialized handle bvhHandles = new BVHHandle[handles.Length]; for (int i = 0; i < handles.Length; ++i) { bvhHandles[i] = new BVHHandle(meshes[i], handles[i], this); } return(msg); }
// Prepare sub-mesh data in a flexible way based on vertex definition static void BuildMesh(BakeContext ctx, Mesh mesh, IVertex vertex, List <int> optSubMeshIndices, ref int ptrOffset) { int vertexCount = optSubMeshIndices == null ? mesh.vertices.Length : optSubMeshIndices.Count; var vertElementIter = vertex.Definition.GetEnumerator(); while (vertElementIter.MoveNext()) { VertexElementType elType = vertElementIter.Current.GetElType; VertexElement elDef = vertElementIter.Current; int componentCount = elDef.ComponentCount; // pointer to new data IntPtr dataPtr = new IntPtr(ctx.m_meshDataPtr.ToInt64() + ptrOffset * SIZE_FLOAT); if (elType == VertexElementType.kTangent && mesh.tangents.Length == 0) { // If the data type is kTangent and there is not tangent data, copy UV0 data into the first half of the tangent // data buffer, leave the second half empty. The UV0 data will be used by the baker to generate the tangent data, which // will then be re-written into the tangent buffer. VertexElement uvElement = new VertexElement(VertexElementType.kUV0, 2, SIZE_FLOAT); CopyVectorArrayFromMesh(dataPtr, vertexCount * uvElement.TotalByteSize, vertexCount * uvElement.TotalByteSize, mesh, uvElement); } else if (elType == VertexElementType.kNormal && mesh.normals.Length == 0) { // Do Nothing! // If the data type is kNormal and there is no data skip this step but still increment pointer to leave a 'hole' in the buffer // that he baker can fill with dynamically generated normals. This statement is just here for reader clarity. } else { // if here just copy data of the element size into the dataPtr (the buffer) CopyVectorArrayFromMesh(dataPtr, vertexCount * elDef.TotalByteSize, vertexCount * elDef.TotalByteSize, mesh, elDef, optSubMeshIndices); } // regardless of which 'if-statement' we fall, in always increment the pointer by the full amount ptrOffset += vertexCount * componentCount; } }
// Helper method for marshaling mesh data with sub mesh definition public static void BuildSceneContext(MeshFilter[] meshes, List <List <int> > subMeshIndices, List <List <int> > subMeshTriangleIndices, BakeContext ctx, IVertex vertex = null) { if (vertex == null) { vertex = new DefaultVertex(); } ctx.m_vertexEementCount = vertex.ElementCount; ctx.m_vertexDefinition = vertex.Definition.ToArray(); int totalVertCount = 0; int totalTriCount = 0; int meshCount = meshes.Length; // extract mesh renderer options MeshRenderer[] renderer = ctx.m_meshRenderers; // calculate mesh data size for (int i = 0; i < meshCount; ++i) { // if a sub mesh is defined use it for vert count if (subMeshIndices != null && subMeshIndices[i] != null) { totalVertCount += subMeshIndices[i].Count; } else { totalVertCount += meshes[i].sharedMesh.vertices.Length; } // if a sub mesh is defined use it for triangle index count if (subMeshTriangleIndices != null && subMeshTriangleIndices[i] != null) { totalTriCount += subMeshTriangleIndices[i].Count; } else { totalTriCount += meshes[i].sharedMesh.triangles.Length; } } // data size const int triangleSize = 3; const int matSize = 16; int totalMatrixDataSize = matSize * meshCount * SIZE_FLOAT; // mesh size depends on vertex definition int totalMeshDataSize = totalVertCount * SIZE_FLOAT * (vertex.VertexSize + meshCount); int totalTriangleDataSize = totalTriCount * triangleSize * SIZE_INT; VertexBakerLib instance = VertexBakerLib.Instance; ctx.m_meshIdsPtr = instance.Alloc(meshCount * SIZE_INT); ctx.m_vertexCountsPtr = instance.Alloc(meshCount * SIZE_INT); ctx.m_triangleCountPtr = instance.Alloc(meshCount * SIZE_INT); ctx.m_matDataPtr = instance.Alloc(totalMatrixDataSize); ctx.m_meshDataPtr = instance.Alloc(totalMeshDataSize); ctx.m_triangleDataPtr = instance.Alloc(totalTriangleDataSize); ctx.m_settingsIndicesPtr = instance.Alloc(meshCount * SIZE_INT); ctx.m_bakeOptionsPtr = instance.Alloc(meshCount * SIZE_INT); ctx.m_layerPtr = instance.Alloc(meshCount * SIZE_INT); // temp buffer for matrix float[] matArr = new float[16]; int matDestOffset = 0; int meshDestOffset = 0; int triangleDestOffset = 0; int[] vertexCounts = new int[meshCount]; int[] triangleCounts = new int[meshCount]; int[] ids = new int[meshCount]; uint[] perMeshBakeOpt = new uint[meshCount]; uint[] layerMask = new uint[meshCount]; // data for settings int[] settingsIdx = new int[meshCount]; List <IntPtr> settingsList = new List <IntPtr>(); // global settings int globalSettingsIdx = 0; IntPtr globalSettings = SettingsToIntPtr(BakeData.Instance().GetBakeSettings().SelectedBakeSet); settingsList.Add(globalSettings); for (int m = 0; m < meshCount; ++m) { bool processSubMesh = false; // assume sub mesh if (subMeshIndices != null && subMeshIndices[m] != null && subMeshTriangleIndices != null && subMeshTriangleIndices[m] != null) { processSubMesh = true; } // setup settings settingsIdx[m] = globalSettingsIdx; // check for override settings VertexLightingOverride ovrdSettings = meshes[m].GetComponent <VertexLightingOverride>(); if (ovrdSettings != null) { // point at this overrides index settingsIdx[m] = settingsList.Count; // ensure ambient settings (copy from global which contains the valid ambient settings for now) ovrdSettings.m_bakeSettingsOverride.CopyAmbient(BakeData.Instance().GetBakeSettings().SelectedBakeSet); IntPtr settingsPtr = SettingsToIntPtr(ovrdSettings.m_bakeSettingsOverride); settingsList.Add(settingsPtr); } Mesh mesh = meshes[m].sharedMesh; ids[m] = meshes[m].GetUniqueId(); // layer mask layerMask[m] = (uint)(1 << meshes[m].gameObject.layer); // clear data perMeshBakeOpt[m] = 0; // if mesh has no normals or tangents flag them for generation // should calculate normals if (meshes[m].sharedMesh.normals.Length == 0) { // set bit for normals perMeshBakeOpt[m] |= BakeOptions.kCalcNormals; } // should calculate tangents if (meshes[m].sharedMesh.tangents.Length == 0) { // set bit for tangents perMeshBakeOpt[m] |= BakeOptions.kCalcTangents; } // extract shadowing options from renderer switch (renderer[m].shadowCastingMode) { case UnityEngine.Rendering.ShadowCastingMode.Off: { perMeshBakeOpt[m] |= BakeOptions.kShadowsOff; } break; case UnityEngine.Rendering.ShadowCastingMode.TwoSided: { perMeshBakeOpt[m] |= BakeOptions.kTwoSided; } break; case UnityEngine.Rendering.ShadowCastingMode.On: { perMeshBakeOpt[m] |= BakeOptions.kShadowsOn; } break; case UnityEngine.Rendering.ShadowCastingMode.ShadowsOnly: { perMeshBakeOpt[m] |= BakeOptions.kShadowsOnly; } break; default: break; } if (renderer[m].receiveShadows) { perMeshBakeOpt[m] |= BakeOptions.kReceiveShadow; } else { perMeshBakeOpt[m] &= ~BakeOptions.kReceiveShadow; } // use the list of unique indices of the sub mesh to find the count here unless its null then assume all vertices are being processed int vertexCount = processSubMesh ? subMeshIndices[m].Count : mesh.vertices.Length; // use the list of triangles from the sub mesh to find the count here unless its null then assume all triangles are being processed int triangleCount = processSubMesh ? subMeshTriangleIndices[m].Count : mesh.triangles.Length; vertexCounts[m] = vertexCount; triangleCounts[m] = triangleCount; // copy mesh data into mesh buffer starting with world matrix int matIndex = 0; AssignMat4(ref matArr, meshes[m].transform.localToWorldMatrix, ref matIndex); // 64 bytes IntPtr matDestPtr = new IntPtr(ctx.m_matDataPtr.ToInt64() + matDestOffset * SIZE_FLOAT); Marshal.Copy(matArr, 0, matDestPtr, 16); matDestOffset += 16; if (processSubMesh) { // build sub mesh BuildMesh(ctx, meshes[m].sharedMesh, vertex, subMeshIndices[m], ref meshDestOffset); } else { // build entire mesh BuildMesh(ctx, meshes[m].sharedMesh, vertex, ref meshDestOffset); } // triangles IntPtr indexPtr = new IntPtr(ctx.m_triangleDataPtr.ToInt64() + triangleDestOffset * SIZE_INT); if (processSubMesh) { // copy sub mesh triangle list Marshal.Copy(subMeshTriangleIndices[m].ToArray(), 0, indexPtr, triangleCount); } else { // copy entire triangle list Marshal.Copy(mesh.triangles, 0, indexPtr, triangleCount); } triangleDestOffset += triangleCount; } // copy the mesh into pointer instance.CopyArray(ctx.m_meshIdsPtr, meshCount * SIZE_INT, ids, meshCount * SIZE_INT); instance.CopyArray(ctx.m_vertexCountsPtr, meshCount * SIZE_INT, vertexCounts, meshCount * SIZE_INT); instance.CopyArray(ctx.m_triangleCountPtr, meshCount * SIZE_INT, triangleCounts, meshCount * SIZE_INT); instance.CopyUIntArray(ctx.m_bakeOptionsPtr, meshCount * SIZE_INT, perMeshBakeOpt, meshCount * SIZE_INT); instance.CopyUIntArray(ctx.m_layerPtr, meshCount * SIZE_INT, layerMask, meshCount * SIZE_INT); instance.CopyArray(ctx.m_settingsIndicesPtr, meshCount * SIZE_INT, settingsIdx, meshCount * SIZE_INT); ctx.m_settingsPtrs = settingsList.ToArray(); ctx.m_vertCounts = vertexCounts; }
// Helper method for marshaling mesh data public static void BuildSceneContext(MeshFilter[] meshes, BakeContext ctx, IVertex vertex = null) { BuildSceneContext(meshes, null, null, ctx, vertex); }
static void BuildLightContext(MeshFilter[] meshes, List <Light> lights, BakeContext ctx) { int lightCount = lights.Count; // light data size const int lightPosSize = 3; // padded with extra float const int LightDirSize = 3; // padded with extra float const int lightColorSize = 3; // padded with extra float (don't need alpha) const int lightRIATSize = 4; // range, intensity, angle, type int totalLightSize = lightCount * SIZE_FLOAT * (lightPosSize + LightDirSize + lightColorSize + lightRIATSize); VertexBakerLib instance = VertexBakerLib.Instance; ctx.m_lightsDataPtr = instance.Alloc(totalLightSize); ctx.m_lightsOptPtr = instance.Alloc(lightCount * SIZE_LONG); int lightDestOffset = 0; float[] riat = new float[4]; long[] data = new long[lightCount]; // light layout for (int l = 0; l < lightCount; ++l) { Light light = lights[l]; riat[0] = light.range; riat[1] = light.intensity; riat[2] = light.spotAngle; riat[3] = (float)light.type; // position data IntPtr lightPosPtr = new IntPtr(ctx.m_lightsDataPtr.ToInt64() + lightDestOffset * SIZE_FLOAT); instance.CopyVector4(lightPosPtr, lightPosSize * SIZE_FLOAT, light.transform.position.ToVector4(1f), lightPosSize * SIZE_FLOAT); lightDestOffset += lightPosSize; // direction data IntPtr lightDirPtr = new IntPtr(ctx.m_lightsDataPtr.ToInt64() + lightDestOffset * SIZE_FLOAT); instance.CopyVector4(lightDirPtr, LightDirSize * SIZE_FLOAT, light.transform.forward.ToVector4(0f), LightDirSize * SIZE_FLOAT); lightDestOffset += LightDirSize; // color data IntPtr lightColorPtr = new IntPtr(ctx.m_lightsDataPtr.ToInt64() + lightDestOffset * SIZE_FLOAT); instance.CopyVector4(lightColorPtr, lightColorSize * SIZE_FLOAT, light.color.ToVector4(1f), lightColorSize * SIZE_FLOAT); lightDestOffset += LightDirSize; // IRAT data IntPtr lightIRATPtr = new IntPtr(ctx.m_lightsDataPtr.ToInt64() + lightDestOffset * SIZE_FLOAT); instance.CopyFloatArray(lightIRATPtr, lightRIATSize * SIZE_FLOAT, riat, lightRIATSize * SIZE_FLOAT); lightDestOffset += lightRIATSize; // set lighting options ulong dataValue = 0; // 3 bits dataValue |= (ulong)lights[l].shadows; // 32 bits max dataValue |= (ulong)(((long)lights[l].cullingMask) << 3); data[l] |= (long)dataValue; } Marshal.Copy(data, 0, ctx.m_lightsOptPtr, lightCount); }
// Prepare mesh data in a flexible way based on vertex definition static void BuildMesh(BakeContext ctx, Mesh mesh, IVertex vertex, ref int ptrOffset) { BuildMesh(ctx, mesh, vertex, null, ref ptrOffset); }