Skip to content

Instantly share code, notes, and snippets.

@Towkin
Created August 15, 2018 21:05
Show Gist options
  • Save Towkin/68ab57ea9aa2130d32c57f0918653ac1 to your computer and use it in GitHub Desktop.
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.
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