您的位置:首页 > 移动开发 > Unity3D

Unity3d中实现点云效果

2014-06-11 17:09 218 查看
有一段时间没写博客了,主要是最近实在太忙,学校的毕设,论文,公司的项目,感情的事儿都加在一块儿,嗨,做男人真累啊!!!

今天跟大家分享的是个人在实现效果时的一个小技巧,希望对有相关兴趣的童鞋有所帮助,关于点云在Unity里面的实现,我在Asset Store上查了一下,还真有一个叫做Point Cloud Viewer and Tooll的插件:



当然是收费插件,看他的介绍是用DX11的特性写了shader然后才显示出点来,关于写Shader我一向都不在行,想学却一直抽不出时间,等把毕设做的差不多了再说吧。我并没有让亲们去花钱买这个插件,那也没必要写这篇博文了,下面是我们的另类的实现方案,测试了一下,30万个点有一点点的卡,不过整体效果还好。

下面介绍不适用DX11特性的实现方案: Particle System! 就是粒子啦。。。

其实这也是受unity官方案例 Procedural Examples中一个场景的启发,用粒子发射器发射固定量的粒子,然后给每个粒子一个位置和颜色信息就OK了,开始的时候让particleEmitter.emit 为 false , 然后调用一个particleEmitter.Emit(int count)的函数,里面的count就是总共的粒子,也就是点云的点的数目了!

这是效果图:



这里可以改变粒子的position, color, size等属性,基本上满足需求。在上代码之前要说明一下的是:传统的Ellipsoid Particle Emitter 加上 Particle Renderer 才能实现上面的效果,但是有一个粒子数量的限制,好像一万多,我在拿同学一个点云文件读取的时候只是显示了很少的一部分。后来经过反复的查找才发现是其本身粒子数目有限制。 而用了新版的particle system 就没有这个限制了, 唯一觉得有点儿不足的就是它有一个lifetime的属性,就是粒子的生命周期,如果想要一直显示就必须给一个很大的值。而老版的并没有这个问题。

代码是根据官方案例改的,没有版权问题吧






using UnityEngine;
using System.Collections;

public class HeightMapGenerator : MonoBehaviour {

public Texture2D heightMap;
public Material material;
public Vector3 size =new Vector3(200, 30, 200);

ParticleSystem.Particle[] allParticles;

public Texture2D curTexture;

// Use this for initialization
void Start () {

particleSystem.emissionRate = 0;

GenerateHeightmap();
}

void GenerateHeightmap ()
{
// Create the game object containing the renderer
gameObject.AddComponent<MeshFilter>();
gameObject.AddComponent<MeshRenderer>();
if (material)
renderer.material = material;
else
renderer.material.color = Color.white;

// Retrieve a mesh instance
Mesh mesh = GetComponent<MeshFilter>().mesh;

int width = Mathf.Min(heightMap.width, 255);
int height = Mathf.Min(heightMap.height, 255);
int y = 0;
int x = 0;

// Build vertices and UVs
Vector3[] vertices = new Vector3[height * width];

Vector2[] uv = new Vector2[height * width];
Vector4[] tangents = new Vector4[height * width];

Vector2 uvScale =new Vector2 (1.0f / (width - 1), 1.0f / (height - 1));
Vector3 sizeScale = new Vector3 (size.x / (width - 1), size.y, size.z / (height - 1));

particleSystem.Emit(height * width);

allParticles = new ParticleSystem.Particle[width * height];

int count = particleSystem.GetParticles(allParticles);

for (y=0;y<height;y++)
{
for (x=0;x<width;x++)
{
float pixelHeight = heightMap.GetPixel(x, y).grayscale;
Vector3 vertex = new Vector3 (x, pixelHeight, y);
vertices[y*width + x] = Vector3.Scale(sizeScale, vertex);

allParticles[y * width + x].position = Vector3.Scale(sizeScale, vertex);//点的位置
allParticles[y * width + x].color = curTexture.GetPixel(x,y);//点的颜色
allParticles[y * width + x].size = pixelHeight+0.6f;//点的大小

uv[y*width + x] = Vector2.Scale(new Vector2 (x, y), uvScale);

// Calculate tangent vector: a vector that goes from previous vertex
// to next along X direction. We need tangents if we intend to
// use bumpmap shaders on the mesh.
Vector3 vertexL = new Vector3( x-1, heightMap.GetPixel(x-1, y).grayscale, y );
Vector3 vertexR = new Vector3( x+1, heightMap.GetPixel(x+1, y).grayscale, y );
Vector3 tan = Vector3.Scale( sizeScale, vertexR - vertexL ).normalized;
tangents[y*width + x] =new Vector4( tan.x, tan.y, tan.z, -1.0f );
}
}

particleSystem.SetParticles(allParticles,count);

//		// Assign them to the mesh
//		mesh.vertices = vertices;
//		mesh.uv = uv;
//
//		// Build triangle indices: 3 indices into vertex array for each triangle
//		var triangles = new int[(height - 1) * (width - 1) * 6];
//		var index = 0;
//		for (y=0;y<height-1;y++)
//		{
//			for (x=0;x<width-1;x++)
//			{
//				// For each grid cell output two triangles
//				triangles[index++] = (y     * width) + x;
//				triangles[index++] = ((y+1) * width) + x;
//				triangles[index++] = (y     * width) + x + 1;
//
//				triangles[index++] = ((y+1) * width) + x;
//				triangles[index++] = ((y+1) * width) + x + 1;
//				triangles[index++] = (y     * width) + x + 1;
//			}
//		}
//		// And assign them to the mesh
//		mesh.triangles = triangles;
//
//		// Auto-calculate vertex normals from the mesh
//		mesh.RecalculateNormals();
//
//		// Assign tangents after recalculating normals
//		mesh.tangents = tangents;
}

}


从代码容易看出,粒子的位置是根据一张灰度图读到的,颜色是用的是另一张图。就是这样的,希望有兴趣的童鞋可以相互交流哈,

QQ: 626222539
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: