(翻译)Unity中,在Terrain上绘制网格

Draw grid on the terrain in Unity

Jan 23, 2015

Drawing grid on the terrain is used in lot of game genres – RTS, Simulation, Tower defense, etc. It can be done very easily in Unity.

Here is some very simple extensible solution with following features:

Respect terrain height Option to have different texture in different parts (eg. to distinguish free and taken cells) Configurable (you can resize grid in editor or real-time and set cell size)

在许多游戏类型的RTS、仿真、塔防御等游戏中都使用了绘图网格,可以很容易地在Unity中完成。

下面是一些非常简单的可扩展的解决方案,具有以下特性:

根据地形高度选项在不同的部分有不同的纹理 (例如. 区分free 和 taken cells)可配置 (可在编辑器或 real-time 中调整网格大小并设置单元格尺寸)

代码:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class TerrainGrid : MonoBehaviour {
public float cellSize = 1;
public int gridWidth = 10;
public int gridHeight = 10;
public float yOffset = 0.5f;
public Material cellMaterialValid;
public Material cellMaterialInvalid;

private GameObject[] _cells;
private float[] _heights;

void Start() {
_cells = new GameObject[gridHeight * gridWidth];
_heights = new float[(gridHeight + 1) * (gridWidth + 1)];

for (int z = 0; z < gridHeight; z++) {
for (int x = 0; x < gridWidth; x++) {
_cells[z * gridWidth + x] = CreateChild();
}
}
}

void Update () {
UpdateSize();
UpdatePosition();
UpdateHeights();
UpdateCells();
}

GameObject CreateChild() {
GameObject go = new GameObject();

go.name = "Grid Cell";
go.transform.parent = transform;
go.transform.localPosition = Vector3.zero;
go.AddComponent<MeshRenderer>();
go.AddComponent<MeshFilter>().mesh = CreateMesh();

return go;
}

void UpdateSize() {
int newSize = gridHeight * gridWidth;
int oldSize = _cells.Length;

if (newSize == oldSize)
return;

GameObject[] oldCells = _cells;
_cells = new GameObject[newSize];

if (newSize < oldSize) {
for (int i = 0; i < newSize; i++) {
_cells[i] = oldCells[i];
}

for (int i = newSize; i < oldSize; i++) {
Destroy(oldCells[i]);
}
}
else if (newSize > oldSize) {
for (int i = 0; i < oldSize; i++) {
_cells[i] = oldCells[i];
}

for (int i = oldSize; i < newSize; i++) {
_cells[i] = CreateChild();
}
}

_heights = new float[(gridHeight + 1) * (gridWidth + 1)];
}

void UpdatePosition() {
RaycastHit hitInfo;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Physics.Raycast(ray, out hitInfo, Mathf.Infinity, LayerMask.GetMask("Terrain"));
Vector3 position = hitInfo.point;

position.x -= hitInfo.point.x % cellSize + gridWidth * cellSize / 2;
position.z -= hitInfo.point.z % cellSize + gridHeight * cellSize / 2;
position.y = 0;

transform.position = position;
}

void UpdateHeights() {
RaycastHit hitInfo;
Vector3 origin;

for (int z = 0; z < gridHeight + 1; z++) {
for (int x = 0; x < gridWidth + 1; x++) {
origin = new Vector3(x * cellSize, 200, z * cellSize);
Physics.Raycast(transform.TransformPoint(origin), Vector3.down, out hitInfo, Mathf.Infinity, LayerMask.GetMask("Terrain"));

_heights[z * (gridWidth + 1) + x] = hitInfo.point.y;
}
}
}

void UpdateCells() {
for (int z = 0; z < gridHeight; z++) {
for (int x = 0; x < gridWidth; x++) {
GameObject cell = _cells[z * gridWidth + x];
MeshRenderer meshRenderer = cell.GetComponent<MeshRenderer>();
MeshFilter meshFilter = cell.GetComponent<MeshFilter>();

meshRenderer.material = IsCellValid(x, z) ? cellMaterialValid : cellMaterialInvalid;
UpdateMesh(meshFilter.mesh, x, z);
}
}
}

bool IsCellValid(int x, int z) {
RaycastHit hitInfo;
Vector3 origin = new Vector3(x * cellSize + cellSize/2, 200, z * cellSize + cellSize/2);
Physics.Raycast(transform.TransformPoint(origin), Vector3.down, out hitInfo, Mathf.Infinity, LayerMask.GetMask("Buildings"));

return hitInfo.collider == null;
}

Mesh CreateMesh() {
Mesh mesh = new Mesh();

mesh.name = "Grid Cell";
mesh.vertices = new Vector3[] { Vector3.zero, Vector3.zero, Vector3.zero, Vector3.zero };
mesh.triangles = new int[] { 0, 1, 2, 2, 1, 3 };
mesh.normals = new Vector3[] { Vector3.up, Vector3.up, Vector3.up, Vector3.up };
mesh.uv = new Vector2[] { new Vector2(1, 1), new Vector2(1, 0), new Vector2(0, 1), new Vector2(0, 0) };

return mesh;
}

void UpdateMesh(Mesh mesh, int x, int z) {
mesh.vertices = new Vector3[] {
MeshVertex(x, z),
MeshVertex(x, z + 1),
MeshVertex(x + 1, z),
MeshVertex(x + 1, z + 1),
};
}

Vector3 MeshVertex(int x, int z) {
return new Vector3(x * cellSize, _heights[z * (gridWidth + 1) + x] + yOffset, z * cellSize);
}
}

Because we want to have different kind of cells we have two options – one is using separate game object for every cell and second option is using one game object containing mesh with lot of submeshes. I chose first option because of simplicity and flexibility.

因为我们想要有不同种类的格子, 我们有两个选择-一个是为每个格子使用单独的游戏对象和第二个选项是使用一个包涵网格的游戏对象, 其中含有大量的网格集合。我选择的第一个选项, 因为简单和灵活性。

For every cell we create corresponding mesh. In example above you can see that it‘s very simple square mesh from just 2 triangles (line 131). Y coordinate of each square‘s vertex is calculated by doing raycast on the terrain (precalculated for every cell in UpdateHeights method every frame) and adding yOffset value. For better result you can experiment with square mesh with much more triangles (eg. 24).

对于每个单元格, 我们创建相应的网格。在上面的例子中, 你可以看到, 它是非常简单的正方形网格从2个三角形 (131 行)。每个正方形顶点的 Y 坐标是通过在地形上进行 raycast (每帧调用UpdateHeights 对于每个单元格) 和增加 yOffset 值来计算的。为更好的结果, 你可以试验的正方形网格更多的三角形 (例如 24)。

To every mesh of the cell we assign material based on IsCellValid method which is doing raycast through the center of the cell and checking "Buildings" layer for some colliders, if there is any the cellMaterialInvalid is used (red in screenshot), otherwise cellMaterialValid is used (green).

对单元格的每个网格我们分配材料基于 IsCellValid 方法,这个方法是通过方格中心并且检查 "Buildings" 层数,做 raycast 为有些碰撞, 如果有任何 cellMaterialInvalid 使用 (截图的中红色), 否则cellMaterialValid 使用 (绿色)。

Number of cells are managed in UpdateSize method which is checking for size changes and doing corresponding action – adding new or deleting cells.

In method UpdatePosition the grid is moved so it‘s center is always under mouse cursor.

This is just an example and for real use you will probably have to modify position and resizing behaviour.

单元格的数量在 UpdateSize 方法中进行管理, 它正在检查大小更改并执行相应操作–添加新或删除单元格。

在方法 UpdatePosition 中, 网格被移动, 因此它的中心总是在鼠标光标下面。

这只是一个例子, 对于实际使用, 您可能需要修改位置和调整行为。

原文地址 <http://rene.klacan.sk/unity3d/games/2015/01/23/draw-grid-on-the-terrain-in-unity/>

时间: 2024-10-06 10:10:48

(翻译)Unity中,在Terrain上绘制网格的相关文章

Unity中实现网格轮廓效果

问题背景: 最近要实现选中实体的高亮效果,要那种类似于unity中Outline的效果,网格轮廓高亮效果. 效果图: 具体代码: OutlineEffect.cs 实体高亮效果类: 轮廓边总控制类,该脚本需要挂载到场景相机上 1 using UnityEngine; 2 using System.Collections.Generic; 3 using UnityEngine.Rendering; 4 5 namespace Tx3d.Framework 6 { 7 [DisallowMulti

【原创翻译】初识Unity中的Compute Shader

一直以来都想试着自己翻译一些东西,现在发现翻译真的很不容易,如果你直接把作者的原文按照英文的思维翻译过来,你会发现中国人读起来很是别扭,但是如果你想完全利用中国人的语言方式来翻译,又怕自己理解的不到位,反而与作者的愿意相悖.所以我想很多时候,国内的译者也是无奈吧,下次再看到译作也会抱着一些感同身受的态度去读.这是我第一次翻译整篇文章,能力有限,望见谅,翻译不好的地方也希望大家指出来. 其实ComputeShader在Unity中出现已经有蛮长的一段时间了,因为自己一直对Shader比较感兴趣,所

Unity&amp;Shader基础篇-绘制网格+圆盘

一.前言 尊重原创,转载请注明出处凯尔八阿哥专栏 上一章点击打开链接中已经画出了一个棋盘网格,首先来完善一下这个画网格的Shader,添加属性,属性包括网格的线的宽度,网格的颜色等.代码如下: Shader "Unlit/Chapter2-2" { Properties { _backgroundColor("面板背景色",Color) = (1.0,1.0,1.0,1.0) _axesColor("坐标轴的颜色",Color) = (0.0,0

Matlab-Octave中绘制网格图和等高线:mesh 和 surf

x=linspace(-50, 50, 50); % 在x轴上取50点y=linspace(-25, 25, 25); % 在y轴上取25点[xx,yy]=meshgrid(x, y); % xx和yy都是矩阵zz=8000-2.*xx.*xx-5.*yy.*yy; % 计算函数值,zz也是21x21的矩阵surf(xx, yy, zz); % 画出立体曲面图colorbar; %如下图,右边那个色卡 可按回车 contour(xx,yy,zz)colorbar 可按回车surfc(xx,yy,

在图片上画矩形并高亮显示矩形区域、统计矩形区域中像素情况并绘制直方图

<学习OpenCV>中文版第4章第3题 提纲 题目要求 程序代码 结果图片 题目要求: ①允许用户在图片上选择一个矩形区域,当鼠标放开,高亮显示矩形区域 ②在另一个独立窗口中,使用绘图函数绘制一个图表,分别用蓝.绿和红色表示选中区域中各种颜色的像素在指定数值范围内的数量. 程序代码: 1 #include "stdafx.h" 2 #include <cv.h> 3 #include <highgui.h> 4 using namespace std

HTML5中的&lt;canvas&gt;画布:使用canvas元素在网页上绘制四分之一圆(3)

前几天自己做了个四分之一的圆,放到手机里面测试.效果不是很好.于是今天通过查资料,找到了canvas.自己研究了一天,发现可以使用canvas画圆.代码如下: 1 <!doctype html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title></title> 6 7 </head> 8 <body&g

HTML5中的&lt;canvas&gt;画布:使用canvas元素在网页上绘制线条和圆(1)

什么是 Canvas? HTML5 的 canvas 元素使用 JavaScript 在网页上绘制图像. 画布是一个矩形区域,您可以控制其每一像素. canvas 拥有多种绘制路径.矩形.圆形.字符以及添加图像的方法. 创建 Canvas 元素 向 HTML5 页面添加 canvas 元素. 规定元素的 id.宽度和高度: 1 <canvas id="myCanvas" width="200" height="100"></ca

[转载]Unity中T4M插件的中文教程

ps:原文出处:http://blog.csdn.net/tianmao111/article/details/46482963 T4M是什么?为什么要用它? 它是一个地形(Terrain)工具.它是一个Unity地形的替代工具,用于所有被3D开发工具(Maya,EarthSculpto,3DS Max,Blender等)创建的几何体.最初,它只用于移动设备,但是更多的人发现了其他的一些益处: T4M是允许用户导入几何体到Unity作为地形(Terrain)的一种工具.T4M for Web和f

2019.9.27 Unity中Sprite和UI Image的区别

来源:https://blog.csdn.net/coffeecato/article/details/78536488 coffeecato写在前面:本文确实不错,作者用以说明自动生成网格的示图非常具有代表性,从drawcall的生成过程分析性能开销的重点,引出了overdraw和达到GPU像素填充率限制的原因,从中也可以看出作者对这个主题的理解颇有深度.查看作者的个人自述,居然是个2012年毕业的小伙子,后生可畏啊!翻译本文对自己也是个考验.英文水平捉急,如果错误请多多指正. 原文:UNIT