Skip to content

Instantly share code, notes, and snippets.

@klkucan
Created March 19, 2018 02:33
Show Gist options
  • Save klkucan/ce6ccf08012d989faeeaa1429a4352b9 to your computer and use it in GitHub Desktop.
Save klkucan/ce6ccf08012d989faeeaa1429a4352b9 to your computer and use it in GitHub Desktop.
make a terrain with code, and you can use multiple textures
Shader "CustomTerrainShaderVF" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_SecondTex("Second (RGB)",2D) = "white"{}
_ThirdTex("ThirdTex (RGB)",2D) = "white"{}
_FourthTex("FourthTex (RGB)",2D) = "white"{}
_Mask("Mask(RG)",2D) = "white"{}
}
SubShader {
Pass {
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
sampler2D _MainTex;
sampler2D _SecondTex;
sampler2D _ThirdTex;
sampler2D _FourthTex;
sampler2D _Mask;
float4 _MainTex_ST;
float4 _SecondTex_ST;
float4 _ThirdTex_ST;
float4 _FourthTex_ST;
float4 _Mask_ST;
struct a2v {
float4 vertex : POSITION;
float4 texcoord : TEXCOORD0;
};
struct v2f {
float4 position : SV_POSITION;
float2 uv : TEXCOORD0;
};
v2f vert(a2v v) {
v2f o;
// Transform the vertex from object space to projection space
o.position = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
fixed4 frag(v2f i) : SV_Target {
half4 c1 = tex2D (_MainTex, i.uv);
half4 c2 = tex2D (_SecondTex, i.uv);
half4 c3 = tex2D (_ThirdTex, i.uv);
half4 c4 = tex2D (_FourthTex, i.uv);
half4 cm = tex2D (_Mask, i.uv);
half3 c = c1.rgb*cm.r+c2.rgb*cm.g+c3.rgb*cm.b+c4.rgb*cm.a;
return fixed4(c.rgb, 1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}
using UnityEngine;
using System.Collections;
public class TerrainManager : MonoBehaviour
{
//材质和高度图
public Material diffuseMap;
public Texture2D heightMap;
//顶点、uv、索引信息
private Vector3[] vertives;
private Vector2[] uvs;
private int[] triangles;
//生成信息
private Vector2 size;//长宽
private float minHeight = -10;
private float maxHeight = 10;
private Vector2 segment;
private float unitH;
//面片mesh
private GameObject terrain;
// Use this for initialization
void Start()
{
//默认生成一个地形,如果不喜欢,注销掉然后用参数生成
SetTerrain();
}
/// <summary>
/// 生成默认地形
/// </summary>
public void SetTerrain()
{
SetTerrain(100, 100, 50, 50, -10, 10);
}
/// <summary>
/// 通过参数生成地形
/// </summary>
/// <param name="width">地形宽度</param>
/// <param name="height">地形长度</param>
/// <param name="segmentX">宽度的段数</param>
/// <param name="segmentY">长度的段数</param>
/// <param name="min">最低高度</param>
/// <param name="max">最高高度</param>
public void SetTerrain(float width, float height, uint segmentX, uint segmentY, int min, int max)
{
Init(width, height, segmentX, segmentY, min, max);
GetVertives();
DrawMesh();
}
/// <summary>
/// 初始化计算某些值
/// </summary>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="segmentX"></param>
/// <param name="segmentY"></param>
/// <param name="min"></param>
/// <param name="max"></param>
private void Init(float width, float height, uint segmentX, uint segmentY, int min, int max)
{
size = new Vector2(width, height);
maxHeight = max;
minHeight = min;
unitH = maxHeight - minHeight;
segment = new Vector2(segmentX, segmentY);
if (terrain != null)
{
Destroy(terrain);
}
terrain = new GameObject();
terrain.name = "plane";
}
/// <summary>
/// 绘制网格
/// </summary>
private void DrawMesh()
{
Mesh mesh = terrain.AddComponent<MeshFilter>().mesh;
terrain.AddComponent<MeshRenderer>();
if (diffuseMap == null)
{
Debug.LogWarning("No material,Create diffuse!!");
diffuseMap = new Material(Shader.Find("Diffuse"));
}
if (heightMap == null)
{
Debug.LogWarning("No heightMap!!!");
}
terrain.GetComponent<Renderer>().material = diffuseMap;
//给mesh 赋值
mesh.Clear();
mesh.vertices = vertives;//,pos);
mesh.uv = uvs;
mesh.triangles = triangles;
//重置法线
mesh.RecalculateNormals();
//重置范围
mesh.RecalculateBounds();
}
/// <summary>
/// 生成顶点信息
/// </summary>
/// <returns></returns>
private Vector3[] GetVertives()
{
int sum = Mathf.FloorToInt((segment.x + 1) * (segment.y + 1));
float w = size.x / segment.x;
float h = size.y / segment.y;
int index = 0;
GetUV();
GetTriangles();
vertives = new Vector3[sum];
for (int i = 0; i < segment.y + 1; i++)
{
for (int j = 0; j < segment.x + 1; j++)
{
float tempHeight = 0;
if (heightMap != null)
{
tempHeight = GetHeight(heightMap, uvs[index]);
}
vertives[index] = new Vector3(j * w, tempHeight, i * h);
index++;
}
}
return vertives;
}
/// <summary>
/// 生成UV信息
/// </summary>
/// <returns></returns>
private Vector2[] GetUV()
{
int sum = Mathf.FloorToInt((segment.x + 1) * (segment.y + 1));
uvs = new Vector2[sum];
float u = 1.0F / segment.x; // 每段的UV长度
float v = 1.0F / segment.y;
uint index = 0;
for (int i = 0; i < segment.y + 1; i++)
{
for (int j = 0; j < segment.x + 1; j++)
{
uvs[index] = new Vector2(j * u, i * v);
index++;
}
}
return uvs;
}
/// <summary>
/// 生成索引信息
/// </summary>
/// <returns></returns>
private int[] GetTriangles()
{
int sum = Mathf.FloorToInt(segment.x * segment.y * 6);
triangles = new int[sum];
uint index = 0;
for (int i = 0; i < segment.y; i++)
{
for (int j = 0; j < segment.x; j++)
{
int role = Mathf.FloorToInt(segment.x) + 1;
int self = j + (i * role);
int next = j + ((i + 1) * role);
triangles[index] = self;
triangles[index + 1] = next + 1;
triangles[index + 2] = self + 1;
triangles[index + 3] = self;
triangles[index + 4] = next;
triangles[index + 5] = next + 1;
index += 6;
}
}
return triangles;
}
private float GetHeight(Texture2D texture, Vector2 uv)
{
if (texture != null)
{
//提取灰度。如果强制读取某个通道,可以忽略
Color c = GetColor(texture, uv);
float gray = c.grayscale;//或者可以自己指定灰度提取算法,比如:gray = 0.3F * c.r + 0.59F * c.g + 0.11F * c.b;
float h = unitH * gray;
return h;
}
else
{
return 0;
}
}
/// <summary>
/// 获取图片上某个点的颜色
/// </summary>
/// <param name="texture"></param>
/// <param name="uv"></param>
/// <returns></returns>
private Color GetColor(Texture2D texture, Vector2 uv)
{
Color color = texture.GetPixel(Mathf.FloorToInt(texture.width * uv.x), Mathf.FloorToInt(texture.height * uv.y));
return color;
}
/// <summary>
/// 从外部设置地形的位置坐标
/// </summary>
/// <param name="pos"></param>
public void SetPos(Vector3 pos)
{
if (terrain)
{
terrain.transform.position = pos;
}
else
{
SetTerrain();
terrain.transform.position = pos;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment