public VirtualTextureLoader(string pathName, ComputeShader terrainEditShader, int terrainMaskCount, long resolution, bool is16Bit, MTerrainLoadingThread loadingThread) { this.loadingThread = loadingThread; if (is16Bit) { readPass = 4; writePass = 5; bitLength = 2; } else { bitLength = 1; readPass = 2; writePass = 3; } this.resolution = resolution; size = resolution * resolution * bitLength; this.terrainMaskCount = terrainMaskCount; fileReadBuffer = new byte[size]; maskLoader = new FileStream(pathName, FileMode.OpenOrCreate, FileAccess.ReadWrite); loadingCommandQueue = new NativeQueue <MaskBuffer>(100, Allocator.Persistent); this.terrainEditShader = terrainEditShader; readWriteBuffer = new ComputeBuffer((int)(size / sizeof(uint)), sizeof(uint)); loadingThreadExecutor = () => { MaskBuffer mb; while (loadingCommandQueue.TryDequeue(out mb)) { maskLoader.Position = mb.offset; maskLoader.Read(fileReadBuffer, 0, (int)size); UnsafeUtility.MemCpy(mb.bytesData, fileReadBuffer.Ptr(), size); *mb.isFinished = true; } }; }
public VirtualTextureLoader(int initialMipCount, int mipLevel, string path, object lockerObj) { enabled = true; this.initialMipCount = initialMipCount; handlerQueue = new NativeQueue <LoadingHandler>(100, Allocator.Persistent); this.lockerObj = lockerObj; this.mipLevel = mipLevel; resetEvent = new AutoResetEvent(true); bufferBytes = new byte[CHUNK_SIZE]; streamPositionOffset = GetStreamingPositionOffset(initialMipCount, mipLevel); streamer = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, (int)CHUNK_SIZE); loadingThread = new Thread(() => { while (enabled) { while (true) { LoadingHandler handler; lock (lockerObj) { if (!handlerQueue.TryDequeue(out handler)) { break; } } try { streamer.Position = CHUNK_SIZE * ((long)(0.1 + pow(2.0, handler.mipLevel)) * handler.position.y + handler.position.x + streamPositionOffset[handler.mipLevel - initialMipCount]); streamer.Read(bufferBytes, 0, (int)CHUNK_SIZE); UnsafeUtility.MemCpy(handler.allBytes, bufferBytes.Ptr(), CHUNK_SIZE); } finally { *handler.isComplete = true; } } resetEvent.WaitOne(); } }); loadingThread.Start(); }
private IEnumerator Loader() { while (enabled) { LoadCommand cmd; if (allLoadingCommand.TryDequeue(out cmd)) { switch (cmd.ope) { case LoadCommand.Operator.Combine: childrenList.Clear(); if (allGPURPScene[cmd.leftDownSon]) { childrenList.Add(allGPURPScene[cmd.leftDownSon]); } if (allGPURPScene[cmd.leftUpSon]) { childrenList.Add(allGPURPScene[cmd.leftUpSon]); } if (allGPURPScene[cmd.rightDownSon]) { childrenList.Add(allGPURPScene[cmd.rightDownSon]); } if (allGPURPScene[cmd.rightUpSon]) { childrenList.Add(allGPURPScene[cmd.rightUpSon]); } yield return(SceneStreaming.Combine(allGPURPScene[cmd.parent], childrenList)); break; case LoadCommand.Operator.Disable: yield return(allGPURPScene[cmd.parent].Delete()); break; case LoadCommand.Operator.Enable: yield return(allGPURPScene[cmd.parent].Generate()); break; case LoadCommand.Operator.Separate: childrenList.Clear(); if (allGPURPScene[cmd.leftDownSon]) { childrenList.Add(allGPURPScene[cmd.leftDownSon]); } if (allGPURPScene[cmd.leftUpSon]) { childrenList.Add(allGPURPScene[cmd.leftUpSon]); } if (allGPURPScene[cmd.rightDownSon]) { childrenList.Add(allGPURPScene[cmd.rightDownSon]); } if (allGPURPScene[cmd.rightUpSon]) { childrenList.Add(allGPURPScene[cmd.rightUpSon]); } yield return(SceneStreaming.Separate(allGPURPScene[cmd.parent], childrenList)); break; } } else { yield return(null); } } }
void OnFinishRead(AsyncGPUReadbackRequest request) { bool useConnection = false; commandQueue.TryDequeue(out useConnection); float depth = request.GetData <float>().Element(0); float4x4 invvp = (GL.GetGPUProjectionMatrix(cam.projectionMatrix, false) * cam.worldToCameraMatrix).inverse; float4 worldPos = mul(invvp, float4(uv * 2 - 1, depth, 1)); worldPos.xyz /= worldPos.w; MTerrain terrain = MTerrain.current; if (!terrain) { return; } NativeList <ulong> allMaskTree = new NativeList <ulong>(5, Allocator.Temp); value = Mathf.Clamp(value, 0, terrain.terrainData.allMaterials.Length - 1); terrain.treeRoot->GetMaterialMaskRoot(worldPos.xz, paintRange, ref allMaskTree); terrainEditShader.SetInt(ShaderIDs._Count, MTerrain.MASK_RESOLUTION); if (!useConnection) { //TODO terrainEditShader.SetVector("_Circle0", float4(worldPos.xz, paintRange, 1)); terrainEditShader.SetVector("_Circle1", float4(worldPos.xz, paintRange, 1)); terrainEditShader.SetMatrix("_QuadMatrix", float4x4(0)); } else { terrain.treeRoot->GetMaterialMaskRoot(lastFrameWorldPos.xz, paintRange, ref allMaskTree); float2 moveDir = lastFrameWorldPos.xz - worldPos.xz; float len = length(moveDir); moveDir /= len; float dotMove = dot(moveDir, moveDir); float2 verticleDir = float2(-moveDir.y / dotMove, moveDir.x / dotMove); float3x3 localToWorld = float3x3(float3(moveDir * len, 0), float3(verticleDir * paintRange * 2, 0), float3((lastFrameWorldPos.xz + worldPos.xz) * 0.5f, 1)); float3x3 worldToLocal = inverse(localToWorld); terrainEditShader.SetVector("_Circle0", float4(worldPos.xz, paintRange, 1)); terrainEditShader.SetVector("_Circle1", float4(lastFrameWorldPos.xz, paintRange, 1)); terrainEditShader.SetMatrix("_QuadMatrix", float4x4(float4(worldToLocal.c0, 0), float4(worldToLocal.c1, 0), float4(worldToLocal.c2, 0), 0)); } const int disp = MTerrain.MASK_RESOLUTION / 8; foreach (var i in allMaskTree) { var treeNodePtr = (TerrainQuadTree *)i; if (treeNodePtr == null) { continue; } int2 maskPos = treeNodePtr->rootPos + (int2)treeNodePtr->maskScaleOffset.yz; int texIndex = terrain.maskVT.GetChunkIndex(maskPos); if (texIndex < 0) { continue; } terrainEditShader.SetVector("_SrcDestCorner", (float4)treeNodePtr->BoundedWorldPos); terrainEditShader.SetInt(ShaderIDs._OffsetIndex, texIndex); PaintMask(terrain, treeNodePtr, texIndex, disp); } if (!useConnection) { terrain.treeRoot->UpdateChunks(double3(worldPos.xz, paintRange)); } else { terrain.treeRoot->UpdateChunks(double3(0.5f * (worldPos.xz + lastFrameWorldPos.xz), 0.5f * distance(worldPos.xz, lastFrameWorldPos.xz) + paintRange)); } lastFrameWorldPos = worldPos.xyz; }