Buffer(uint blockMetadataSize, uint maxBlockSize, long streamLocation, long opNumber, Guid StreamId) { this._AllocationReportedToGC = maxBlockSize + (uint)KLogicalLogInformation.FixedMetadataSize; AddGCMemoryPressure(this._AllocationReportedToGC); this._MetadataSize = blockMetadataSize; NativeLog.CreateSimpleKIoBuffer((uint)KLogicalLogInformation.FixedMetadataSize, out this._MetadataKIoBuffer); // // Allocate the write KIoBuffer to be the full block size requested by the caller despite the fact that some // data will live in the metadata portion. Consider the fact that when the block is completely full, there will be some // amount of data in the metadata and then the data portion will be full as well except for a gap at the end of the block // which is the size of the data in the metadata portion. When rounding up we will need this last block despite it not being // completely full. // NativeLog.CreateSimpleKIoBuffer((uint)(maxBlockSize), out this._PageAlignedKIoBuffer); NativeLog.CreateEmptyKIoBuffer(out this._CombinedKIoBuffer); this._CombinedKIoBuffer.AddIoBufferReference(this._MetadataKIoBuffer, 0, (uint)KLogicalLogInformation.FixedMetadataSize); this._CombinedKIoBuffer.AddIoBufferReference( this._PageAlignedKIoBuffer, 0, (uint)(maxBlockSize - KLogicalLogInformation.FixedMetadataSize)); this._CombinedBufferStream = new KIoBufferStream(this._CombinedKIoBuffer, (uint)blockMetadataSize); NativeLog.CreateEmptyKIoBuffer(out this._PageAlignedKIoBufferView); unsafe { KLogicalLogInformation.MetadataBlockHeader *mdHdr = null; mdHdr = (KLogicalLogInformation.MetadataBlockHeader *) this._CombinedBufferStream.GetBufferPointer(); this._MetadataBlockHeader = mdHdr; ReleaseAssert.AssertIfNot( this._CombinedBufferStream.Skip((uint)sizeof(KLogicalLogInformation.MetadataBlockHeader)), "Unexpected Skip failure"); this._StreamBlockHeader = (KLogicalLogInformation.StreamBlockHeader *) this._CombinedBufferStream.GetBufferPointer(); mdHdr->OffsetToStreamHeader = this._CombinedBufferStream.GetPosition(); // Position the stream at 1st byte of user record ReleaseAssert.AssertIfNot( this._CombinedBufferStream.Skip((uint)sizeof(KLogicalLogInformation.StreamBlockHeader)), "Unexpected Skip failure"); this._StreamBlockHeader->Signature = KLogicalLogInformation.StreamBlockHeader.Sig; this._StreamBlockHeader->StreamOffsetPlusOne = streamLocation + 1; this._StreamBlockHeader->HighestOperationId = opNumber; this._StreamBlockHeader->StreamId = StreamId; this._StreamBlockHeader->HeaderCRC64 = 0; this._StreamBlockHeader->DataCRC64 = 0; this._StreamBlockHeader->DataSize = 0; this._StreamBlockHeader->Reserved = 0; this._OffsetToData = mdHdr->OffsetToStreamHeader + (uint)sizeof(KLogicalLogInformation.StreamBlockHeader); } }
void ExportTarget() { if (_isExporting) { return; } _isExporting = true; NativeLog.InstallDebugLogCallback(); // why do we need to do this every time? float starttick = Time.realtimeSinceStartup; string exportname = string.IsNullOrEmpty(_exportFileName) ? "export" : Path.GetFileNameWithoutExtension(_exportFileName); string finalSaveFileName = Path.Combine(_exportDirectory, exportname) + (_binaryExport ? ".vsgb" : ".vsga"); if (_exportTarget != null) { GraphBuilder.Export(new GameObject[] { _exportTarget }, finalSaveFileName, _settings); } else { Scene scene = SceneManager.GetActiveScene(); GraphBuilder.Export(scene.GetRootGameObjects(), finalSaveFileName, _settings); } _feedbackText = "Exported in " + (Time.realtimeSinceStartup - starttick) + " seconds"; EditorUtility.SetDirty(this); if (_showPreview) { GraphBuilder.LaunchViewer(finalSaveFileName, _matchSceneCamera, _previewCameras[_cameraSelectionIndex]); // this currently blocks } _isExporting = false; }
/// <summary> /// Create an array of new image data representing the passed texture array /// </summary> /// <param name="texture"></param> /// <returns>ImageData array representing the texture array</returns> public static ImageData[] CreateImageDatas(Texture2DArray texture, bool addToCache = true) { List <ImageData> texdatas = new List <ImageData>(); TextureSupportIssues issues = GetSupportIssuesForTexture(texture); if (issues != TextureSupportIssues.None) { texdatas.Add(CreateImageData(Texture2D.whiteTexture)); NativeLog.WriteLine(GetTextureSupportReport(issues, texture)); return(texdatas.ToArray()); } for (int i = 0; i < texture.depth; i++) { ImageData texdata = new ImageData(); PopulateImageData(texture, i, ref texdata); texdata.id = texture.GetInstanceID() * (i + 1); // hack some kind of id for the texture texdatas.Add(texdata); // add to the cache (double check it doesn't exist already) if (!_imageDataCache.ContainsKey(texdata.id) && addToCache) { _imageDataCache[texdata.id] = texdata; } } return(texdatas.ToArray()); }
/// <summary> /// Create a new image data representing the passed texture /// </summary> /// <param name="texture"></param> /// <returns>ImageData representing the texture</returns> public static ImageData CreateImageData(Texture texture, bool addToCache = true) { ImageData texdata = new ImageData(); TextureSupportIssues issues = GetSupportIssuesForTexture(texture); if ((issues & TextureSupportIssues.Format) == TextureSupportIssues.Format && texture.dimension == TextureDimension.Tex2D) { Texture2D source = texture as Texture2D; RenderTexture rt = RenderTexture.GetTemporary(source.width, source.height, 0, RenderTextureFormat.ARGB32); Graphics.Blit(source, rt); Texture2D converted = new Texture2D(rt.width, rt.height, TextureFormat.RGBA32, false); Graphics.SetRenderTarget(rt); converted.ReadPixels(new Rect(0.0f, 0.0f, rt.width, rt.height), 0, 0, false); converted.Apply(false, false); RenderTexture.ReleaseTemporary(rt); _convertedTextures.Add(converted); texdata = TextureConverter.CreateImageData(converted, false); TextureConverter.AddImageDataToCache(texdata, source.GetInstanceID()); return(texdata); } else if (issues != TextureSupportIssues.None) { texdata = CreateImageData(Texture2D.whiteTexture); NativeLog.WriteLine(GetTextureSupportReport(issues, texture)); return(texdata); } switch (texture.dimension) { case TextureDimension.Tex2D: PopulateImageData(texture as Texture2D, ref texdata); break; case TextureDimension.Tex3D: PopulateImageData(texture as Texture3D, ref texdata); break; default: break; } // add to the cache (double check it doesn't exist already) if (!_imageDataCache.ContainsKey(texdata.id) && addToCache) { _imageDataCache[texdata.id] = texdata; } return(texdata); }
/// <summary> /// Initializes a new instance of the <see cref="WindowsPointerHandler"/> class. /// </summary> /// <param name="addPointer">A function called when a new pointer is detected.</param> /// <param name="updatePointer">A function called when a pointer is moved or its parameter is updated.</param> /// <param name="pressPointer">A function called when a pointer touches the surface.</param> /// <param name="releasePointer">A function called when a pointer is lifted off.</param> /// <param name="removePointer">A function called when a pointer is removed.</param> /// <param name="cancelPointer">A function called when a pointer is cancelled.</param> public WindowsPointerHandler(PointerDelegate addPointer, PointerDelegate updatePointer, PointerDelegate pressPointer, PointerDelegate releasePointer, PointerDelegate removePointer, PointerDelegate cancelPointer) { this.addPointer = addPointer; this.updatePointer = updatePointer; this.pressPointer = pressPointer; this.releasePointer = releasePointer; this.removePointer = removePointer; this.cancelPointer = cancelPointer; nativeLogDelegate = nativeLog; nativePointerDelegate = nativePointer; touchPool = new ObjectPool <TouchPointer>(10, () => new TouchPointer(this), null, resetPointer); hMainWindow = WindowsUtils.GetActiveWindow(); disablePressAndHold(); setScaling(); }
Buffer( uint blockMetadataSize, long startingStreamPosition, NativeLog.IKIoBuffer metadataBuffer, NativeLog.IKIoBuffer pageAlignedKIoBuffer, string traceType) { this._MetadataSize = blockMetadataSize; this._MetadataKIoBuffer = metadataBuffer; this._PageAlignedKIoBuffer = pageAlignedKIoBuffer; unsafe { this._StreamBlockHeader = null; } this._PageAlignedKIoBufferView = null; this._OffsetToData = uint.MaxValue; NativeLog.CreateEmptyKIoBuffer(out this._CombinedKIoBuffer); this.OpenForRead(startingStreamPosition, traceType); }
CreatePhysicalLogStreamBeginWrapper( Guid PhysicalLogStreamId, Guid PhysicalLogStreamTypeId, string OptionalLogStreamAlias, string OptionalPath, FileSecurity OptionalSecurityInfo, Int64 MaximumSize, UInt32 MaximumBlockSize, LogManager.LogCreationFlags CreationFlags, NativeCommon.IFabricAsyncOperationCallback Callback) { NativeLog.IKBuffer secInfo = null; if (OptionalSecurityInfo != null) { var secDesc = OptionalSecurityInfo.GetSecurityDescriptorBinaryForm(); NativeLog.CreateKBuffer((UInt32)secDesc.GetLength(0), out secInfo); } NativeCommon.IFabricAsyncOperationContext context; using (var pin = new PinCollection()) { this._NativeContainer.BeginCreateLogStream( PhysicalLogStreamId, PhysicalLogStreamTypeId, pin.AddBlittable(OptionalLogStreamAlias), // CONSIDER: what about NULL Alias ? pin.AddBlittable(OptionalPath), secInfo, // CONSIDER: does native code need to AddRef() ? MaximumSize, MaximumBlockSize, CreationFlags, Callback, out context); } return(context); }
Memcopy(byte *Src, byte *Dest, UInt32 Length) { // The best observed throughput has been about 2GB/sec or 500ps/byte without calling CopyMemory. Further we // see a native call/return overhead of about 70nsecs/call. This is assuming a memory bandwidth of about 27GB/sec // our a mem-to-mem copy rate of about 13.5GB/sec. This means that it takes about 140 byte transfer to break even // above that and we should call CopyMemory. if (Length > 140) { // At least break even overhead NativeLog.CopyMemory(Src, Dest, Length); return; } // BUG: richhas, xxxxxx, it would be great to have access to a memcpy intrinsic - this // code could just as much damage. // The best observed throughput has been about 2GB/sec or 500ps/byte. This means that it takes about // 140 byte transfer to break even while (Length >= sizeof(UInt64)) { *((UInt64 *)Dest) = *((UInt64 *)Src); Src += sizeof(UInt64); Dest += sizeof(UInt64); if ((Length -= sizeof(UInt64)) == 0) { return; } } while (Length > 0) { *Dest = *Src; Src += 1; Dest += 1; Length--; } }
PhysicalLogManager(LogManager.LoggerType LoggerType) { switch (LoggerType) { case LogManager.LoggerType.Inproc: { NativeLog.CreateLogManagerInproc(out this._NativeManager); _LoggerType = LogManager.LoggerType.Inproc; break; } case LogManager.LoggerType.Driver: { NativeLog.CreateLogManager(out this._NativeManager); _LoggerType = LogManager.LoggerType.Driver; break; } default: { throw new InvalidOperationException("Invalid LogManager.LoggerType"); } } }
private static extern void Init(TOUCH_API api, NativeLog log, NativePointerDelegate pointerDelegate);
OpenForRead(long streamPosition, string traceType) { // Combine the metadata and page-align IoBuffers uint mdBufferSize; uint paBufferSize; this._MetadataKIoBuffer.QuerySize(out mdBufferSize); this._PageAlignedKIoBuffer.QuerySize(out paBufferSize); this._AllocationReportedToGC = mdBufferSize + paBufferSize; AddGCMemoryPressure(this._AllocationReportedToGC); this._CombinedKIoBuffer.Clear(); this._CombinedKIoBuffer.AddIoBufferReference(this._MetadataKIoBuffer, 0, mdBufferSize); this._CombinedKIoBuffer.AddIoBufferReference(this._PageAlignedKIoBuffer, 0, paBufferSize); this._CombinedBufferStream.Reuse(this._CombinedKIoBuffer, this._MetadataSize); // Parse the log stream physical record unsafe { KLogicalLogInformation.MetadataBlockHeader *mdHdr = null; mdHdr = (KLogicalLogInformation.MetadataBlockHeader *) this._CombinedBufferStream.GetBufferPointer(); ReleaseAssert.AssertIfNot( this._CombinedBufferStream.PositionTo(mdHdr->OffsetToStreamHeader), "Unexpected PositionTo failure"); this._StreamBlockHeader = (KLogicalLogInformation.StreamBlockHeader *) this._CombinedBufferStream.GetBufferPointer(); // Position the stream at 1st byte of user record ReleaseAssert.AssertIfNot( this._CombinedBufferStream.Skip((uint)sizeof(KLogicalLogInformation.StreamBlockHeader)), "Unexpected Skip failure"); this._OffsetToData = mdHdr->OffsetToStreamHeader + (uint)sizeof(KLogicalLogInformation.StreamBlockHeader); #if false // TODO: Start: DebugOnly UInt64 savedCrc = _StreamBlockHeader->HeaderCRC64; _StreamBlockHeader->HeaderCRC64 = 0; if (NativeLog.KCrc64(_StreamBlockHeader, (uint)sizeof(KLogicalLogInformation.StreamBlockHeader), 0) != savedCrc) { throw new InvalidDataException(); } _StreamBlockHeader->HeaderCRC64 = 0; // NOTE: Leave HeaderCRC64 0 - this is the unsealed condition if ((_OffsetToData + _StreamBlockHeader->DataSize) > mdBufferSize) { savedCrc = 0; KIoBufferStream.InterationCallback LocalHashFunc = (( byte *ioBufferFragment, ref UInt32 fragmentSize) => { savedCrc = NativeLog.KCrc64(ioBufferFragment, fragmentSize, savedCrc); return(0); }); ReleaseAssert.AssertIfNot( _CombinedBufferStream.Iterate(LocalHashFunc, _StreamBlockHeader->DataSize) == 0, "Unexpected Iterate failure"); if (_StreamBlockHeader->DataCRC64 != savedCrc) { throw new InvalidDataException(); } } // TODO: END: DebugOnly #endif // Compute position and limits of the KIoBufferStream System.Diagnostics.Debug.Assert(this._StreamBlockHeader->StreamOffsetPlusOne > 0); var recordOffsetToDesiredPosition = streamPosition - (this._StreamBlockHeader->StreamOffsetPlusOne - 1); if ((recordOffsetToDesiredPosition < 0) || (recordOffsetToDesiredPosition >= this._StreamBlockHeader->DataSize)) { var s = string.Format( CultureInfo.InvariantCulture, "OpenForRead: streamPosition {0}, StreamOffsetPlusOne {1}, DataSize {2}, recordOffsetToDesiredPosition {3}, HeadTruncationPoint {4}, HighestOperationId {5} ", streamPosition, this._StreamBlockHeader->StreamOffsetPlusOne, this._StreamBlockHeader->DataSize, recordOffsetToDesiredPosition, this._StreamBlockHeader->HeadTruncationPoint, this._StreamBlockHeader->HighestOperationId); AppTrace.TraceSource.WriteInfo( traceType, s ); } System.Diagnostics.Debug.Assert(recordOffsetToDesiredPosition <= uint.MaxValue); this._CombinedBufferStream.Reuse( this._CombinedKIoBuffer, (uint)recordOffsetToDesiredPosition + this._OffsetToData, this._OffsetToData + this._StreamBlockHeader->DataSize); } }
SealForWrite( long currentHeadTruncationPoint, bool IsBarrier, out NativeLog.IKIoBuffer metadataBuffer, out uint metadataSize, out NativeLog.IKIoBuffer pageAlignedBuffer, out long userSizeOfStreamData, out long AsnOfRecord, out long OpOfRecord) { unsafe { uint trimSize = 0; uint dataResidingOutsideMetadata = 0; UInt64 dataCrc = 0; this._MetadataBlockHeader->Flags = IsBarrier ? (uint)KLogicalLogInformation.MetadatBlockHeaderFlags.IsEndOfLogicalRecord : 0; this._StreamBlockHeader->DataSize = this._CombinedBufferStream.GetPosition() - this._OffsetToData; this._StreamBlockHeader->HeadTruncationPoint = currentHeadTruncationPoint; this._PageAlignedKIoBufferView.Clear(); // Compute CRC64 for record data if ((this._OffsetToData < KLogicalLogInformation.FixedMetadataSize) && ((this._OffsetToData + this._StreamBlockHeader->DataSize) <= KLogicalLogInformation.FixedMetadataSize)) { // no data outside the metadata buffer metadataSize = this._OffsetToData + this._StreamBlockHeader->DataSize; } else { // // Compute how much of the metadata is being used. It should be the entire 4K block minus the // space reserved by the physical logger // metadataSize = (uint)KLogicalLogInformation.FixedMetadataSize - this._MetadataSize; ReleaseAssert.AssertIfNot(this._CombinedBufferStream.PositionTo(this._OffsetToData), "Unexpected PositionTo failure"); KIoBufferStream.InterationCallback LocalHashFunc = (( byte *ioBufferFragment, ref UInt32 fragmentSize) => { dataCrc = NativeLog.KCrc64(ioBufferFragment, fragmentSize, dataCrc); return(0); }); ReleaseAssert.AssertIfNot( this._CombinedBufferStream.Iterate(LocalHashFunc, this._StreamBlockHeader->DataSize) == 0, "Unexpected Iterate failure"); // // Compute the number of data blocks that are needed to hold the data that is within the payload // data buffer. This excludes the payload data in the metadata portion // ReleaseAssert.AssertIf(this._OffsetToData > MetadataBlockSize, "Unexpected size for _OffsetToData"); dataResidingOutsideMetadata = this._StreamBlockHeader->DataSize - (MetadataBlockSize - this._OffsetToData); trimSize = ((((dataResidingOutsideMetadata) + (MetadataBlockSize - 1)) / MetadataBlockSize) * MetadataBlockSize); this._PageAlignedKIoBufferView.AddIoBufferReference( this._PageAlignedKIoBuffer, 0, (uint)trimSize); } this._StreamBlockHeader->DataCRC64 = dataCrc; // Now compute block header CRC this._StreamBlockHeader->HeaderCRC64 = NativeLog.KCrc64( this._StreamBlockHeader, (uint)sizeof(KLogicalLogInformation.StreamBlockHeader), 0); // Build results metadataBuffer = this._MetadataKIoBuffer; pageAlignedBuffer = this._PageAlignedKIoBufferView; userSizeOfStreamData = this._StreamBlockHeader->DataSize; AsnOfRecord = this._StreamBlockHeader->StreamOffsetPlusOne; OpOfRecord = this._StreamBlockHeader->HighestOperationId; } }
public static void Export(GameObject[] gameObjects, string saveFileName, ExportSettings settings) { MeshConverter.ClearCaches(); TextureConverter.ClearCaches(); MaterialConverter.ClearCaches(); ShaderMappingIO.ClearCaches(); GraphBuilderInterface.unity2vsg_BeginExport(); List <PipelineData> storePipelines = new List <PipelineData>(); bool insideLODGroup = false; bool firstNodeAdded = false; System.Action <GameObject> processGameObject = null; processGameObject = (GameObject go) => { // determine the gameObject type Transform gotrans = go.transform; bool nodeAdded = false; // does it have a none identiy local matrix if (gotrans.localPosition != Vector3.zero || gotrans.localRotation != Quaternion.identity || gotrans.localScale != Vector3.one) { if (firstNodeAdded || !settings.zeroRootTransform) { // add as a transform TransformData transformdata = TransformConverter.CreateTransformData(gotrans); GraphBuilderInterface.unity2vsg_AddTransformNode(transformdata); nodeAdded = true; } } // do we need to insert a group if (!nodeAdded)// && gotrans.childCount > 0) { //add as a group GraphBuilderInterface.unity2vsg_AddGroupNode(); nodeAdded = true; } firstNodeAdded = true; bool meshexported = false; // get the meshrender here so we can check if the LOD exports the the mesh MeshFilter meshFilter = go.GetComponent <MeshFilter>(); MeshRenderer meshRenderer = go.GetComponent <MeshRenderer>(); // does this node have an LOD group LODGroup lodgroup = go.GetComponent <LODGroup>(); if (lodgroup != null && !insideLODGroup) { // rather than process the children we figure out which renderers are in which children and add them as LOD children LOD[] lods = lodgroup.GetLODs(); if (lods.Length > 0) { // get bounds from first renderer if (lods[0].renderers.Length > 0) { CullData lodCullData = new CullData(); Bounds bounds = new Bounds(lods[0].renderers[0].bounds.center, lods[0].renderers[0].bounds.size); foreach (Renderer boundsrenderer in lods[0].renderers) { if (boundsrenderer != null) { bounds.Encapsulate(boundsrenderer.bounds); } } Vector3 center = bounds.center - gotrans.position; CoordSytemConverter.Convert(ref center); lodCullData.center = NativeUtils.ToNative(center); lodCullData.radius = bounds.size.magnitude * 0.5f; GraphBuilderInterface.unity2vsg_AddLODNode(lodCullData); insideLODGroup = true; for (int i = 0; i < lods.Length; i++) { // for now just support one renderer and assume it's under a seperate child gameObject if (lods[i].renderers.Length == 0) { continue; } LODChildData lodChild = new LODChildData(); lodChild.minimumScreenHeightRatio = lods[i].screenRelativeTransitionHeight; GraphBuilderInterface.unity2vsg_AddLODChild(lodChild); foreach (Renderer lodrenderer in lods[i].renderers) { if (lodrenderer == meshRenderer) { meshexported = true; ExportMesh(meshFilter.sharedMesh, meshRenderer, gotrans, settings, storePipelines); } else if (lodrenderer != null) { // now process the renderers gameobject, it'll be added to the group we just created by adding an LOD child processGameObject(lodrenderer.gameObject); } } GraphBuilderInterface.unity2vsg_EndNode(); } insideLODGroup = false; GraphBuilderInterface.unity2vsg_EndNode(); // end the lod node } } } else { // transverse any children for (int i = 0; i < gotrans.childCount; i++) { processGameObject(gotrans.GetChild(i).gameObject); } } // does it have a mesh if (!meshexported && meshFilter && meshFilter.sharedMesh && meshRenderer) { Mesh mesh = meshFilter.sharedMesh; ExportMesh(mesh, meshRenderer, gotrans, settings, storePipelines); } // does this node have a terrain Terrain terrain = go.GetComponent <Terrain>(); if (terrain != null) { ExportTerrainMesh(terrain, settings, storePipelines); } // if we added a group or transform step out if (nodeAdded) { GraphBuilderInterface.unity2vsg_EndNode(); } }; foreach (GameObject go in gameObjects) { processGameObject(go); } //GraphBuilderInterface.unity2vsg_EndNode(); // step out of convert coord system node GraphBuilderInterface.unity2vsg_EndExport(saveFileName); NativeLog.PrintReport(); }
private static void ExportMesh(Mesh mesh, MeshRenderer meshRenderer, Transform gotrans, ExportSettings settings, List <PipelineData> storePipelines = null) { bool addedCullGroup = false; if (settings.autoAddCullNodes) { CullData culldata = new CullData(); Vector3 center = meshRenderer.bounds.center - gotrans.position; CoordSytemConverter.Convert(ref center); culldata.center = NativeUtils.ToNative(center); culldata.radius = meshRenderer.bounds.size.magnitude * 0.5f; GraphBuilderInterface.unity2vsg_AddCullGroupNode(culldata); addedCullGroup = true; } // Material[] materials = meshRenderer.sharedMaterials; if (mesh != null && mesh.isReadable && mesh.vertexCount > 0 && mesh.GetIndexCount(0) > 0) { int meshid = mesh.GetInstanceID(); MeshInfo meshInfo = MeshConverter.GetOrCreateMeshInfo(mesh); int subMeshCount = mesh.subMeshCount; // shader instance id, Material Data, sub mesh indicies Dictionary <int, Dictionary <MaterialInfo, List <int> > > meshMaterials = new Dictionary <int, Dictionary <MaterialInfo, List <int> > >(); for (int matindex = 0; matindex < materials.Length && matindex < subMeshCount; matindex++) { Material mat = materials[matindex]; if (mat == null) { continue; } MaterialInfo matdata = MaterialConverter.GetOrCreateMaterialData(mat); int matshaderid = matdata.shaderStages.id; if (!meshMaterials.ContainsKey(matshaderid)) { meshMaterials.Add(matshaderid, new Dictionary <MaterialInfo, List <int> >()); } if (!meshMaterials[matshaderid].ContainsKey(matdata)) { meshMaterials[matshaderid].Add(matdata, new List <int>()); } meshMaterials[matshaderid][matdata].Add(matindex); } if (subMeshCount > 1) { // create mesh data, if the mesh has already been created we only need to pass the ID to the addGeometry function foreach (int shaderkey in meshMaterials.Keys) { List <MaterialInfo> mds = new List <MaterialInfo>(meshMaterials[shaderkey].Keys); if (mds.Count == 0) { continue; } // add stategroup and pipeline for shader GraphBuilderInterface.unity2vsg_AddStateGroupNode(); PipelineData pipelineData = NativeUtils.CreatePipelineData(meshInfo); //WE NEED INFO ABOUT THE SHADER SO WE CAN BUILD A PIPLE LINE pipelineData.descriptorBindings = NativeUtils.WrapArray(mds[0].descriptorBindings.ToArray()); pipelineData.shaderStages = mds[0].shaderStages.ToNative(); pipelineData.useAlpha = mds[0].useAlpha; pipelineData.id = NativeUtils.ToNative(NativeUtils.GetIDForPipeline(pipelineData)); storePipelines.Add(pipelineData); if (GraphBuilderInterface.unity2vsg_AddBindGraphicsPipelineCommand(pipelineData, 1) == 1) { GraphBuilderInterface.unity2vsg_AddCommandsNode(); VertexBuffersData vertexBuffersData = MeshConverter.GetOrCreateVertexBuffersData(meshInfo); GraphBuilderInterface.unity2vsg_AddBindVertexBuffersCommand(vertexBuffersData); IndexBufferData indexBufferData = MeshConverter.GetOrCreateIndexBufferData(meshInfo); GraphBuilderInterface.unity2vsg_AddBindIndexBufferCommand(indexBufferData); foreach (MaterialInfo md in mds) { BindDescriptors(md, false); foreach (int submeshIndex in meshMaterials[shaderkey][md]) { DrawIndexedData drawIndexedData = MeshConverter.GetOrCreateDrawIndexedData(meshInfo, submeshIndex); GraphBuilderInterface.unity2vsg_AddDrawIndexedCommand(drawIndexedData); } } GraphBuilderInterface.unity2vsg_EndNode(); // step out of commands node for descriptors and draw indexed commands } GraphBuilderInterface.unity2vsg_EndNode(); // step out of stategroup node for shader } } else { List <int> sids = new List <int>(meshMaterials.Keys); if (sids.Count > 0) { List <MaterialInfo> mds = new List <MaterialInfo>(meshMaterials[sids[0]].Keys); if (mds.Count > 0) { // add stategroup and pipeline for shader GraphBuilderInterface.unity2vsg_AddStateGroupNode(); PipelineData pipelineData = NativeUtils.CreatePipelineData(meshInfo); //WE NEED INFO ABOUT THE SHADER SO WE CAN BUILD A PIPLE LINE pipelineData.descriptorBindings = NativeUtils.WrapArray(mds[0].descriptorBindings.ToArray()); pipelineData.shaderStages = mds[0].shaderStages.ToNative(); pipelineData.useAlpha = mds[0].useAlpha; pipelineData.id = NativeUtils.ToNative(NativeUtils.GetIDForPipeline(pipelineData)); storePipelines.Add(pipelineData); if (GraphBuilderInterface.unity2vsg_AddBindGraphicsPipelineCommand(pipelineData, 1) == 1) { BindDescriptors(mds[0], true); VertexIndexDrawData vertexIndexDrawData = MeshConverter.GetOrCreateVertexIndexDrawData(meshInfo); GraphBuilderInterface.unity2vsg_AddVertexIndexDrawNode(vertexIndexDrawData); GraphBuilderInterface.unity2vsg_EndNode(); // step out of vertex index draw node } GraphBuilderInterface.unity2vsg_EndNode(); // step out of stategroup node } } } } else { string reason = mesh == null ? "mesh is null." : (!mesh.isReadable ? "mesh '" + mesh.name + "' is not readable. Please enabled read/write in the models import settings." : "mesh '" + mesh.name + "' has an unknown error."); NativeLog.WriteLine("ExportMesh: Unable to export mesh for gameobject " + gotrans.gameObject.name + ", " + reason); } if (addedCullGroup) { GraphBuilderInterface.unity2vsg_EndNode(); } }
public static TerrainInfo CreateTerrainInfo(Terrain terrain, GraphBuilder.ExportSettings settings) { TerrainInfo terrainInfo = new TerrainInfo(); bool usingCustomMaterial = false; if (terrain.materialType == Terrain.MaterialType.Custom) { // try and load a shader mapping file to match the custom terrain material terrainInfo.shaderMapping = ShaderMappingIO.ReadFromJsonFile(terrain.materialTemplate.shader); if (terrainInfo.shaderMapping != null) { usingCustomMaterial = true; } } else { // load the default terrain shader mapping file terrainInfo.shaderMapping = ShaderMappingIO.ReadFromJsonFile(ShaderMappingIO.GetPathForShaderMappingFile("DefaultTerrain")); } if (terrainInfo.shaderMapping == null) { // no mapping loaded, use a default shader so we can at least export and render the terrain mesh NativeLog.WriteLine("GraphBuilder: Failed to load Terrain Shader Mapping file for terrain '" + terrain.name + "'."); terrainInfo.shaderMapping = ShaderMappingIO.ReadFromJsonFile(ShaderMappingIO.GetPathForShaderMappingFile("Default")); usingCustomMaterial = true; return(null); } terrainInfo.shaderDefines.Add("VSG_LIGHTING"); // build mesh int samplew = terrain.terrainData.heightmapWidth; int sampleh = terrain.terrainData.heightmapHeight; int cellw = terrain.terrainData.heightmapWidth - 1; int cellh = terrain.terrainData.heightmapHeight - 1; Vector3 size = terrain.terrainData.size; Vector2 cellsize = new Vector3(size.x / cellw, size.z / cellh); Vector2 uvcellsize = new Vector2(1.0f / cellw, 1.0f / cellh); float[,] terrainHeights = terrain.terrainData.GetHeights(0, 0, samplew, sampleh); int vertcount = samplew * sampleh; Vector3[] verts = new Vector3[vertcount]; Vector3[] normals = new Vector3[vertcount]; Vector2[] uvs = new Vector2[vertcount]; int[] indicies = new int[(cellw * cellh) * 6]; // vertices and UVs for (int y = 0; y < samplew; y++) { for (int x = 0; x < sampleh; x++) { verts[y * samplew + x].Set(x * cellsize.x, terrainHeights[y, x] * size.y, y * cellsize.y); normals[y * samplew + x] = terrain.terrainData.GetInterpolatedNormal((float)x / (float)samplew, (float)y / (float)sampleh); uvs[y * samplew + x].Set(x * uvcellsize.x, y * uvcellsize.y); } } CoordSytemConverter.Convert(verts); CoordSytemConverter.Convert(normals); // triangles int index = 0; for (int y = 0; y < cellw; y++) { for (int x = 0; x < cellh; x++) { indicies[index++] = (y * samplew) + x; indicies[index++] = ((y + 1) * samplew) + x; indicies[index++] = (y * samplew) + x + 1; indicies[index++] = ((y + 1) * samplew) + x; indicies[index++] = ((y + 1) * samplew) + x + 1; indicies[index++] = (y * samplew) + x + 1; } } CoordSytemConverter.FlipTriangleFaces(indicies); // convert to meshinfo MeshInfo mesh = null; if (!MeshConverter.GetMeshInfoFromCache(terrain.GetInstanceID(), out mesh)) { mesh = new MeshInfo { id = terrain.GetInstanceID(), verticies = NativeUtils.WrapArray(verts), normals = NativeUtils.WrapArray(normals), uv0 = NativeUtils.WrapArray(uvs), triangles = NativeUtils.WrapArray(indicies), use32BitIndicies = 1 }; MeshConverter.AddMeshInfoToCache(mesh, terrain.GetInstanceID()); } terrainInfo.terrainMesh = mesh; terrainInfo.terrainSize = size; // gather material info if (!usingCustomMaterial) { // use standard terrain layers TerrainLayer[] layers = terrain.terrainData.terrainLayers; for (int i = 0; i < layers.Length; i++) { ImageData layerData = TextureConverter.GetOrCreateImageData(layers[i].diffuseTexture); terrainInfo.diffuseTextureDatas.Add(layerData); terrainInfo.diffuseScales.Add(new Vector4(1.0f / layers[i].tileSize.x, 1.0f / layers[i].tileSize.y)); } for (int i = 0; i < terrain.terrainData.alphamapTextureCount; i++) { Texture2D srcmask = terrain.terrainData.GetAlphamapTexture(i); ImageData splatData = TextureConverter.GetOrCreateImageData(srcmask); terrainInfo.maskTextureDatas.Add(splatData); } if (terrainInfo.diffuseTextureDatas.Count > 0) { terrainInfo.descriptorBindings.Add(new VkDescriptorSetLayoutBinding() { binding = 0, descriptorType = VkDescriptorType.VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, stageFlags = VkShaderStageFlagBits.VK_SHADER_STAGE_FRAGMENT_BIT, descriptorCount = (uint)terrainInfo.diffuseTextureDatas.Count }); terrainInfo.descriptorBindings.Add(new VkDescriptorSetLayoutBinding() { binding = 2, descriptorType = VkDescriptorType.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, stageFlags = VkShaderStageFlagBits.VK_SHADER_STAGE_FRAGMENT_BIT, descriptorCount = (uint)terrainInfo.diffuseScales.Count }); terrainInfo.shaderConsts.Add(terrainInfo.diffuseTextureDatas.Count); terrainInfo.shaderDefines.Add("VSG_TERRAIN_LAYERS"); } terrainInfo.descriptorBindings.Add(new VkDescriptorSetLayoutBinding() { binding = 3, descriptorType = VkDescriptorType.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, stageFlags = VkShaderStageFlagBits.VK_SHADER_STAGE_FRAGMENT_BIT, descriptorCount = 1 }); if (terrainInfo.maskTextureDatas.Count > 0) { terrainInfo.descriptorBindings.Add(new VkDescriptorSetLayoutBinding() { binding = 1, descriptorType = VkDescriptorType.VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, stageFlags = VkShaderStageFlagBits.VK_SHADER_STAGE_FRAGMENT_BIT, descriptorCount = (uint)terrainInfo.maskTextureDatas.Count }); terrainInfo.shaderConsts.Add(terrainInfo.maskTextureDatas.Count); } } else { Material customMaterial = terrain.materialTemplate; terrainInfo.customMaterial = MaterialConverter.CreateMaterialData(customMaterial, terrainInfo.shaderMapping); terrainInfo.customMaterial.customDefines = terrainInfo.shaderDefines; } return(terrainInfo); }