Created
March 19, 2018 02:33
-
-
Save klkucan/ce6ccf08012d989faeeaa1429a4352b9 to your computer and use it in GitHub Desktop.
make a terrain with code, and you can use multiple textures
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 "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" | |
} |
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
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