

지표면은 어느정도 완성됐는데 바다가 좀 어색한데 이 부분을 개선시켜보자.
바다 색을 지정할 Gradient를 따로 만들어준다.
public Gradient oceanColor;
텍스쳐의 해상도를 2배로 늘려준 다음에 그 절반을 바다를 위해 ColorSettings에 선언해준 oceanColor Gradient를 사용해서 구현한다. textureResolution을 2배 해줬기 때문에 Update Color에서 절반은 oceanColor를 절반은 기존의 biome Gradient Texture를 구현하도록 업데이트한다.
public void UpdateSettings(ColorSettings settings)
{
this.settings = settings;
if (texture == null || texture.height != settings.biomeColorSettings.biomes.Length)
{
texture = new Texture2D(textureResolution*2, settings.biomeColorSettings.biomes.Length, TextureFormat.RGBA32, false);
}
biomeNoiseFilter = NoiseFilterFactory.CreateNoiseFilter(settings.biomeColorSettings.noise);
}
public void UpdateColors()
{
Color[] colors = new Color[textureResolution * texture.height];
int colorIndex = 0;
foreach(var biome in settings.biomeColorSettings.biomes)
{
for (int i = 0; i < textureResolution * 2; i++)
{
Color gradientCol;
if (i < textureResolution)
{
gradientCol = settings.oceanColor.Evaluate(i / (textureResolution - 1f)); ;
}
else
{
gradientCol = biome.gradient.Evaluate((i-textureResolution) / (textureResolution - 1f)); ;
}
Color tintCol = biome.tint;
colors[colorIndex] = gradientCol * (1 - biome.tintPercent) + tintCol * biome.tintPercent;
colorIndex++;
}
}
texture.SetPixels(colors);
texture.Apply();
settings.planetMaterial.SetTexture("_texture", texture);
}
기존에 우리는 매끄러운 바다 표면을 위해 정점의 최소 높이를 지정해서 해당 높이 보다 낮은 정점을 일정한 높이로 끌어올려주어서 바다 표면을 구현했기 때문에 바다의 깊이에 관한 정보는 가지고 있지 않다.
더 이상 최소 높이를 고정하지 않고 바다가 얼마나 깊은지를 알기 위해 UV에 해당 깊이 정보를 저장하도록 해보자. 일단 SimpleNoiseFilter의 Mathf.Max를 지워준다.
// before : noiseValue = Mathf.Max(0, noiseValue - settings.minValue);
noiseValue = noiseValue - settings.minValue;
그 다음 ShapeGenerator의 CalcluationElevation을 아래와 같이 수정한다.
public float CalculateUnscaledElevation(Vector3 pointOnUnitSphere)
{
float firstLayerValue = 0;
float elevation = 0;
if (noiseFilters.Length > 0)
{
firstLayerValue = noiseFilters[0].Evaluate(pointOnUnitSphere);
if (settings.noiseLayers[0].enabled)
{
elevation = firstLayerValue;
}
}
for (int i = 1; i < noiseFilters.Length; i++)
{
if (settings.noiseLayers[i].enabled)
{
float mask = (settings.noiseLayers[i].useFirstLayerAsMask) ? firstLayerValue : 1;
elevation += noiseFilters[i].Evaluate(pointOnUnitSphere) * mask;
}
}
elevationMinMax.AddValue(elevation);
return elevation;
}
public float GetScaledElevation(float unscaledElevation)
{
float elevation = Mathf.Max(0, unscaledElevation);
elevation = settings.planetRadius * (1 + elevation);
return elevation;
}
이렇게 코드를 업데이트하면 float 형식의 unscaledElevation을 구한 후에 scaled(Mathf.Max) 작업을 따로 해주기 때문에 높이를 조정하기 전의 표면의 높이, 즉 깊이 정보를 가질 수 있게된다.
즉, 기존에는 바로 Mathf.Max 작업으로 높이를 고정시켜서 바다를 만들었다면 이제 scaled 하지 않고 높이를 구한 후에 그 다음 scaled 하는 작업을 두 함수로 구분하면서 중간에 scaled 하지 않은 기존의 높이를 얻을 수 있게 된다.
Vector2[] uv = (mesh.uv.Length == vertices.Length) ? mesh.uv : new Vector2[vertices.Length];
for (int y = 0; y < resolution; y++)
{
for (int x = 0; x < resolution; x++)
{
int i = x + y * resolution;
Vector2 percent = new Vector2(x, y) / (resolution - 1);
Vector3 pointOnUnitCube = localUp + (percent.x - .5f) * 2 * axisA + (percent.y - .5f) * 2 * axisB;
Vector3 pointOnUnitSphere = pointOnUnitCube.normalized;
float unscaledElevation = shapeGenerator.CalculateUnscaledElevation(pointOnUnitSphere);
vertices[i] = pointOnUnitSphere * shapeGenerator.GetScaledElevation(unscaledElevation);
uv[i].y = unscaledElevation;
if (x != resolution - 1 && y != resolution - 1)
{
triangles[triIndex] = i;
triangles[triIndex + 1] = i + resolution + 1;
triangles[triIndex + 2] = i + resolution;
triangles[triIndex + 3] = i;
triangles[triIndex + 4] = i + 1;
triangles[triIndex + 5] = i + resolution + 1;
triIndex += 6;
}
}
}
이제 Shader를 아래와 같이 수정해준다.


이제 이렇게 바뀌는데 oceanGradient를 따로 설정해줬기 때문에 기존 Color Gradient에서 ocean Color를 다 제거해준다.

이제 ocean Gradient를 적절히 조절해주면 깊이에 따른 바다 색을 이렇게 구현할 수 있어 실제 지구와 같은 모습으로 바뀌는 것을 확인할 수 있다.