959e80cf72
assets upload description.
354 lines
12 KiB
C#
354 lines
12 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Xml;
|
|
using AwesomeTechnologies.Vegetation;
|
|
using Unity.Burst;
|
|
using Unity.Collections;
|
|
using Unity.Jobs;
|
|
using Unity.Mathematics;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
|
|
|
|
namespace AwesomeTechnologies.VegetationSystem
|
|
{
|
|
// ReSharper disable once InconsistentNaming
|
|
public struct ARGBBytes
|
|
{
|
|
public byte A;
|
|
public byte R;
|
|
public byte G;
|
|
public byte B;
|
|
}
|
|
|
|
// ReSharper disable once InconsistentNaming
|
|
public struct RGBABytes
|
|
{
|
|
public byte A;
|
|
public byte R;
|
|
public byte G;
|
|
public byte B;
|
|
}
|
|
|
|
// [BurstCompile(CompileSynchronously = true)]
|
|
// public struct SplatMapRuleJob : IJob
|
|
// {
|
|
// public NativeList<VegetationInstance> InstanceList;
|
|
// [ReadOnly]
|
|
// public NativeArray<ARGBBytes> SplatMapArray;
|
|
// public float MinValue;
|
|
// public float MaxValue;
|
|
// public int SplatmapIndex;
|
|
// public int Width;
|
|
// public int Height;
|
|
// public float3 TerrainPosition;
|
|
// public float2 SplatCellSize;
|
|
//
|
|
// public void Execute()
|
|
// {
|
|
// int minValue = Mathf.RoundToInt(MinValue * 256);
|
|
// int maxValue = Mathf.RoundToInt(MaxValue * 256);
|
|
//
|
|
// for (int i = 0; i <= InstanceList.Length - 1; i++)
|
|
// {
|
|
// VegetationInstance vegetationInstance = InstanceList[i];
|
|
// float3 localPosition = vegetationInstance.Position - TerrainPosition;
|
|
// int x = math.clamp(Mathf.RoundToInt(localPosition.x / SplatCellSize.x), 0, Width -1);
|
|
// int z = math.clamp(Mathf.RoundToInt(localPosition.z / SplatCellSize.y), 0, Height -1);
|
|
//
|
|
// int value = 0;
|
|
// switch (SplatmapIndex)
|
|
// {
|
|
// case 0:
|
|
// value = SplatMapArray[x + (z * Width)].R;
|
|
// break;
|
|
// case 1:
|
|
// value = SplatMapArray[x + (z * Width)].G;
|
|
// break;
|
|
// case 2:
|
|
// value = SplatMapArray[x + (z * Width)].B;
|
|
// break;
|
|
// case 3:
|
|
// value = SplatMapArray[x + (z * Width)].A;
|
|
// break;
|
|
// }
|
|
// if (value >= minValue && value <= maxValue)
|
|
// {
|
|
// vegetationInstance.TerrainTextureData = 1;
|
|
// }
|
|
// InstanceList[i] = vegetationInstance;
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
[BurstCompile(CompileSynchronously = true)]
|
|
public struct SplatMapRuleJob : IJobParallelForDefer
|
|
{
|
|
[NativeDisableParallelForRestriction] public NativeList<byte> Excluded;
|
|
[NativeDisableParallelForRestriction] public NativeList<byte> TerrainTextureData;
|
|
[NativeDisableParallelForRestriction] public NativeList<float3> Position;
|
|
|
|
[ReadOnly] public NativeArray<ARGBBytes> SplatMapArray;
|
|
public float MinValue;
|
|
public float MaxValue;
|
|
public int SplatmapIndex;
|
|
public int Width;
|
|
public int Height;
|
|
public float3 TerrainPosition;
|
|
public float2 SplatCellSize;
|
|
public bool Include;
|
|
|
|
public void Execute(int index)
|
|
{
|
|
if (Excluded[index] == 1) return;
|
|
|
|
int minValue = Mathf.RoundToInt(MinValue * 256);
|
|
int maxValue = Mathf.RoundToInt(MaxValue * 256);
|
|
|
|
float3 localPosition = Position[index] - TerrainPosition;
|
|
//int x = math.clamp(Mathf.RoundToInt(localPosition.x / SplatCellSize.x), 0, Width - 1);
|
|
//int z = math.clamp(Mathf.RoundToInt(localPosition.z / SplatCellSize.y), 0, Height - 1);
|
|
|
|
|
|
int x = Mathf.RoundToInt(localPosition.x / SplatCellSize.x);
|
|
int z = Mathf.RoundToInt(localPosition.z / SplatCellSize.y);
|
|
if (x < 0 || z < 0 || x > (Width - 1) || z > (Height - 1))
|
|
{
|
|
if (Include)
|
|
{
|
|
TerrainTextureData[index] = 1;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
int value = 0;
|
|
switch (SplatmapIndex)
|
|
{
|
|
case 0:
|
|
value = SplatMapArray[x + (z * Width)].R;
|
|
break;
|
|
case 1:
|
|
value = SplatMapArray[x + (z * Width)].G;
|
|
break;
|
|
case 2:
|
|
value = SplatMapArray[x + (z * Width)].B;
|
|
break;
|
|
case 3:
|
|
value = SplatMapArray[x + (z * Width)].A;
|
|
break;
|
|
}
|
|
|
|
if (value >= minValue && value <= maxValue)
|
|
{
|
|
TerrainTextureData[index] = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// [BurstCompile]
|
|
// public struct SplatMapRuleCompleteJob : IJob
|
|
// {
|
|
// public NativeList<VegetationInstance> InstanceList;
|
|
// public bool Include;
|
|
//
|
|
// public void Execute()
|
|
// {
|
|
// for (int i = InstanceList.Length - 1; i >= 0; i--)
|
|
// {
|
|
// if (Include)
|
|
// {
|
|
// if (InstanceList[i].TerrainTextureData != 1)
|
|
// {
|
|
// InstanceList.RemoveAtSwapBack(i);
|
|
// }
|
|
// else
|
|
// {
|
|
// VegetationInstance vegetationInstance = InstanceList[i];
|
|
// vegetationInstance.TerrainTextureData = 0;
|
|
// InstanceList[i] = vegetationInstance;
|
|
// }
|
|
// }
|
|
// else
|
|
// {
|
|
// if (InstanceList[i].TerrainTextureData == 1)
|
|
// {
|
|
// InstanceList.RemoveAtSwapBack(i);
|
|
// }
|
|
// else
|
|
// {
|
|
// VegetationInstance vegetationInstance = InstanceList[i];
|
|
// vegetationInstance.TerrainTextureData = 0;
|
|
// InstanceList[i] = vegetationInstance;
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
|
|
[BurstCompile]
|
|
public struct SplatMapRuleCompleteJob : IJobParallelForDefer
|
|
{
|
|
[NativeDisableParallelForRestriction] public NativeList<byte> Excluded;
|
|
[NativeDisableParallelForRestriction] public NativeList<byte> TerrainTextureData;
|
|
public bool Include;
|
|
|
|
public void Execute(int index)
|
|
{
|
|
if (Excluded[index] == 1) return;
|
|
|
|
if (Include)
|
|
{
|
|
if (TerrainTextureData[index] != 1)
|
|
{
|
|
Excluded[index] = 1;
|
|
}
|
|
else
|
|
{
|
|
TerrainTextureData[index] = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (TerrainTextureData[index] == 1)
|
|
{
|
|
Excluded[index] = 1;
|
|
}
|
|
else
|
|
{
|
|
TerrainTextureData[index] = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public partial class UnityTerrain
|
|
{
|
|
public Texture2D GetTerrainPreviewTexture(int textureIndex)
|
|
{
|
|
#if UNITY_EDITOR
|
|
#if UNITY_2018_3_OR_NEWER
|
|
if (textureIndex < Terrain.terrainData.terrainLayers.Length)
|
|
{
|
|
return AssetPreview.GetAssetPreview(Terrain.terrainData.terrainLayers[textureIndex].diffuseTexture);
|
|
}
|
|
else
|
|
{
|
|
return null;
|
|
}
|
|
#else
|
|
if (textureIndex < Terrain.terrainData.splatPrototypes.Length)
|
|
{
|
|
return AssetPreview.GetAssetPreview(Terrain.terrainData.splatPrototypes[textureIndex].texture);
|
|
}
|
|
else
|
|
{
|
|
return null;
|
|
}
|
|
#endif
|
|
#else
|
|
return null;
|
|
#endif
|
|
}
|
|
|
|
public void RefreshSplatMaps()
|
|
{
|
|
if (!Terrain || !Terrain.terrainData) return;
|
|
|
|
_splatMapArrayList.Clear();
|
|
_splatMapFormatList.Clear();
|
|
for (int i = 0; i <= Terrain.terrainData.alphamapTextures.Length - 1; i++)
|
|
{
|
|
NativeArray<ARGBBytes> splatmapArray =
|
|
Terrain.terrainData.alphamapTextures[i].GetRawTextureData<ARGBBytes>();
|
|
_splatMapArrayList.Add(splatmapArray);
|
|
|
|
if (Terrain.terrainData.alphamapTextures[i].format == TextureFormat.RGBA32)
|
|
{
|
|
_splatMapFormatList.Add(1);
|
|
}
|
|
else
|
|
{
|
|
_splatMapFormatList.Add(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool IsSplatmapArraysValid()
|
|
{
|
|
for (int i = 0; i <= _splatMapArrayList.Count - 1; i++)
|
|
{
|
|
if (!_splatMapArrayList[i].IsCreated) return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public void VerifySplatmapAccess()
|
|
{
|
|
RefreshSplatMaps();
|
|
}
|
|
|
|
public JobHandle ProcessSplatmapRules(List<TerrainTextureRule> terrainTextureRuleList,
|
|
VegetationInstanceData instanceData, bool include, Rect cellRect, JobHandle dependsOn)
|
|
{
|
|
if (cellRect.Overlaps(_terrainRect))
|
|
{
|
|
if (!IsSplatmapArraysValid()) return dependsOn;
|
|
|
|
int width = Terrain.terrainData.alphamapWidth;
|
|
int height = Terrain.terrainData.alphamapHeight;
|
|
|
|
Vector2 splatCellSize = new Vector2(Terrain.terrainData.size.x / (width - 1),
|
|
Terrain.terrainData.size.z / (height - 1));
|
|
for (int i = 0; i <= terrainTextureRuleList.Count - 1; i++)
|
|
{
|
|
int splatmapIndex = terrainTextureRuleList[i].TextureIndex / 4;
|
|
int localIndex = terrainTextureRuleList[i].TextureIndex - (4 * splatmapIndex);
|
|
|
|
if (splatmapIndex < _splatMapArrayList.Count)
|
|
{
|
|
if (_splatMapFormatList[splatmapIndex] == 1)
|
|
{
|
|
localIndex--;
|
|
if (localIndex == -1) localIndex = 3;
|
|
}
|
|
|
|
SplatMapRuleJob splatMapRuleJob = new SplatMapRuleJob
|
|
{
|
|
Excluded = instanceData.Excluded,
|
|
TerrainTextureData = instanceData.TerrainTextureData,
|
|
Position = instanceData.Position,
|
|
|
|
SplatMapArray = _splatMapArrayList[splatmapIndex],
|
|
MinValue = terrainTextureRuleList[i].MinimumValue,
|
|
MaxValue = terrainTextureRuleList[i].MaximumValue,
|
|
SplatmapIndex = localIndex,
|
|
Width = width,
|
|
Height = height,
|
|
TerrainPosition = TerrainPosition,
|
|
SplatCellSize = splatCellSize,
|
|
Include = include
|
|
};
|
|
dependsOn = splatMapRuleJob.Schedule(instanceData.Excluded, 32, dependsOn);
|
|
}
|
|
}
|
|
|
|
SplatMapRuleCompleteJob splatMapRuleCompleteJob =
|
|
new SplatMapRuleCompleteJob
|
|
{
|
|
Excluded = instanceData.Excluded,
|
|
TerrainTextureData = instanceData.TerrainTextureData,
|
|
|
|
Include = include
|
|
};
|
|
return splatMapRuleCompleteJob.Schedule(instanceData.Excluded, 32, dependsOn);
|
|
}
|
|
|
|
return dependsOn;
|
|
}
|
|
}
|
|
} |