public InternalTerrainDetailElementToken(IntRectangle queryArea, TerrainCardinalResolution resolution, TerrainDescriptionElementTypeEnum type, CornersMergeStatus mergeStatus)
 {
     _queryArea   = queryArea;
     _resolution  = resolution;
     _type        = type;
     _mergeStatus = mergeStatus;
 }
예제 #2
0
 public HeightArrayGenerator(TerrainShapeDbProxy terrainShapeDb, TerrainTextureFormatTransformator transformator,
                             TerrainCardinalResolution resolution)
 {
     _terrainShapeDb = terrainShapeDb;
     _transformator  = transformator;
     _resolution     = resolution;
 }
예제 #3
0
        public TerrainHeightArrayWithUvBase RetriveTerrainHeightInfo(MyRectangle queryArea,
                                                                     TerrainCardinalResolution resolution)
        {
            var retrived = _resolutionDbs[resolution].ProvidePartsAt(queryArea).Result;

            return(new TerrainHeightArrayWithUvBase()
            {
                HeightArray = retrived.CoordedPart.Part,
                UvBase = retrived.Uv
            });
        }
예제 #4
0
        public async Task <TextureWithCoords> ApplyFeatureAsync(TextureWithCoords texture,
                                                                TerrainCardinalResolution resolution, bool canMultistep)
        {
            var configuration = _configurations[resolution];

            var detailedHeightmapArray = await TaskUtils
                                         .RunInThreadPool(
                () =>
            {
                var creator      = new DiamondSquareCreator(_randomProviderGenerator.GetRandom());
                var initialArray = creator.CreateDiamondSquareNoiseArray(
                    texture.TextureSize,
                    configuration.DiamondSquareWorkingArrayLength);
                return(initialArray);
            });

            var detailedTexture = await _commonExecutor
                                  .AddAction(() => HeightmapUtils.CreateTextureFromHeightmap(detailedHeightmapArray));


            UniformsPack pack = new UniformsPack();

            pack.SetTexture("_Texture1", texture.Texture);
            pack.SetTexture("_Texture2", detailedTexture);
            pack.SetUniform("_Texture2Weight", configuration.DiamondSquareWeight);

            var renderCoords = new MyRectangle(0, 0, 1, 1);

            var outTextureSize = texture.TextureSize;

            ConventionalTextureInfo outTextureInfo =
                new ConventionalTextureInfo(outTextureSize.X, outTextureSize.Y, TextureFormat.ARGB32, true);
            TextureRenderingTemplate template = new TextureRenderingTemplate()
            {
                CanMultistep        = canMultistep,
                Coords              = renderCoords,
                OutTextureInfo      = outTextureInfo,
                RenderTextureFormat = RenderTextureFormat.RFloat,
                ShaderName          = "Custom/TerrainCreation/DiamondSquareTextureAddingPlain",
                UniformPack         = pack,
                CreateTexture2D     = false
            };

            var renderedTexture = await _rendererProxy.AddOrder(template);

            await _commonExecutor.AddAction(() => GameObject.Destroy(detailedTexture));

            return(new TextureWithCoords(sizedTexture: new TextureWithSize()
            {
                Texture = renderedTexture,
                Size = texture.TextureSize
            }, coords: texture.Coords));
        }
        public async Task Test5() //RetriveSeveralMergedTerrains in Max resolution
        {
            float terrainWidth = 90;
            TerrainCardinalResolution resolution = TerrainCardinalResolution.MAX_RESOLUTION;

            await CreateMergedGriddedTerrain(new IntVector2(10 + 1, 10 + 1), terrainWidth, resolution);

            await CreateMergedGriddedTerrain(new IntVector2(10, 10), terrainWidth, resolution);
            await CreateMergedGriddedTerrain(new IntVector2(11, 10), terrainWidth, resolution);
            await CreateMergedGriddedTerrain(new IntVector2(12, 10), terrainWidth, resolution);

            await CreateMergedGriddedTerrain(new IntVector2(10, 11), terrainWidth, resolution);
            await CreateMergedGriddedTerrain(new IntVector2(12, 11), terrainWidth, resolution);

            await CreateMergedGriddedTerrain(new IntVector2(10, 12), terrainWidth, resolution);
            await CreateMergedGriddedTerrain(new IntVector2(11, 12), terrainWidth, resolution);
            await CreateMergedGriddedTerrain(new IntVector2(12, 12), terrainWidth, resolution);
        }
        public async Task Test4() //RetriveSeveralMergedTerrains in Min resolution
        {
            float terrainWidth = 5760f;
            TerrainCardinalResolution resolution = TerrainCardinalResolution.MIN_RESOLUTION;

            await CreateMergedGriddedTerrain(new IntVector2(1, 1), terrainWidth, resolution);

            await CreateMergedGriddedTerrain(new IntVector2(0, 0), terrainWidth, resolution);
            await CreateMergedGriddedTerrain(new IntVector2(1, 0), terrainWidth, resolution);
            await CreateMergedGriddedTerrain(new IntVector2(2, 0), terrainWidth, resolution);

            await CreateMergedGriddedTerrain(new IntVector2(0, 1), terrainWidth, resolution);
            await CreateMergedGriddedTerrain(new IntVector2(2, 1), terrainWidth, resolution);

            await CreateMergedGriddedTerrain(new IntVector2(0, 2), terrainWidth, resolution);
            await CreateMergedGriddedTerrain(new IntVector2(1, 2), terrainWidth, resolution);
            await CreateMergedGriddedTerrain(new IntVector2(2, 2), terrainWidth, resolution);
        }
예제 #7
0
        public async Task <TextureWithCoords> ApplyFeatureAsync(TextureWithCoords inputTexture,
                                                                TerrainCardinalResolution resolution, bool CanMultistep = false)
        {
            if (!TaskUtils.GetGlobalMultithreading())
            {
                Preconditions.Assert(inputTexture.Texture.width == inputTexture.Texture.height,
                                     "Only square inputTextures are supported");
            }
            UniformsPack pack = new UniformsPack();
            await _commonExecutor.AddAction(() => inputTexture.Texture.filterMode = FilterMode.Point);

            pack.SetTexture("_SourceTexture", inputTexture.Texture);
            pack.SetUniform("_InputGlobalCoords", inputTexture.Coords.ToVector4());
            pack.SetUniform("_QuantingResolution", inputTexture.TextureSize.X - 1);


            var configuration = _configurations[resolution];

            pack.SetUniform("_DetailResolutionMultiplier", configuration.DetailResolutionMultiplier);
            pack.SetUniform("_NoiseStrengthMultiplier", configuration.NoiseStrengthMultiplier);

            var renderCoords = new MyRectangle(0, 0, 1, 1);

            var outTextureSize = inputTexture.TextureSize;

            ConventionalTextureInfo outTextureInfo =
                new ConventionalTextureInfo(outTextureSize.X, outTextureSize.Y, TextureFormat.ARGB32, true);
            TextureRenderingTemplate template = new TextureRenderingTemplate()
            {
                CanMultistep        = false,
                Coords              = renderCoords,
                OutTextureInfo      = outTextureInfo,
                RenderTextureFormat = RenderTextureFormat.RFloat,
                ShaderName          = "Custom/TerrainCreation/NoiseAddingPlain",
                UniformPack         = pack,
                CreateTexture2D     = false
            };

            return(new TextureWithCoords(sizedTexture: new TextureWithSize()
            {
                Texture = await _rendererProxy.AddOrder(template),
                Size = inputTexture.TextureSize
            }, coords: inputTexture.Coords));
        }
        private async Task <UniformsPack> CreateUniformsPack(Ring1Node ring1Node)
        {
            UniformsPack pack = new UniformsPack();


            var terrainOutput = await _terrainShapeDb.Query(new TerrainDescriptionQuery()
            {
                QueryArea = Ring1Node.Ring1Position,
                RequestedElementDetails = new List <TerrainDescriptionQueryElementDetail>()
                {
                    new TerrainDescriptionQueryElementDetail()
                    {
                        //PixelsPerMeter = 10, //todo
                        Resolution = TerrainCardinalResolution.FromRing1NodeLodLevel(Ring1Node.QuadLodLevel),
                        Type       = TerrainDescriptionElementTypeEnum.HEIGHT_ARRAY
                    },
                    new TerrainDescriptionQueryElementDetail()
                    {
                        //PixelsPerMeter = 10, //todo
                        Resolution = TerrainCardinalResolution.FromRing1NodeLodLevel(Ring1Node.QuadLodLevel),
                        Type       = TerrainDescriptionElementTypeEnum.TESSALATION_REQ_ARRAY
                    },
                }
            });

            var uvPosition =
                _coordsCalculator.CalculateUvPosition(Ring1Node.Ring1Position); //_submapTextures.UvPosition;
            var heightmapTexture   = terrainOutput.GetElementOfType(TerrainDescriptionElementTypeEnum.HEIGHT_ARRAY);
            var tessalationTexture =
                terrainOutput.GetElementOfType(TerrainDescriptionElementTypeEnum.TESSALATION_REQ_ARRAY);

            pack.SetUniform("_TerrainTextureUvPositions",
                            new Vector4(uvPosition.X, uvPosition.Y, uvPosition.Width, uvPosition.Height));
            pack.SetTexture("_HeightmapTex", heightmapTexture.TokenizedElement.DetailElement.Texture.Texture);
            pack.SetTexture("_TessalationTex", tessalationTexture.TokenizedElement.DetailElement.Texture.Texture);

            pack.SetTexture("_LodTexture", _visibilityTexture);
            pack.SetUniform("_MaxHeight", 100);
            pack.SetUniform("_LodTextureUvOffset",
                            _coordsCalculator.CalculateTextureUvLodOffset(ring1Node.Ring1Position));
            pack.SetUniform("_BaseTrianglesCount",
                            _coordsCalculator.CalculateGameObjectSize(ring1Node.Ring1Position).X - 1);
            return(pack);
        }
예제 #9
0
 public override Task <TerrainDetailElementOutput> RetriveTerrainDetailAsync(
     TerrainDescriptionElementTypeEnum type, MyRectangle queryArea, TerrainCardinalResolution resolution, RequiredCornersMergeStatus cornersMergeStatus)
 {
     return(TaskUtils.MyFromResult(_mockProvidingFunction(type, queryArea, resolution, cornersMergeStatus)));
 }
예제 #10
0
        private GroundPieceCreationDetails CalculateQueryDetails(int quadLodLevel)
        {
            TerrainCardinalResolution detailResolution = TerrainCardinalResolution.MIN_RESOLUTION;
            int  meshLodPower            = 0;
            bool directNormalCalculation = false;

            if (quadLodLevel == 1)
            {
                detailResolution = TerrainCardinalResolution.MIN_RESOLUTION;
                meshLodPower     = 3;
            }
            else if (quadLodLevel == 2)
            {
                detailResolution = TerrainCardinalResolution.MIN_RESOLUTION;
                meshLodPower     = 3;
            }
            else if (quadLodLevel == 3)
            {
                detailResolution = TerrainCardinalResolution.MIN_RESOLUTION;
                meshLodPower     = 2;
            }
            else if (quadLodLevel == 4)
            {
                detailResolution = TerrainCardinalResolution.MID_RESOLUTION;
                meshLodPower     = 2;
            }
            else if (quadLodLevel == 5)
            {
                detailResolution = TerrainCardinalResolution.MID_RESOLUTION;
                meshLodPower     = 1;
            }
            else if (quadLodLevel == 6)
            {
                detailResolution        = TerrainCardinalResolution.MID_RESOLUTION;
                meshLodPower            = 0;
                directNormalCalculation = true;
            }
            else if (quadLodLevel == 7)
            {
                detailResolution        = TerrainCardinalResolution.MAX_RESOLUTION;
                meshLodPower            = 0;
                directNormalCalculation = true;
            }
            //else if (lodLevel == 8)
            //{
            //    detailResolution = TerrainCardinalResolution.MAX_RESOLUTION;
            //    meshLodPower = 0;
            //}
            else
            {
                Preconditions.Fail("Unsupported lod level: " + quadLodLevel);
            }

            int        baseMeshResolution    = 240;
            int        finalMeshResolution   = Mathf.RoundToInt(baseMeshResolution / Mathf.Pow(2, meshLodPower));
            IntVector2 terrainMeshResolution = new IntVector2(finalMeshResolution + 1, finalMeshResolution + 1);

            var queryElementDetails = new List <TerrainDescriptionQueryElementDetail>()
            {
                new TerrainDescriptionQueryElementDetail()
                {
                    Resolution = detailResolution,
                    Type       = TerrainDescriptionElementTypeEnum.HEIGHT_ARRAY
                },
            };

            if (!directNormalCalculation)
            {
                queryElementDetails.Add(
                    new TerrainDescriptionQueryElementDetail()
                {
                    Resolution = detailResolution,
                    Type       = TerrainDescriptionElementTypeEnum.NORMAL_ARRAY
                }
                    );
            }


            var pack = new UniformsPack();

            pack.SetUniform("_LodLevel", quadLodLevel);
            pack.SetUniform("_HeightmapLodOffset", meshLodPower);

            List <string> keywords = new List <string>();

            if (directNormalCalculation)
            {
                keywords.Add("DYNAMIC_NORMAL_GENERATION");
            }

            return(new GroundPieceCreationDetails()
            {
                KeywordSet = new ShaderKeywordSet(keywords),
                QueryElementDetails = queryElementDetails,
                Pack = pack,
                TerrainMeshResolution = terrainMeshResolution
            });
        }
        private async Task <TokenizedTerrainDetailElement> GenerateElementAsync(
            MyRectangle alignedArea, TerrainCardinalResolution resolution,
            RequiredCornersMergeStatus requiredMerge,
            TerrainDescriptionElementTypeEnum elementType,
            Func <MyRectangle, TerrainCardinalResolution, CornersMergeStatus, Task <TerrainDetailElement> > detailElementGenerator
            )
        {
            CornersMergeStatus statusWeTarget;

            if (requiredMerge == RequiredCornersMergeStatus.NOT_IMPORTANT)
            {
                if (_memoryTerrainCaches[CornersMergeStatus.MERGED][elementType].IsInCache(GenerateInternalToken(alignedArea, resolution, elementType, CornersMergeStatus.MERGED)))
                {
                    statusWeTarget = CornersMergeStatus.MERGED;
                }
                else
                {
                    statusWeTarget = CornersMergeStatus.NOT_MERGED;
                }
            }
            else if (requiredMerge == RequiredCornersMergeStatus.NOT_MERGED)
            {
                statusWeTarget = CornersMergeStatus.NOT_MERGED;
            }
            else
            {
                statusWeTarget = CornersMergeStatus.MERGED;
            }

            if (!_mergingEnabled)
            {
                statusWeTarget = CornersMergeStatus.NOT_MERGED;
            }

            var internalToken = GenerateInternalToken(alignedArea, resolution, elementType, statusWeTarget);
            var queryOutput   = await _memoryTerrainCaches[statusWeTarget][elementType].TryRetriveAsync(internalToken);

            if (queryOutput.Asset != null)
            {
                return(new TokenizedTerrainDetailElement()
                {
                    DetailElement = new TerrainDetailElement()
                    {
                        Texture = queryOutput.Asset,
                        Resolution = resolution,
                        DetailArea = alignedArea,
                        CornersMergeStatus = statusWeTarget
                    },
                    Token = new TerrainDetailElementToken(alignedArea, resolution, elementType, statusWeTarget)
                });
            }
            else
            {
                var detailElement = await detailElementGenerator(alignedArea, resolution, statusWeTarget);

                var   queryOutputCreationObligationToken = queryOutput.CreationObligationToken.Value;
                await _memoryTerrainCaches[statusWeTarget][elementType].AddAssetAsync(
                    queryOutputCreationObligationToken, internalToken, detailElement.Texture);
                return(new TokenizedTerrainDetailElement()
                {
                    DetailElement = new TerrainDetailElement()
                    {
                        Texture = detailElement.Texture,
                        Resolution = resolution,
                        DetailArea = alignedArea,
                        CornersMergeStatus = statusWeTarget
                    },
                    Token = new TerrainDetailElementToken(alignedArea, resolution, elementType, detailElement.CornersMergeStatus)
                });
            }
        }
 public async Task <TokenizedTerrainDetailElement> GenerateHeightDetailElementAsync(MyRectangle alignedArea,
                                                                                    TerrainCardinalResolution resolution, RequiredCornersMergeStatus requiredMerge)
 {
     return(await GenerateElementAsync(alignedArea, resolution, requiredMerge, TerrainDescriptionElementTypeEnum.HEIGHT_ARRAY, _terrainDetailProvider.GenerateHeightDetailElementAsync));
 }
        private async Task CreateMergedGriddedTerrain(IntVector2 gridPosition, float terrainWidth, TerrainCardinalResolution resolution)
        {
            var startPosition = gridPosition * terrainWidth;
            var heightTexture = (await _shapeDb.ShapeDb.QueryAsync(new TerrainDescriptionQuery()
            {
                QueryArea = new MyRectangle(startPosition.x, startPosition.y, terrainWidth, terrainWidth),
                RequestedElementDetails = new List <TerrainDescriptionQueryElementDetail>()
                {
                    new TerrainDescriptionQueryElementDetail()
                    {
                        RequiredMergeStatus = RequiredCornersMergeStatus.MERGED,
                        Resolution = resolution,
                        Type = TerrainDescriptionElementTypeEnum.HEIGHT_ARRAY
                    }
                }
            })).GetElementOfType(TerrainDescriptionElementTypeEnum.HEIGHT_ARRAY).TokenizedElement.DetailElement.Texture.Texture;

            CreateTerrainObject(heightTexture, gridPosition * 90f);
        }
 private InternalTerrainDetailElementToken GenerateInternalToken(
     MyRectangle rect, TerrainCardinalResolution resolution, TerrainDescriptionElementTypeEnum type, CornersMergeStatus mergeStatus)
 {
     return(new InternalTerrainDetailElementToken(GenerateQuantisizedQueryRectangle(rect), resolution, type, mergeStatus));
 }
        public async Task <TextureWithCoords> ApplyFeatureAsync(TextureWithCoords texture,
                                                                TerrainCardinalResolution resolution, bool canMultistep)
        {
            ComputeShaderParametersContainer parametersContainer = new ComputeShaderParametersContainer();
            IntVector2 textureSize = texture.TextureSize;

            var heightComputeBuffer = parametersContainer.AddComputeBufferTemplate(new MyComputeBufferTemplate()
            {
                Count  = textureSize.X * textureSize.Y,
                Stride = 4,
                Type   = ComputeBufferType.Default
            });
            var outRenderTexture = parametersContainer.AddComputeShaderTextureTemplate(
                new MyComputeShaderTextureTemplate()
            {
                Size            = textureSize,
                Depth           = 24,
                EnableReadWrite = true,
                Format          = RenderTextureFormat.RFloat,
                TexWrapMode     = TextureWrapMode.Clamp,
            });

            MultistepComputeShader transferComputeShader =
                new MultistepComputeShader(_computeShaderContainer.HeightTransferShaderPlain, textureSize);
            var textureToBufferKernel = transferComputeShader.AddKernel("CSHeightTransform_InputTextureToBuffer");
            var bufferToTextureKernel = transferComputeShader.AddKernel("CSHeightTransform_BufferToOutputTexture");

            transferComputeShader.SetGlobalUniform("g_sideLength", textureSize.X);

            var inputHeightTexture = parametersContainer.AddExistingComputeShaderTexture(texture.Texture);

            transferComputeShader.SetTexture("InputHeightTexture", inputHeightTexture,
                                             new List <MyKernelHandle>()
            {
                textureToBufferKernel
            });

            transferComputeShader.SetTexture("OutputHeightTexture", outRenderTexture,
                                             new List <MyKernelHandle>()
            {
                bufferToTextureKernel
            });

            transferComputeShader.SetBuffer("HeightBuffer", heightComputeBuffer,
                                            new List <MyKernelHandle>()
            {
                textureToBufferKernel, bufferToTextureKernel
            });
            //////////////////////////////

            MultistepComputeShader thermalErosionComputeShader =
                new MultistepComputeShader(_computeShaderContainer.TweakedThermalErosionShader, textureSize);
            var kernel1 = thermalErosionComputeShader.AddKernel("CSTweakedThermal_Precalculation");
            var kernel2 = thermalErosionComputeShader.AddKernel("CSTweakedThermal_Erosion");

            var configuration = _configurations[resolution];

            thermalErosionComputeShader.SetGlobalUniform("g_tParam", configuration.TParam);
            thermalErosionComputeShader.SetGlobalUniform("g_cParam", configuration.CParam);
            thermalErosionComputeShader.SetGlobalUniform("g_sideLength", textureSize.X);

            thermalErosionComputeShader.SetTexture("InputHeightTexture", inputHeightTexture,
                                                   new List <MyKernelHandle>()
            {
                kernel1
            });

            thermalErosionComputeShader.SetBuffer("HeightBuffer0", heightComputeBuffer,
                                                  new List <MyKernelHandle>()
            {
                kernel1, kernel2
            });

            var MyHeightBuffer1 = parametersContainer.AddComputeBufferTemplate(new MyComputeBufferTemplate()
            {
                Count  = textureSize.X * textureSize.Y,
                Stride = 4,
                Type   = ComputeBufferType.Default
            });

            thermalErosionComputeShader.SetBuffer("HeightBuffer1", MyHeightBuffer1,
                                                  new List <MyKernelHandle>()
            {
                kernel1, kernel2
            });

            var MyMidTextureBuffer = parametersContainer.AddComputeBufferTemplate(new MyComputeBufferTemplate()
            {
                Count  = textureSize.X * textureSize.Y,
                Stride = 4 * 2,
                Type   = ComputeBufferType.Default
            });

            thermalErosionComputeShader.SetBuffer("MidTextureBuffer", MyMidTextureBuffer,
                                                  new List <MyKernelHandle>()
            {
                kernel1, kernel2
            });

            var outParameters = new ComputeBufferRequestedOutParameters(new List <MyComputeShaderTextureId>()
            {
                outRenderTexture
            });
            await _shaderExecutorObject.AddOrder(new ComputeShaderOrder()
            {
                OutParameters       = outParameters,
                ParametersContainer = parametersContainer,
                WorkPacks           = new List <ComputeShaderWorkPack>()
                {
                    new ComputeShaderWorkPack()
                    {
                        Shader        = transferComputeShader,
                        DispatchLoops = new List <ComputeShaderDispatchLoop>()
                        {
                            new ComputeShaderDispatchLoop()
                            {
                                DispatchCount = 1,
                                KernelHandles = new List <MyKernelHandle>()
                                {
                                    textureToBufferKernel
                                }
                            }
                        }
                    },
                    new ComputeShaderWorkPack()
                    {
                        DispatchLoops = new List <ComputeShaderDispatchLoop>()
                        {
                            new ComputeShaderDispatchLoop()
                            {
                                DispatchCount = 30,
                                KernelHandles = new List <MyKernelHandle>()
                                {
                                    kernel1, kernel2
                                }
                            },
                        },
                        Shader = thermalErosionComputeShader
                    },
                    new ComputeShaderWorkPack()
                    {
                        Shader        = transferComputeShader,
                        DispatchLoops = new List <ComputeShaderDispatchLoop>()
                        {
                            new ComputeShaderDispatchLoop()
                            {
                                DispatchCount = 1,
                                KernelHandles = new List <MyKernelHandle>()
                                {
                                    bufferToTextureKernel
                                }
                            }
                        }
                    },
                }
            });

            return(new TextureWithCoords(sizedTexture: new TextureWithSize()
            {
                Texture = outParameters.RetriveTexture(outRenderTexture),
                Size = texture.TextureSize
            }, coords: texture.Coords));
        }
        public async Task <TextureWithCoords> ApplyFeatureAsync(TextureWithCoords texture,
                                                                TerrainCardinalResolution resolution, bool canMultistep)
        {
            ComputeShaderParametersContainer parametersContainer = new ComputeShaderParametersContainer();
            IntVector2 textureSize = texture.TextureSize;

            var heightComputeBuffer = parametersContainer.AddComputeBufferTemplate(new MyComputeBufferTemplate()
            {
                Count  = textureSize.X * textureSize.Y,
                Stride = 4,
                Type   = ComputeBufferType.Default
            });
            var outRenderTexture = parametersContainer.AddComputeShaderTextureTemplate(
                new MyComputeShaderTextureTemplate()
            {
                Depth           = 24,
                EnableReadWrite = true,
                Format          = RenderTextureFormat.RFloat,
                Size            = textureSize,
                TexWrapMode     = TextureWrapMode.Clamp
            });

            MultistepComputeShader transferComputeShader =
                new MultistepComputeShader(_computeShaderContainer.HeightTransferShaderPlain, textureSize);
            var textureToBufferKernel = transferComputeShader.AddKernel("CSHeightTransform_InputTextureToBuffer");
            var bufferToTextureKernel = transferComputeShader.AddKernel("CSHeightTransform_BufferToOutputTexture");

            transferComputeShader.SetGlobalUniform("g_sideLength", textureSize.X);

            var transferInputHeightTexture = parametersContainer.AddExistingComputeShaderTexture(texture.Texture);

            transferComputeShader.SetTexture("InputHeightTexture", transferInputHeightTexture,
                                             new List <MyKernelHandle>()
            {
                textureToBufferKernel
            });

            transferComputeShader.SetTexture("OutputHeightTexture", outRenderTexture,
                                             new List <MyKernelHandle>()
            {
                bufferToTextureKernel
            });

            transferComputeShader.SetBuffer("HeightBuffer", heightComputeBuffer,
                                            new List <MyKernelHandle>()
            {
                textureToBufferKernel, bufferToTextureKernel
            });
            //////////////////////////////

            //var configuration =
            //    new HydraulicEroderConfiguration()
            //    {
            //        StepCount = 20,
            //        kr_ConstantWaterAddition = 0.000002f,  // 0.0001f,
            //        ks_GroundToSedimentFactor = 1f,
            //        ke_WaterEvaporationFactor = 0.05f,
            //        kc_MaxSedimentationFactor = 0.8f,
            //    };
            var configuration = _configurations[resolution];

            MultistepComputeShader computeShader =
                new MultistepComputeShader(_computeShaderContainer.HydraulicErosionShader, textureSize);
            var kernel_water                 = computeShader.AddKernel("CSHydraulicErosion_Water");
            var kernel_erostion              = computeShader.AddKernel("CSHydraulicErosion_Erosion");
            var kernel_deltaSum              = computeShader.AddKernel("CSHydraulicErosion_DeltaSum");
            var kernel_clearDelta            = computeShader.AddKernel("CSHydraulicErosion_ClearDelta");
            var kernel_evaporation           = computeShader.AddKernel("CSHydraulicErosion_Evaporation");
            var kernel_sedimentationToGround = computeShader.AddKernel("CSHydraulicErosion_SedimentationToGround");

            computeShader.SetGlobalUniform("g_sideLength", textureSize.X);
            computeShader.SetGlobalUniform("g_krParam", configuration.kr_ConstantWaterAddition);
            computeShader.SetGlobalUniform("g_ksParam", configuration.ks_GroundToSedimentFactor);
            computeShader.SetGlobalUniform("g_keParam", configuration.ke_WaterEvaporationFactor);
            computeShader.SetGlobalUniform("g_kcParam", configuration.kc_MaxSedimentationFactor);

            var allKernels =
                new List <MyKernelHandle>()
            {
                kernel_water,
                kernel_erostion,
                kernel_deltaSum,
                kernel_clearDelta,
                kernel_evaporation,
                kernel_sedimentationToGround
            };

            computeShader.SetBuffer("HeightMap", heightComputeBuffer,
                                    new List <MyKernelHandle>()
            {
                kernel_water,
                kernel_erostion,
                kernel_evaporation,
                kernel_sedimentationToGround
            });


            var waterMap = parametersContainer.AddComputeBufferTemplate(new MyComputeBufferTemplate()
            {
                Count  = textureSize.X * textureSize.Y,
                Stride = 4,
                Type   = ComputeBufferType.Default
            });

            computeShader.SetBuffer("WaterMap", waterMap,
                                    new List <MyKernelHandle>()
            {
                kernel_water,
                kernel_erostion,
                kernel_deltaSum,
                kernel_evaporation,
            });

            var deltaBuffer = parametersContainer.AddComputeBufferTemplate(new MyComputeBufferTemplate()
            {
                Count  = textureSize.X * textureSize.Y,
                Stride = 4 * 2 * 9,
                Type   = ComputeBufferType.Default
            });

            computeShader.SetBuffer("DeltaBuffer", deltaBuffer,
                                    new List <MyKernelHandle>()
            {
                kernel_erostion,
                kernel_deltaSum,
                kernel_clearDelta
            });

            var sedimentMap = parametersContainer.AddComputeBufferTemplate(new MyComputeBufferTemplate()
            {
                Count  = textureSize.X * textureSize.Y,
                Stride = 4,
                Type   = ComputeBufferType.Default
            });

            computeShader.SetBuffer("SedimentMap", sedimentMap,
                                    new List <MyKernelHandle>()
            {
                kernel_water,
                kernel_erostion,
                kernel_deltaSum,
                kernel_evaporation,
                kernel_sedimentationToGround
            });

            var debugTexture = parametersContainer.AddComputeShaderTextureTemplate(new MyComputeShaderTextureTemplate()
            {
                Depth           = 24,
                EnableReadWrite = true,
                Format          = RenderTextureFormat.ARGB32,
                Size            = textureSize,
                TexWrapMode     = TextureWrapMode.Clamp
            });

            computeShader.SetTexture("DebugTexture", debugTexture,
                                     new List <MyKernelHandle>()
            {
                kernel_water,
                kernel_erostion,
                kernel_deltaSum,
                kernel_clearDelta,
                kernel_evaporation,
                kernel_sedimentationToGround
            });


            var loopedKernels = new List <MyKernelHandle>()
            {
                kernel_water,
                kernel_erostion,
                kernel_deltaSum,
                kernel_clearDelta,
                kernel_evaporation,
            };

            ComputeBufferRequestedOutParameters outParameters = new ComputeBufferRequestedOutParameters(
                new List <MyComputeShaderTextureId>()
            {
                outRenderTexture
            });
            await _shaderExecutorObject.AddOrder(new ComputeShaderOrder()
            {
                ParametersContainer = parametersContainer,
                OutParameters       = outParameters,
                WorkPacks           = new List <ComputeShaderWorkPack>()
                {
                    new ComputeShaderWorkPack()
                    {
                        Shader        = transferComputeShader,
                        DispatchLoops = new List <ComputeShaderDispatchLoop>()
                        {
                            new ComputeShaderDispatchLoop()
                            {
                                DispatchCount = 1,
                                KernelHandles = new List <MyKernelHandle>()
                                {
                                    textureToBufferKernel
                                }
                            }
                        }
                    },
                    new ComputeShaderWorkPack()
                    {
                        DispatchLoops = new List <ComputeShaderDispatchLoop>()
                        {
                            new ComputeShaderDispatchLoop()
                            {
                                DispatchCount = configuration.StepCount,
                                KernelHandles = loopedKernels,
                            },
                            new ComputeShaderDispatchLoop()
                            {
                                DispatchCount = 1,
                                KernelHandles = new List <MyKernelHandle>()
                                {
                                    kernel_sedimentationToGround
                                }
                            }
                        },
                        Shader = computeShader
                    },
                    new ComputeShaderWorkPack()
                    {
                        Shader        = transferComputeShader,
                        DispatchLoops = new List <ComputeShaderDispatchLoop>()
                        {
                            new ComputeShaderDispatchLoop()
                            {
                                DispatchCount = 1,
                                KernelHandles = new List <MyKernelHandle>()
                                {
                                    bufferToTextureKernel
                                }
                            }
                        }
                    },
                }
            });

            return(new TextureWithCoords(sizedTexture: new TextureWithSize()
            {
                Texture = outParameters.RetriveTexture(outRenderTexture),
                Size = texture.TextureSize
            }, coords: texture.Coords));
        }
예제 #17
0
        public async Task <TextureWithSize> MergeHeightDetailCorners(MyRectangle queryArea,
                                                                     TerrainCardinalResolution cardinalResolution, TextureWithSize baseTexture)
        {
            RetriveTerrainDetailProvider();

            var griddedTerrainDetail     = _alignmentCalculator.GetGriddedTerrainArea(queryArea, cardinalResolution);
            var sourceTerrainDetailTasks = new List <TerrainDetailNeighbourhoodDirections>()
            {
                TerrainDetailNeighbourhoodDirections.Left,
                TerrainDetailNeighbourhoodDirections.BottomLeft,
                TerrainDetailNeighbourhoodDirections.Bottom,
            }.Select(direction => new
            {
                direction,
                alignedPosition = _alignmentCalculator.GetAlignedTerrainArea(griddedTerrainDetail + direction.Movement, cardinalResolution)
            })
            .Where(p => _alignmentCalculator.AreaInMap(p.alignedPosition))
            .ToDictionary(
                p => p.direction,
                p => _terrainDetailProvider.RetriveTerrainDetailAsync(
                    TerrainDescriptionElementTypeEnum.HEIGHT_ARRAY, p.alignedPosition, cardinalResolution, RequiredCornersMergeStatus.NOT_IMPORTANT)
                );

            var sourceTerrainDetails = new Dictionary <TerrainDetailNeighbourhoodDirections, TokenizedTerrainDetailElement>();

            foreach (var pair in sourceTerrainDetailTasks)
            {
                sourceTerrainDetails.Add(pair.Key, (await pair.Value).TokenizedElement);
            }

            var activeTerrainDetails = new TerrainDetailElement()
            {
                CornersMergeStatus = CornersMergeStatus.NOT_MERGED,
                DetailArea         = new MyRectangle(0, 0, 1, 1),
                Resolution         = cardinalResolution,
                Texture            = baseTexture
            };

            var outputTexture = await CreateOutputTexture(baseTexture);

            var scratchTextureSize = 121; //todo configurable
            var scratchTexture     = await _textureConciever.ConcieveRenderTextureAsync(new MyRenderTextureTemplate(scratchTextureSize, scratchTextureSize, RenderTextureFormat.RFloat, false, FilterMode.Point));

            var scratchTextureWithSize = new TextureWithSize()
            {
                Texture = scratchTexture,
                Size    = new IntVector2(scratchTextureSize, scratchTextureSize)
            };

            await MergeDetailObject(new Dictionary <TerrainDetailCorner, TerrainDetailElement>()
            {
                { TerrainDetailCorner.BottomLeft, activeTerrainDetails },
            }, baseTexture, outputTexture, TerrainDetailCorner.TopRight, scratchTextureWithSize);

            if (sourceTerrainDetails.ContainsKey(TerrainDetailNeighbourhoodDirections.Left)) // do not merge if one of merging elements was out of map boundaries
            {
                await MergeDetailObject(new Dictionary <TerrainDetailCorner, TerrainDetailElement>()
                {
                    { TerrainDetailCorner.BottomRight, activeTerrainDetails },
                    { TerrainDetailCorner.BottomLeft, sourceTerrainDetails[TerrainDetailNeighbourhoodDirections.Left].DetailElement },
                }, baseTexture, outputTexture, TerrainDetailCorner.TopLeft, scratchTextureWithSize);
            }

            if (sourceTerrainDetails.ContainsKey(TerrainDetailNeighbourhoodDirections.Left) &&
                sourceTerrainDetails.ContainsKey(TerrainDetailNeighbourhoodDirections.BottomLeft) &&
                sourceTerrainDetails.ContainsKey(TerrainDetailNeighbourhoodDirections.Bottom))
            {
                await MergeDetailObject(new Dictionary <TerrainDetailCorner, TerrainDetailElement>()
                {
                    { TerrainDetailCorner.TopRight, activeTerrainDetails },
                    { TerrainDetailCorner.TopLeft, sourceTerrainDetails[TerrainDetailNeighbourhoodDirections.Left].DetailElement },
                    { TerrainDetailCorner.BottomLeft, sourceTerrainDetails[TerrainDetailNeighbourhoodDirections.BottomLeft].DetailElement },
                    { TerrainDetailCorner.BottomRight, sourceTerrainDetails[TerrainDetailNeighbourhoodDirections.Bottom].DetailElement },
                }, baseTexture, outputTexture, TerrainDetailCorner.BottomLeft, scratchTextureWithSize);
            }

            if (sourceTerrainDetails.ContainsKey(TerrainDetailNeighbourhoodDirections.Bottom))
            {
                await MergeDetailObject(new Dictionary <TerrainDetailCorner, TerrainDetailElement>()
                {
                    { TerrainDetailCorner.TopLeft, activeTerrainDetails },
                    { TerrainDetailCorner.BottomLeft, sourceTerrainDetails[TerrainDetailNeighbourhoodDirections.Bottom].DetailElement },
                }, baseTexture, outputTexture, TerrainDetailCorner.BottomRight, scratchTextureWithSize);
            }

            await _commonExecutor.AddAction(() => GameObject.Destroy(scratchTexture));

            await TaskUtils.WhenAll(sourceTerrainDetails.Values.Select(c => c.Token)
                                    .Select(c => _terrainDetailProvider.RemoveTerrainDetailAsync(c)));

            return(outputTexture);
        }
        public async Task <TextureWithCoords> ApplyFeatureAsync(TextureWithCoords texture,
                                                                TerrainCardinalResolution resolution,
                                                                bool canMultistep)
        {
            //IntVector2 textureSize = texture.TextureSize;

            //var heightComputeBuffer = new ComputeBuffer(textureSize.X * textureSize.Y, 4, ComputeBufferType.Default);
            //var outRenderTexture = new RenderTexture(textureSize.X, textureSize.Y, 24, RenderTextureFormat.ARGB32);
            //outRenderTexture.enableRandomWrite = true;
            //outRenderTexture.Create();

            ////MultistepComputeShader transferComputeShader =
            ////    new MultistepComputeShader(_computeShaderContainer.HeightTransferShader, textureSize, 8);
            ////var textureToBufferKernel = transferComputeShader.AddKernel("CSHeightTransform_InputTextureToBuffer");
            ////var bufferToTextureKernel = transferComputeShader.AddKernel("CSHeightTransform_BufferToOutputTexture");
            ////transferComputeShader.SetGlobalUniform("g_sideLength", textureSize.X);

            //var inputHeightArray = HeightmapUtils.CreateHeightmapArrayFromTexture(texture.Texture as Texture2D);
            //var inExtremes = MyArrayUtils.CalculateExtremes(inputHeightArray.HeightmapAsArray);
            //MyArrayUtils.Normalize(inputHeightArray.HeightmapAsArray, inExtremes);
            //MyArrayUtils.Multiply(inputHeightArray.HeightmapAsArray, 800f);

            ////var transferInputHeightTexture = new MyRenderTexture("InputHeightTexture", texture.Texture);
            ////transferComputeShader.SetTexture(transferInputHeightTexture,
            ////    new List<MyKernelHandle>() {textureToBufferKernel});

            ////var transferOutputHeightTexture = new MyRenderTexture("OutputHeightTexture", outRenderTexture);
            ////transferComputeShader.SetTexture(transferOutputHeightTexture,
            ////    new List<MyKernelHandle>() {bufferToTextureKernel});

            ////var transferHeightBuffer = new MyComputeBuffer("HeightBuffer", heightComputeBuffer);
            ////transferComputeShader.SetBuffer(transferHeightBuffer,
            ////    new List<MyKernelHandle>() {textureToBufferKernel, bufferToTextureKernel});
            ////////////////////////////////


            //MultistepComputeShader computeShader =
            //    new MultistepComputeShader(_computeShaderContainer.MeiErosionShader, textureSize, 8);

            //var kernel_bufferInitialization = computeShader.AddKernel("CSMei_InitializeBuffers");
            //var kernel_waterIncrement = computeShader.AddKernel("CSMei_WaterIncrement");
            //var kernel_flowSimulation = computeShader.AddKernel("CSMei_FlowSimulation");
            //var kernel_velocityCalculation = computeShader.AddKernel("CSMei_VelocityCalculation");
            //var kernel_sedimentCalculation = computeShader.AddKernel("CSMei_SedimentCalculation");
            //var kernel_sedimentTransportation = computeShader.AddKernel("CSMei_SedimentTransportation");
            //var kernel_evaporation = computeShader.AddKernel("CSMei_Evaporation");


            //int StepCount = 50;
            //float A_PipeCrossSection = 0.05f;
            //float ConstantWaterAdding = 1f / 64;
            //float GravityAcceleration = 9.81f;
            //float DeltaT = 1f;
            //float DepositionConstant = 0.0001f * 12;
            //float DissolvingConstant = 0.0001f * 12;
            //float EvaporationConstant = 0.05f * 10;
            //Vector2 GridSize = new Vector2(1, 1);
            //float L_PipeLength = 1;
            //float SedimentCapacityConstant = 150;

            //computeShader.SetGlobalUniform("g_sideLength", textureSize.X);
            //computeShader.SetGlobalUniform("deltaT", DeltaT);
            //computeShader.SetGlobalUniform("constantWaterAdding", ConstantWaterAdding);
            //computeShader.SetGlobalUniform("A_pipeCrossSection", A_PipeCrossSection);
            //computeShader.SetGlobalUniform("l_pipeLength", L_PipeLength);
            //computeShader.SetGlobalUniform("g_GravityAcceleration", GravityAcceleration);
            //computeShader.SetGlobalUniform("ks_DissolvingConstant", DissolvingConstant);
            //computeShader.SetGlobalUniform("kd_DepositionConstant", DepositionConstant);
            //computeShader.SetGlobalUniform("ke_EvaporationConstant", EvaporationConstant);
            //computeShader.SetGlobalUniform("kc_SedimentCapacityConstant", SedimentCapacityConstant);
            //computeShader.SetGlobalUniform("gridSideSize", GridSize.x);

            //var allKernels =
            //    new List<MyKernelHandle>()
            //    {
            //        kernel_waterIncrement,
            //        kernel_flowSimulation,
            //        kernel_velocityCalculation,
            //        kernel_sedimentCalculation,
            //        kernel_sedimentTransportation,
            //        kernel_evaporation,
            //        kernel_bufferInitialization
            //    };

            //var heightMap = new MyComputeBuffer("HeightMap", heightComputeBuffer);
            //heightMap.SetData(inputHeightArray.HeightmapAsArray); //TODODODOD
            //computeShader.SetBuffer(heightMap, allKernels);

            //var waterMap = new MyComputeBuffer("WaterMap", textureSize.X * textureSize.Y, 4);
            //computeShader.SetBuffer(waterMap, allKernels);

            //var waterMap1 = new MyComputeBuffer("WaterMap_1", textureSize.X * textureSize.Y, 4);
            //computeShader.SetBuffer(waterMap1, allKernels);

            //var waterMap2 = new MyComputeBuffer("WaterMap_2", textureSize.X * textureSize.Y, 4);
            //computeShader.SetBuffer(waterMap2, allKernels);

            //var fluxMap = new MyComputeBuffer("FluxMap", textureSize.X * textureSize.Y, 4 * 4);
            //computeShader.SetBuffer(fluxMap, allKernels);

            //var velocityMap = new MyComputeBuffer("VelocityMap", textureSize.X * textureSize.Y, 4 * 2);
            //computeShader.SetBuffer(velocityMap, allKernels);

            //var sedimentMap = new MyComputeBuffer("SedimentMap", textureSize.X * textureSize.Y, 4);
            //computeShader.SetBuffer(sedimentMap, allKernels);

            //var sedimentMap1 = new MyComputeBuffer("SedimentMap_1", textureSize.X * textureSize.Y, 4);
            //computeShader.SetBuffer(sedimentMap1, allKernels);

            //var DebugTexture = new MyRenderTexture("DebugTexture",
            //    new RenderTexture(textureSize.X, textureSize.Y, 24, RenderTextureFormat.ARGB32), true);
            //computeShader.SetTexture(DebugTexture, allKernels);

            //var loopedKernels =
            //    new List<MyKernelHandle>()
            //    {
            //        kernel_waterIncrement,
            //        kernel_flowSimulation,
            //        kernel_velocityCalculation,
            //        kernel_sedimentCalculation,
            //        kernel_sedimentTransportation,
            //        kernel_evaporation,
            //    };

            //await _shaderExecutorObject.DispatchComputeShader(new ComputeShaderOrder()
            //{
            //    WorkPacks = new List<ComputeShaderWorkPack>()
            //    {
            //        //new ComputeShaderWorkPack()
            //        //{
            //        //    Shader    = transferComputeShader,
            //        //    DispatchLoops = new List<ComputeShaderDispatchLoop>()
            //        //    {
            //        //        new ComputeShaderDispatchLoop()
            //        //        {
            //        //            DispatchCount = 1,
            //        //            KernelHandles = new List<MyKernelHandle>() {textureToBufferKernel }
            //        //        }
            //        //    }
            //        //},
            //        new ComputeShaderWorkPack()
            //        {
            //            DispatchLoops = new List<ComputeShaderDispatchLoop>()
            //            {
            //                new ComputeShaderDispatchLoop()
            //                {
            //                    DispatchCount = StepCount,
            //                    KernelHandles = loopedKernels,

            //                }
            //            },
            //            Shader = computeShader
            //        },
            //        //new ComputeShaderWorkPack()
            //        //{
            //        //    Shader    = transferComputeShader,
            //        //    DispatchLoops = new List<ComputeShaderDispatchLoop>()
            //        //    {
            //        //        new ComputeShaderDispatchLoop()
            //        //        {
            //        //            DispatchCount = 1,
            //        //            KernelHandles = new List<MyKernelHandle>() {bufferToTextureKernel}
            //        //        }
            //        //    }
            //        //},
            //    }
            //});

            //var outHeightMap = new float[textureSize.X, textureSize.Y];
            //heightMap.GetData(outHeightMap);

            //MyArrayUtils.Multiply(outHeightMap, 1/800f);
            //MyArrayUtils.DeNormalize(outHeightMap, inExtremes);

            //var outTexture = HeightmapUtils.CreateTextureFromHeightmap(new HeightmapArray(outHeightMap));

            //return new TextureWithCoords(sizedTexture: new TextureWithSize()
            //{
            //    Texture = outTexture,
            //    Size = texture.TextureSize
            //},   coords: texture.Coords);
            throw new NotImplementedException(); //todo
        }
예제 #19
0
        public async Task <GRingGroundShapeDetail> ProvideGroundTextureDetail()
        {
            int flatLodLevel = _flatLod.ScalarValue;

            if (!_configuration.SettingPerFlatLod.ContainsKey(flatLodLevel))
            {
                Preconditions.Fail("Unsupported lod level: " + flatLodLevel);
            }
            var setting = _configuration.SettingPerFlatLod[flatLodLevel];

            TerrainCardinalResolution detailResolution = setting.DetailResolution;
            bool directNormalCalculation = setting.DirectNormalComputation;

            var queryElementDetails = new List <TerrainDescriptionQueryElementDetail>()
            {
                new TerrainDescriptionQueryElementDetail()
                {
                    Resolution = detailResolution,
                    Type       = TerrainDescriptionElementTypeEnum.HEIGHT_ARRAY
                },
            };
            //if (!directNormalCalculation) //we have to do it every time , as we need normals for spot updating!
            {
                queryElementDetails.Add(
                    new TerrainDescriptionQueryElementDetail()
                {
                    Resolution = detailResolution,
                    Type       = TerrainDescriptionElementTypeEnum.NORMAL_ARRAY
                }
                    );
            }

            var uniformsPack = new UniformsPack();

            uniformsPack.SetUniform("_LodLevel", flatLodLevel);

            var terrainOutput = await _terrainShapeDb.Query(new TerrainDescriptionQuery()
            {
                QueryArea = _terrainDetailAreaPosition,
                RequestedElementDetails = queryElementDetails
            });

            var heightmapTexture = terrainOutput.GetElementOfType(TerrainDescriptionElementTypeEnum.HEIGHT_ARRAY);

            uniformsPack.SetTexture("_HeightmapTex",
                                    heightmapTexture.TokenizedElement.DetailElement.Texture.Texture);
            uniformsPack.SetUniform("_HeightmapUv", heightmapTexture.UvBase.ToVector4());

            var normalAsTexture = terrainOutput.GetElementOfType(TerrainDescriptionElementTypeEnum.NORMAL_ARRAY);

            if (!directNormalCalculation)
            {
                uniformsPack.SetTexture("_NormalmapTex",
                                        normalAsTexture.TokenizedElement.DetailElement.Texture.Texture);
                uniformsPack.SetUniform("_NormalmapUv", normalAsTexture.UvBase.ToVector4());
            }

            List <string> keywords = new List <string>();

            if (directNormalCalculation)
            {
                keywords.Add("DYNAMIC_NORMAL_GENERATION");
            }

            IGroundShapeToken token = null;

            if (_spotUpdater != null) //todo remove when tests over!
            {
                token = _spotUpdater.AddArea(new GroundShapeInfo()
                {
                    TextureGlobalPosition = _terrainDetailAreaPosition,
                    TextureCoords         = new MyRectangle(heightmapTexture.UvBase),
                    HeightmapResolution   = detailResolution,
                },
                                             new UpdatedTerrainTextures()
                {
                    HeightTexture         = heightmapTexture.TokenizedElement.DetailElement.Texture.Texture,
                    NormalTexture         = normalAsTexture.TokenizedElement.DetailElement.Texture.Texture,
                    TextureGlobalPosition = heightmapTexture.TokenizedElement.DetailElement.DetailArea,
                    TextureCoords         = new MyRectangle(heightmapTexture.UvBase),
                });
            }
            else
            {
                Debug.Log("T333 WARNING. SPOT UPDATER NOT SET. SHOUDL BE USED ONLY IN TESTING");
                token = new DummyGroundShapeToken();
            }

            return(new GRingGroundShapeDetail()
            {
                ShaderKeywordSet = new ShaderKeywordSet(keywords),
                Uniforms = uniformsPack,
                GroundShapeToken = token,
                HeightDetailOutput = heightmapTexture
            });
        }