Created
August 15, 2018 21:05
-
-
Save Towkin/68ab57ea9aa2130d32c57f0918653ac1 to your computer and use it in GitHub Desktop.
A simple terrain generator shader. You need to get a simplex noise shader from https://github.com/keijiro/NoiseShader that fits your platform, by default this is intended for HLSL.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Shader "Custom/GeneratedTerrainShader" { | |
CGINCLUDE | |
#include "Tessellation.cginc" | |
#include "HLSL/SimplexNoise3D.hlsl" | |
ENDCG | |
Properties { | |
_Tess("Tessellation", Range(1,128)) = 4 | |
_HeightOctaves("Height Octaves", Range(1, 16)) = 8 | |
_HeightFrequency("Height Base Frequency", Range(0, 1.0)) = 0.01 | |
_HeightLacunarity("Height Smoothness", Range(0.0, 10.0)) = 2.0 | |
_HeightScalar("Height Scalar", Range(0.0, 10.0)) = 1.5 | |
_HumidityOctaves("Humidity Octaves", Range(1, 16)) = 4 | |
_HumidityFrequency("Humidity Base Frequency", Range(0, 1.0)) = 0.02 | |
_HumidityLacunarity("Humidity Smoothness", Range(0.0, 10.0)) = 2.0 | |
_HumidityScalar("Humidity Scalar", Range(0.0, 10.0)) = 1.5 | |
_Color ("Color", Color) = (1,1,1,1) | |
_Displacement("Displacement", Range(0, 1.0)) = 0.3 | |
_OffsetY("Offset Y Axis", float) = 0.0 | |
_MainTex ("Albedo (RGB)", 2D) = "white" {} | |
_Glossiness ("Smoothness", Range(0,1)) = 0.5 | |
_Metallic ("Metallic", Range(0,1)) = 0.0 | |
} | |
SubShader { | |
Tags { "RenderType"="Opaque" } | |
LOD 200 | |
CGPROGRAM | |
// Physically based Standard lighting model, and enable shadows on all light types | |
#pragma surface surf Standard fullforwardshadows vertex:vert tessellate:tessDistance tessphong:0.5 | |
#pragma target 4.6 | |
struct appdata { | |
float4 vertex : POSITION; | |
float3 normal : NORMAL; | |
float4 color : COLOR; | |
}; | |
struct Input { | |
float4 color : COLOR; | |
}; | |
float | |
_Tess; | |
// Unity standard simple edge length based tesselation. | |
float4 tessDistance(appdata v0, appdata v1, appdata v2) { | |
return UnityEdgeLengthBasedTess(v0.vertex, v1.vertex, v2.vertex, _Tess); | |
} | |
float | |
_Displacement, | |
_OffsetY; | |
int _HeightOctaves, | |
_HumidityOctaves; | |
float | |
_HeightFrequency, | |
_HumidityFrequency; | |
float | |
_HeightScalar, | |
_HumidityScalar; | |
float | |
_HeightLacunarity, | |
_HumidityLacunarity; | |
void vert(inout appdata v) { | |
float3 worldPos = float3(0, _OffsetY, 0) + mul(unity_ObjectToWorld, v.vertex).xyz; | |
float | |
humidity = 0.0, | |
weight = 1.0, | |
totalWeight = 0.0; | |
float4 heightGrad = float4(0.0, 0.0, 0.0, 0.0); | |
for (int heightIndex = 0; heightIndex < _HeightOctaves; heightIndex++) { | |
// Each octave adds a level of granuality by halfing the position value. | |
float3 heightPos = worldPos * _HeightFrequency * pow(0.5, heightIndex); | |
// Use the gradient version of Simplex noise, as we will use the data it in the normal adjustments later. | |
heightGrad += snoise_grad(heightPos) * weight; | |
totalWeight += weight; | |
weight *= _HeightLacunarity; | |
} | |
// Normalize gradient. | |
heightGrad /= totalWeight; | |
weight = 1.0; | |
totalWeight = 0.0; | |
for (int humidityIndex = 1; humidityIndex <= _HumidityOctaves; humidityIndex++) { | |
// Each octave adds a level of granuality by halfing the position value. | |
float3 humidityPos = worldPos * _HumidityFrequency * pow(0.5, humidityIndex); | |
// Humidity isn't going to affect the normal, so we won't need the gradient, so we use the normal snoise() function. | |
humidity += snoise(humidityPos) * weight; | |
totalWeight += weight; | |
weight *= _HumidityLacunarity; | |
} | |
// Normalize. | |
humidity /= totalWeight; | |
// Limit the minimum height at ocean level and make the mountains more pointy by a simple power. | |
// Take note: heightGrad.w is in the [-1 ... 1] range here. | |
float height = pow(max(heightGrad.w, 0.0), 2) * _Displacement * _HeightScalar; | |
float3 up = v.normal; | |
v.vertex.xyz += up * height; | |
// Use the Color RG-channels to transfer the Height and Humidity values to the pixel shader. | |
v.color = float4( | |
0.5 + 0.5 * heightGrad.w * _HeightScalar, | |
0.5 + 0.5 * humidity * _HumidityScalar, | |
0.0, 0.0); | |
// Tried my hand at fixing the normals... this ain't right, but it provides meh-ok looking results. | |
heightGrad.xyz = lerp(up, heightGrad.xyz, height * 2.0); | |
heightGrad.xyz = up - (heightGrad.xyz - up * dot(heightGrad.xyz, up)); | |
heightGrad.xyz = normalize(heightGrad.xyz); | |
v.normal = heightGrad.xyz; | |
} | |
sampler2D _MainTex; | |
half _Glossiness; | |
half _Metallic; | |
fixed4 _Color; | |
void surf (Input IN, inout SurfaceOutputStandard o) { | |
// Use the input color's RG as X, Y coordinates on the texture. | |
// They translate to the Height and Humidity values, supposedly. Roughly. | |
o.Albedo = tex2D(_MainTex, IN.color.rg) * _Color; | |
// Metallic and smoothness come from slider variables | |
o.Metallic = _Metallic; | |
o.Smoothness = _Glossiness; | |
} | |
ENDCG | |
} | |
FallBack "Diffuse" | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment