微信理财通和余额宝会员有什么特权 微信理财通和余额宝会员特权说明

Unity中Mesh分解与边缘高亮加上深度检测_Unity3D教程_中国AR网
&当前位置: &
一个比较简单的需求,不过遇到些坑,记录下。  房间有多个模型,每个模型可能多个SubMesh,点击后,需要能具体到是那个SubMesh,并且在这个SubMesh上显示边缘高光,以及能个性这单个SubMesh对应的Material。如一个桌子的Mesh,其实有二个材质,分别对应二个SubMesh,一个桌面和一个桌脚,点击桌面后,只有这个桌面高光,而不是整个桌子,并且能单独更换这个桌面的Material.  我们知道Unity中,Mesh和Ogre一样,也是可以有多个SubMesh,每个SubMesh有自己的Material,但是不同Ogre每个Submesh可以有不同的顶点数据,Unity中Mesh所有SubMesh共享相同顶点数据,分别使用不同的顶点索引。我原来做过一个项目,用Ogre里的Renderable与MovableObject组合形成这种格式,里面的所有模型都是用的这种格式显示,而不是Ogre本身的Entiy,当时就发现这种更容易理解,好用。  下面这个脚本文件是这个功能的具体实现,包含分解Mesh,检查具体是那个SubMesh碰撞等功能。&
&&&&&&cIndex&=&-&Material&lineMat&=&&Material&selectMat&=&
&&&&&MeshFilter&meshFilter&=&&MeshRenderer&meshRender&=&&MeshCollider&meshCollider&=&&BoxCollider&boxCollider&=&&&Transform&transform&=&&LineRenderer&lineRender&=&&HighlightableObject&hightLight&=&&&vminDist&=&&List&&&indexLay&=&&List&&&&bPreObject&=&&&preIndex&=&&Mesh&mesh&=&
&&&&&&defaultAdd&=&&RaycastHit&preHit&=&&&bHold&=&&Vector3&oldLocation&=&Dictionary&,&List&&&&matTextures&=&&Dictionary&,&List&&&=&Resources.Load&Material&(=&checkDefault&MeshFilter&=&checkDefault&MeshCollider&=&checkDefault&MeshRenderer&=&checkDefault&BoxCollider&=&checkDefault&Transform&=&checkDefault&LineRenderer&=&checkDefault&HighlightableObject&=&=,&
&&&&&&&&.gameObject.layer&=&=&,&matTextures,&XmlReader.ParseMatXml,&&&T&()&=&.gameObject.GetComponent&T&&(t&==&=&.gameObject.AddComponent&T&
&&&&&UNITY_EDITOR&&&&&&&&&(Input.GetMouseButtonDown()&&&&!&UNITY_ANDROID&||&UNITY_IPHONE&&&&&&&&&(Input.touchCount&&&&&&&Input.GetTouch().phase&==&TouchPhase.Began&&&&&!EventSystem.current.IsPointerOverGameObject(Input.GetTouch(=&bAxis&=&Physics.Raycast(ray,&&hit,&,&&&&&==&=
&&&&&&&&&&&&&(GetMinDist(ray,&&(preCollider&!=&=&
&&&&&&&&&&&&&&&&bPreObject&=&hit.collider&==&(!bPreObject&&&&preCollider&!=&=
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&(selectMat&!=&&haveTexture&=
&&&&&&&&&&&&&&&&&&&&&&&&&(defaultAdd&||&(defaultAdd&||&UNITY_EDITOR&&&&&&&&&(Input.GetMouseButtonUp(&UNITY_ANDROID&||&UNITY_IPHONE&&&&&&&&&(Input.touchCount&&&&&&&Input.GetTouch().phase&===&&&&UNITY_EDITOR&&&&&&&&&(bHold&&&&Input.GetMouseButton(&UNITY_ANDROID&||&UNITY_IPHONE&&&&&&&&&(bHold&&&&Input.touchCount&&&&&&&Input.GetTouch().phase&===&newPot&=&ray.origin&+&ray.direction&*&preHit.distance&-=&&GetMinDist(Ray&ray,&=&&hits&=&origin&=&minDist&=&&result&=&&(&hit&&(hit.collider&==&meshCollider&||&hit.collider&==&sqrLenght&=&(hit.point&-&(sqrLenght&&===&&&render&=&collider.GetComponent&Renderer&&filter&=&collider.GetComponent&MeshFilter&&(render&!=&&&&&filter&!=&
&&&&&&&&&&&&transform.position&====
&&&&&&&&&&&&&minDist&=&=&=&=&=&====
&&&&&&&&&&&&&(filter.mesh.subMeshCount&&&&(&meshIndex&=&;&meshIndex&&&filter.mesh.subMeshC&meshIndex++=&=&&indexs&=&(indexs.Length&/&&&&=&====&==&(currentCollider.Raycast(ray,&&hit,&&sqrLenght&=&(Camera.main.transform.position&-
&&&&&&&&&&&&&&&&&&&&&&&&&(Mathf.Abs(sqrLenght&-&minDist)&&&(!&(!&(sqrLenght&&===&mesh.bounds.center&-&mesh.bounds.size&/=&mesh.bounds.center&+&mesh.bounds.size&/
&&&&&&&&&&&&&(indexLay.Count&&&&&&&nIndex&==&++nIndex&%=&(cIndex&&=&&&&&render.materials.Length&&=
&&&&&&&&&&&&&&&&&indexs&==
&&&&&&&&&&&&&&&&meshRender.material&=&vertexs&=
&&&&&&&&&&&&&&&&meshRender.enabled&=&&&&=&&&&cornerDirty&=&&Vector3&min&=&Vector3&max&=&Vector3[]&mCorners&=&&Vector3[==&==&&&(cmp.x&&=&(cmp.y&&=&(cmp.z&&=&&(cmp.x&&=&(cmp.y&&=&(cmp.z&&=&=&&===&&&&&
&&&&&&&&&]&=].x&=&min.x;&mCorners[].y&=&max.y;&mCorners[].z&=].x&=&max.x;&mCorners[].y&=&max.y;&mCorners[].z&=].x&=&max.x;&mCorners[].y&=&min.y;&mCorners[].z&=]&=].x&=&min.x;&mCorners[].y&=&max.y;&mCorners[].z&=].x&=&min.x;&mCorners[].y&=&min.y;&mCorners[].z&=].x&=&max.x;&mCorners[].y&=&min.y;&mCorners[].z&=&i&=&=&&Vector3[
&&&&&&&&pos[i++]&=&.Corners[++]&=&.Corners[++]&=&.Corners[
&&&&&&&&pos[i++]&=&.Corners[++]&=&.Corners[++]&=&.Corners[
&&&&&&&&pos[i++]&=&.Corners[++]&=&.Corners[++]&=&.Corners[
&&&&&&&&pos[i++]&=&.Corners[++]&=&.Corners[++]&=&.Corners[
&&&&&&&&pos[i++]&=&.Corners[++]&=&.Corners[++]&=&.Corners[++]&=&.Corners[=&=&=&=  需要注意的点是:  1&如果几个模型有多个SubMesh分散在各个位置,故需要把所有RaycastHit上碰撞点与眼睛求出最近点。  2 LineRender中是N点组成N-1条线,而不是N/2,如A-B-C-D,并不是显示AB,CD.而是AB,BC,CD.  3 模型的SubMesh可能边框重合,这样的话,就会导致可能永远都是选的其中一个。  4 我们根据SubMesh生成新的Mesh,并不需要在主摄像头中渲染(通过Layer与cullingMask组合),不然和原来模型的SubMesh显示不清。  5 鼠标按下,是否在UI上面,鼠标弹起,电脑与移动平台要不同的处理。  6 安卓平台下,用WWW加载资源,必需用yield return,故相应加载完成的处理可以用函数指针传入。  到这模型就差不多了,然后添加边缘高亮组件highightingSystem,这个的思路也是比较简单的。  首先在主摄像机渲染场景前,把边缘高亮的模型给一个单独的层,并且修改相应材质为我们需要高亮的颜色,然后复制主摄像头新生成一个摄像头,新摄像头的cullingMask只渲染前面边缘高亮模型的层的那些模型到一张Stencil的RTT中保存,然后把原来的边缘高亮的模型的层和材质换回来。  然后是主摄像头正常渲染,渲染完后,在OnRenderImage中先把在上面的那张RTT进行简单的Blur模糊,保存为Blur的RTT。最后把上面的Stencil的RTT,Blur的RTT,主摄像头渲染的source,我们并不渲染stencil本身,只渲染stencil模糊后的边缘部分。  嗯,现在有个麻烦,老大要在看不到的部分不显示高亮,如下这样:  &  第一张图是现在的显示效果,老大要的是第二张,说实话,我最开始以为很简单,好吧,做完后就加了点东东,确实不复杂,但是因为对Unity的相关理解有误,把采过的坑说下。  说实话,这个需求就是加个深度检测就行了,那么在原来基础上添加如下一些代码。=&refCam.projectionM&&&&&&&&shaderCamera.cullingMask&==&==&=&=&==shaderCamera.depthTextureMode&=depthBuffer&=&RenderTexture.GetTemporary(()GetComponent&Camera&().pixelWidth,&()GetComponent&Camera&().pixelHeight,&=);  Shader.Shader&&=&&vertex&vert&&&&&&&&&&&&&fragment&frag
&&&&&&&&&&&&
&&&&&&&&&&&&==&v.texcoord.&
&&&&&&&&&&&&&&&&o.depth&=
&&&&&&&&&&&&&&&&&float4(i.depth,,,  在这我进行一次尝试,结果不对,在shaderCamera.Render()渲染之前,设定depthTextureMode为Depth,我在Shader开始应用_CameraDepthTexture,发现结果不对,网上查找说是这个RTT一直是主摄像头的,后面使用_LastCameraDepthTexture,结果很奇怪,和后面主摄像头的_CameraDepthTexture比对结果完全对不上,深度值不是0或1,但是渲染出来看,深度值又没看到变化,后来仔细想了下,应该是主摄像头Graphics.Blit后的值,因为这个只是渲染一个正方形,深度显示出来就会这样。  最后去Unity5Shader里面找_CameraDepthTexture这个RTT是如何渲染的,我们找到这个值COMPUTE_DEPTH_01是放入深度RTT中的,具体意思大家去unityCG.cginc里去找就行了,因为这个值就是根据当前顶点的位置算出来的,所以在这我们放入顶点着色器就行。  然后就是在第一张Blur模糊图上比较上一张深度RTT的深度值,相应DEPTH_COMP_ON位置为新增加的。&&&&
&&&&&&off&=Shader&,&2D)&=&,&Range(,))&=&,&2D)&=&&vertex&vert&&&&&&&&&&&&&fragment&frag&&&&&&&&&&&&&fragmentoption&ARB_precision_hint_fastest&&&&&&&&&&&&&multi_compile&__&DEPTH_COMP_ON&
&&&&&&&&&defined(DEPTH_COMP_ON)
&&&&&&&&&&&&==&_MainTex_TexelSize.xy&*].x&=&v.texcoord.x&-].y&=&v.texcoord.y&-].x&=&v.texcoord.x&+].y&=&v.texcoord.y&-].x&=&v.texcoord.x&+].y&=&v.texcoord.y&+].x&=&v.texcoord.x&-].y&=&v.texcoord.y&+=&(_MainTex_TexelSize.y&&&=&&-=&tex2D(_MainTex,&i.uv[=&tex2D(_MainTex,&i.uv[=&tex2D(_MainTex,&i.uv[=&tex2D(_MainTex,&i.uv[====&(color1.a&+&color2.a&+&color3.a&+&color4.a)&*&defined(DEPTH_COMP_ON)&&&&&&&&&&&&&&&&&cDepth&=&oDepth&=
&&&&&&&&&&&&&&&&&(abs(oDepth&-&cDepth)&&&=&fixed4(,,,  注意:  1 我们只需要比较第一张模糊图的深度,后面的模糊都是根据这张再重新模糊,因此我们在着色器定义编译符,使之第一次与后面几次根据编译符不同的执行。  2 在深度比较的Shader中,我们其实已经取不到原顶点pos相应的值了,因为我们并不是渲染原来的模型,而是相当于Ogre中的后处理PassQuad(只渲染一个正方形),因此,在这之前,需要将主摄像根据情况,先把设定主摄像头的depthTextureMode为Depth,这样在OnPreRender之后,主摄像头正常渲染前,先调用UpdateDepthTexture,渲染场景内所有模型的深度到_CameraDepthTexture上,这样在后面的OnRenderImage中,我们才能取到正常的深度值。  3 在这,二张深度图里默认的精度都只有16位,因此需要定义一个范围。  有几次试错,都在于没搞清Unity里的执行过程,后来结合Untiy提供的Frame Debugger,才搞定这个简单的修改。
中国AR网()为更好的服务国内AR技术爱好者 ,现已推出“AR那些事”官方公众号,请在微信公众账号中搜索「AR网」或者加QQ群:,即可获得每日内容推送和最新的AR开发教程及AR H游戏资源哦!
上一篇: 下一篇:
有话您说 访客日访客日访客日访客日访客日HTTP/1.1 新建会话失败Unity3D Mesh小课堂(五)CombineMeshes合并网格
Unity3D Mesh小课堂(五)CombineMeshes合并网格
Unity3D Mesh
合并网格可以提升性能,而且也可以让我们更好更灵活的管理模型。
例如下面这三个模型:
有些时候我们会希望这三个模型使用同一个Collider,但是我们显然不能让美术再给我们专门为碰撞做模型来。因为他们可能会有不同的组合,或者跟其他的物体进行组合,如果每种组合都做一个碰撞模型的话,美术大人会砍死我们的,而且这样也不利于维护(调整一下坐标,这个碰撞模型就得重做)。
那么只有我们程序来实现了。
这里我们用到了Untiy的一个API——。
CombineMeshes有三个参数:
combine:(struct)类型的数组,这个结构里包括了需要合并的网格(mesh),子网格的索引(subMeshIndex)和转换矩阵(transform)。
mergeSubMeshes:bool值,是否需要将所有的Mesh合并成一个。
useMatrices:bool值,是否使用矩阵,如果为false,那么CombineInstance里的transform将会被忽略。
那么我们来实现这样一个功能。
我们选取图中某个对象做为父对象,将其他两个对象作为它的子对象。
并新建一个脚本,添加到父对象上。脚本如下:
using UnityE
using System.C
[RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))]
public class CombineMesh : MonoBehaviour {
void Start()
MeshFilter[] meshFilters = GetComponentsInChildren&MeshFilter& ();
CombineInstance[] combine = new CombineInstance[meshFilters.Length];
Material[] mats = new Material[meshFilters.Length];
Matrix4x4 matrix = transform.worldToLocalM
for (int i = 0; i & meshFilters.L i++) {
MeshFilter mf = meshFilters [i];
MeshRenderer mr = meshFilters [i].GetComponent&MeshRenderer& ();
if (mr == null) {
combine[i].mesh = mf.sharedM
combine[i].transform = mf.transform.localToWorldMatrix *
mr.enabled =
mats [i] = mr.sharedM
MeshFilter thisMeshFilter = GetComponent&MeshFilter& ();
Mesh mesh = new Mesh ();
mesh.name = &Combined&;
thisMeshFilter.mesh =
bineMeshes (combine, false);
MeshRenderer thisMeshRenderer = GetComponent&MeshRenderer& ();
thisMeshRenderer.sharedMaterials =
thisMeshRenderer.enabled =
MeshCollider thisMeshCollider = GetComponent&MeshCollider& ();
if (thisMeshCollider != null) {
thisMeshCollider.sharedMesh =
脚本里我们做了几件事情:
<span style="color:#、将MeshFilter里的保存给CombineInstance。
<span style="font-size:14 color:#、计算transform矩阵,将子对象(或本对象)本地转世界的矩阵和本对象世界转本地的矩阵相乘,就得到了子对象(或本对象)转换到本对象本地的矩阵。
<span style="color:#、将MeshRenderer的sharedMaterial保存到数组里(关于sharedMaterial可以参考我之前的)。并且将MeshRenderer设置为不可用的,这样子对象就不会再渲染了。如果这里换成gameObject.SetActive(false)是不恰当的,因为那样的话,gameObject上挂载的其他组件也不能执行。
<span style="font-size:14 color:#、新建一个mesh,赋给MeshFilter,并调用CombineMesh的方法合并子mesh。因为我们要用不同的Material,所以第二个参数mergeSubMeshes为false。(顺口一提,如果第三个参数useMatrices为false的话,所有mesh都会从local原点开始)
<span style="font-size:14 color:#、将Material数组赋&#20540;给MeshRenderer的sharedMaterials,并将MeshRenderer设置为可用的。
<span style="font-size:14 color:#、最后判断如果存在MeshCollider,将MeshCollider的sharedMesh赋&#20540;为新建的mesh。
最后要补充一点,如果本对象和所有子对象都是用相同的材质和纹理的话,那么这段代码就需要修改一下,把Material相关的代码去掉即可,然后CombineMesh的第二个参数要改为true(默认true)。当然,添加一个public的bool变量来控制是否使用同一个Material的话也是不错的选择。
附上可用的代码。
我的热门文章
即使是一小步也想与你分享Unity中Mesh分解与边缘高亮加上深度检测-爱编程
Unity中Mesh分解与边缘高亮加上深度检测
  一个比较简单的需求,不过遇到些坑,记录下。
  房间有多个模型,每个模型可能多个SubMesh,点击后,需要能具体到是那个SubMesh,并且在这个SubMesh上显示边缘高光,以及能个性这单个SubMesh对应的Material。如一个桌子的Mesh,其实有二个材质,分别对应二个SubMesh,一个桌面和一个桌脚,点击桌面后,只有这个桌面高光,而不是整个桌子,并且能单独更换这个桌面的Material.
  我们知道Unity中,Mesh和Ogre一样,也是可以有多个SubMesh,每个SubMesh有自己的Material,但是不同Ogre每个Submesh可以有不同的顶点数据,Unity中Mesh所有SubMesh共享相同顶点数据,分别使用不同的顶点索引。我原来做过一个项目,用Ogre里的Renderable与MovableObject组合形成这种格式,里面的所有模型都是用的这种格式显示,而不是Ogre本身的Entiy,当时就发现这种更容易理解,好用。
  下面这个脚本文件是这个功能的具体实现,包含分解Mesh,检查具体是那个SubMesh碰撞等功能。
using UnityE
using System.C
using System.Collections.G
using UnityEngine.EventS
public class RayCheck : MonoBehaviour
//public MaterialUI
public NewUIC
private Collider preC
private int cIndex = -1;
private Material lineMat = null;
private Material selectMat = null;
//private Material showMat =
private MeshFilter meshFilter = null;
private MeshRenderer meshRender = null;
private MeshCollider meshCollider = null;
private BoxCollider boxCollider = null;
private new Transform transform = null;
private LineRenderer lineRender = null;
private HighlightableObject hightLight = null;
private float vminDist = 1.0f;
private List&int& indexLay = new List&int&();
private bool bPreObject = false;
private int preIndex = 0;
private Mesh mesh = null;
//如果为true,所有模型都能切换texture
public bool defaultAdd = true;
private RaycastHit preHit = new RaycastHit();
private bool bHold = false;
private Vector3 oldLocation = Vector3.
private Dictionary&string, List&string&& matTextures = new Dictionary&string, List&string&&();
void Start()
lineMat = Resources.Load&Material&("LineMat");
//showMat = Resources.Load&Material&("ShowMat");
meshFilter = checkDefault&MeshFilter&();
meshCollider = checkDefault&MeshCollider&();
meshRender = checkDefault&MeshRenderer&();
boxCollider = checkDefault&BoxCollider&();
transform = checkDefault&Transform&();
lineRender = checkDefault&LineRenderer&();
hightLight = checkDefault&HighlightableObject&();
lineRender.useWorldSpace = false;
lineRender.sharedMaterial = lineM
lineRender.SetWidth(0.01f, 0.01f);
//meshRender.sharedMaterial = showM
//单独添加层,在正常渲染时,让摄像机不渲染这个模型,我们只需要在高光时渲染
this.gameObject.layer = 4;
mesh = new Mesh();
StartCoroutine(XmlReader.GetXML("materialtextures.xml", matTextures, XmlReader.ParseMatXml, this.InitUiMatTextures));
//ui.onApply = ApplyM
public void InitUiMatTextures()
ui.SetMatTextures(matTextures);
T checkDefault&T&() where T : Component
T t = this.gameObject.GetComponent&T&();
if (t == null)
t = this.gameObject.AddComponent&T&();
// Update is called once per frame
void Update()
//!ui.isActiveAndEnabled &&
#if UNITY_EDITOR
if (Input.GetMouseButtonDown(0) && !EventSystem.current.IsPointerOverGameObject())
#elif UNITY_ANDROID || UNITY_IPHONE
if (Input.touchCount & 0 && Input.GetTouch(0).phase == TouchPhase.Began
&& !EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId))
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
var bAxis = Physics.Raycast(ray, out hit, 10000.0f, 2 && 7);
if (bAxis)
bHold = true;
oldLocation = preCollider.transform.
//与当前camera最近交点
if (GetMinDist(ray, out hit))
if (preCollider != null)
lineRender.enabled = false;
//如果不是同一个模型,indexLay清空
bPreObject = hit.collider == preC
if (!bPreObject && preCollider != null)
preCollider.gameObject.SetActive(true);
indexLay.Clear();
preCollider = hit.
//得到选择的gameObject模型
if (checkIsRender(hit.collider, ray))
//preCollider.gameObject.SetActive(false);
if (selectMat != null)
var haveTexture = ui.SetSelectMat(selectMat);
//当前材质有对应能够更新的纹理
if (defaultAdd || haveTexture)
ui.gameObject.SetActive(true);
ui.gameObject.SetActive(false);
//显示高亮
hightLight.ReinitMaterials();
hightLight.FlashingOn(2f);
if (defaultAdd || haveTexture)
hightLight.On();
hightLight.Off();
#if UNITY_EDITOR
if (Input.GetMouseButtonUp(0))
#elif UNITY_ANDROID || UNITY_IPHONE
if (Input.touchCount & 0 && Input.GetTouch(0).phase == TouchPhase.Ended)
bHold = false;
public void FixedUpdate()
DragAxis();
public void DragAxis()
#if UNITY_EDITOR
if (bHold && Input.GetMouseButton(0))
#elif UNITY_ANDROID || UNITY_IPHONE
if (bHold && Input.touchCount & 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
var newPot = ray.origin + ray.direction * preHit.distance - preHit.
preCollider.transform.position = newP
public bool GetMinDist(Ray ray, out RaycastHit rayHit)
rayHit = new RaycastHit();
var hits = Physics.RaycastAll(ray);
var origin = Camera.main.transform.
float minDist = float.MaxV
bool result = false;
foreach (var hit in hits)
if (hit.collider == meshCollider || hit.collider == boxCollider)
var sqrLenght = (hit.point - origin).sqrM
if (sqrLenght & minDist)
minDist = sqrL
result = true;
public bool checkIsRender(Collider collider, Ray ray)
var render = collider.GetComponent&Renderer&();
var filter = collider.GetComponent&MeshFilter&();
if (render != null && filter != null)
//设置成当成位置
transform.position = render.transform.
transform.rotation = render.transform.
transform.localScale = render.transform.localS
transform.parent = render.transform.
//初始化信息
float minDist = float.MaxV
AABB minAABB = new AABB();
cIndex = 0;
selectMat = null;
mesh.Clear();
Collider currentCollider = null;
mesh.vertices = filter.mesh.
mesh.normals = filter.mesh.
mesh.uv = filter.mesh.
mesh.uv2 = filter.mesh.uv2;
//使用如下语句,颜色包含GI能正确使用,描边不能用,可能与UV有关。
//不使用,模型对应GI颜色不对,但是描边能用。
//解决方法: 定义raycheck自己的gameObject的层为单独一层,这样当前模型不渲染,只渲染描边
//meshRender.useLightProbes = render.useLightP
//meshRender.lightmapIndex = render.lightmapI
//meshRender.lightmapScaleOffset = render.lightmapScaleO
//meshRender.realtimeLightmapIndex = render.realtimeLightmapI
//meshRender.realtimeLightmapScaleOffset = render.realtimeLightmapScaleO
//如果有多个SubMesh,重新分割每个SubMesh,并重新验证相交,取最近subMesh
if (filter.mesh.subMeshCount & 1)
for (int meshIndex = 0; meshIndex & filter.mesh.subMeshC meshIndex++)
meshCollider.enabled = false;
boxCollider.enabled = false;
var indexs = filter.mesh.GetIndices(meshIndex);
mesh.SetIndices(indexs, filter.mesh.GetTopology(meshIndex), 0);
if (indexs.Length / 3 & 255)
boxCollider.enabled = true;
boxCollider.center = mesh.bounds.
boxCollider.size = mesh.bounds.
currentCollider = boxC
meshCollider.enabled = true;
meshCollider.sharedMesh =
currentCollider = meshC
if (currentCollider.Raycast(ray, out hit, 10000))
float sqrLenght = (Camera.main.transform.position - hit.point).sqrM
//模型有多个subMesh,但是无论怎么点击,其中一个subMesh总是最近。
if (Mathf.Abs(sqrLenght - minDist) & vminDist)
if (!indexLay.Contains(cIndex))
indexLay.Add(cIndex);
if (!indexLay.Contains(meshIndex))
indexLay.Add(meshIndex);
if (sqrLenght & minDist)
minDist = sqrL
cIndex = meshI
minAABB.Min = mesh.bounds.center - mesh.bounds.size / 2f;
minAABB.Max = mesh.bounds.center + mesh.bounds.size / 2f;
//一个模型有多个SubMesh,并且每个SubMesh边框相重。
if (indexLay.Count & 1 && preCollider)
if (indexLay.Contains(preIndex))
var nIndex = indexLay.IndexOf(preIndex);
cIndex = ++nIndex % indexLay.C
preIndex = cI
if (cIndex &= 0 && render.materials.Length & cIndex)
selectMat = render.materials[cIndex];
//显示自己的Mesh
var indexs = filter.mesh.GetIndices(cIndex);
mesh.SetIndices(indexs, filter.mesh.GetTopology(cIndex), 0);
meshFilter.mesh =
//重新设置材质
meshRender.material = selectM
var vertexs = minAABB.LinePositions();
lineRender.SetVertexCount(vertexs.Length);
lineRender.SetPositions(vertexs);
//重置状态
//lineRender.enabled =
meshRender.enabled = true;
return true;
return false;
public void ApplyMaterial()
meshRender.enabled = false;
ui.gameObject.SetActive(false);
public class AABB
private bool cornerDirty = true;
private Vector3 min = Vector3.
private Vector3 max = Vector3.
public Vector3[] mCorners = new Vector3[8];
public Vector3[] Corners
if (cornerDirty)
GetAllCorners();
public Vector3 Min
cornerDirty = true;
public Vector3 Max
cornerDirty = true;
private void makeFloor(Vector3 cmp)
if (cmp.x & min.x)
min.x = cmp.x;
if (cmp.y & min.y)
min.y = cmp.y;
if (cmp.z & min.z)
min.z = cmp.z;
private void makeCeil(Vector3 cmp)
if (cmp.x & max.x)
max.x = cmp.x;
if (cmp.y & max.y)
max.y = cmp.y;
if (cmp.z & max.z)
max.z = cmp.z;
public void Merge(Vector3 cmp)
makeCeil(cmp);
makeFloor(cmp);
cornerDirty = true;
public void SetNull()
min = Vector3.
max = Vector3.
cornerDirty = true;
/// &summary&
private void GetAllCorners()
mCorners[0] =
mCorners[1].x = min.x; mCorners[1].y = max.y; mCorners[1].z = min.z;
mCorners[2].x = max.x; mCorners[2].y = max.y; mCorners[2].z = min.z;
mCorners[3].x = max.x; mCorners[3].y = min.y; mCorners[3].z = min.z;
mCorners[4] =
mCorners[5].x = min.x; mCorners[5].y = max.y; mCorners[5].z = max.z;
mCorners[6].x = min.x; mCorners[6].y = min.y; mCorners[6].z = max.z;
mCorners[7].x = max.x; mCorners[7].y = min.y; mCorners[7].z = max.z;
public Vector3[] LinePositions()
int i = 0;
Vector3[] pos = new Vector3[16];
pos[i++] = this.Corners[0];
pos[i++] = this.Corners[1];
pos[i++] = this.Corners[2];
pos[i++] = this.Corners[3];
pos[i++] = this.Corners[0];
pos[i++] = this.Corners[6];
pos[i++] = this.Corners[7];
pos[i++] = this.Corners[3];
pos[i++] = this.Corners[2];
pos[i++] = this.Corners[4];
pos[i++] = this.Corners[7];
pos[i++] = this.Corners[6];
//左边 上边
pos[i++] = this.Corners[5];
pos[i++] = this.Corners[1];
pos[i++] = this.Corners[5];
pos[i++] = this.Corners[4];
public AABB Clone()
AABB ab = new AABB();
ab.min = this.
ab.max = this.
ab.cornerDirty = true;
  需要注意的点是:
  1&如果几个模型有多个SubMesh分散在各个位置,故需要把所有RaycastHit上碰撞点与眼睛求出最近点。
  2 LineRender中是N点组成N-1条线,而不是N/2,如A-B-C-D,并不是显示AB,CD.而是AB,BC,CD.
  3 模型的SubMesh可能边框重合,这样的话,就会导致可能永远都是选的其中一个。
  4 我们根据SubMesh生成新的Mesh,并不需要在主摄像头中渲染(通过Layer与cullingMask组合),不然和原来模型的SubMesh显示不清。
  5 鼠标按下,是否在UI上面,鼠标弹起,电脑与移动平台要不同的处理。
  6 安卓平台下,用WWW加载资源,必需用yield return,故相应加载完成的处理可以用函数指针传入。
  到这模型就差不多了,然后添加边缘高亮组件highightingSystem,这个的思路也是比较简单的。
  首先在主摄像机渲染场景前,把边缘高亮的模型给一个单独的层,并且修改相应材质为我们需要高亮的颜色,然后复制主摄像头新生成一个摄像头,新摄像头的cullingMask只渲染前面边缘高亮模型的层的那些模型到一张Stencil的RTT中保存,然后把原来的边缘高亮的模型的层和材质换回来。
  然后是主摄像头正常渲染,渲染完后,在OnRenderImage中先把在上面的那张RTT进行简单的Blur模糊,保存为Blur的RTT。最后把上面的Stencil的RTT,Blur的RTT,主摄像头渲染的source,我们并不渲染stencil本身,只渲染stencil模糊后的边缘部分。
  嗯,现在有个麻烦,老大要在看不到的部分不显示高亮,如下这样:
&  第一张图是现在的显示效果,老大要的是第二张,说实话,我最开始以为很简单,好吧,做完后就加了点东东,确实不复杂,但是因为对Unity的相关理解有误,把采过的坑说下。
  说实话,这个需求就是加个深度检测就行了,那么在原来基础上添加如下一些代码。
shaderCamera.CopyFrom(refCam);
shaderCamera.projectionMatrix = refCam.projectionM
// Uncomment this line if you have problems using Highlighting System with custom projection matrix on your camera
shaderCamera.cullingMask = layerM
shaderCamera.rect = new Rect(0f, 0f, 1f, 1f);
shaderCamera.renderingPath = RenderingPath.F
shaderCamera.hdr = false;
shaderCamera.useOcclusionCulling = false;
shaderCamera.backgroundColor = new Color(0f, 0f, 0f, 0f);
shaderCamera.clearFlags = CameraClearFlags.C
shaderCamera.targetTexture = stencilB
//我们因为直接在渲染highlight object,故可以直接算出深度,并不需要在前面多渲染一次
shaderCamera.depthTextureMode = DepthTextureMode.N
//通过culling mask(layerMask),只渲染highlight object
shaderCamera.Render();
//渲染深度
depthBuffer = RenderTexture.GetTemporary((int)GetComponent&Camera&().pixelWidth, (int)GetComponent&Camera&().pixelHeight, 16, RenderTextureFormat.RHalf);
shaderCamera.targetTexture = depthB
shaderCamera.RenderWithShader(DepthShader, null);
添加渲染深度。
  Shader.
Shader "Custom/Render depth buffer" {
Tags{ "RenderType" = "Opaque" }
ZWrite Off
ZTest Always
Lighting Off
Fog{ Mode Off }
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
//sampler2D_float _LastCameraDepthT
//sampler2D_float _CameraDepthT
struct v2f {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float depth : TEXCOORD1;
v2f vert(appdata_img v) {
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.texcoord. //float2(v.texcoord.x, 1 - v.texcoord.y); //v.texcoord.
o.depth = COMPUTE_DEPTH_01;
float4 frag(v2f i) : COLOR
//float depth = SAMPLE_DEPTH_TEXTURE(_LastCameraDepthTexture, i.uv);
//float depthSample = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_LastCameraDepthTexture, i.uv));//_CameraDepthTexture _LastCameraDepthTexture
//return float4(depthSample, 0, 0, 0);
return float4(i.depth,0,0,0);
FallBack Off
Render depth buffer
  在这我进行一次尝试,结果不对,在shaderCamera.Render()渲染之前,设定depthTextureMode为Depth,我在Shader开始应用_CameraDepthTexture,发现结果不对,网上查找说是这个RTT一直是主摄像头的,后面使用_LastCameraDepthTexture,结果很奇怪,和后面主摄像头的_CameraDepthTexture比对结果完全对不上,深度值不是0或1,但是渲染出来看,深度值又没看到变化。
  最后去Unity5Shader里面找_CameraDepthTexture这个RTT是如何渲染的,我们找到这个值COMPUTE_DEPTH_01是放入深度RTT中的,具体意思大家去unityCG.cginc里去找就行了,因为这个值就是根据当前顶点的位置算出来的,所以在这我们放入顶点着色器就行。
  然后就是在第一张Blur模糊图上比较上一张深度RTT的深度值。
// Downsamples source texture
private void DownSample4x(RenderTexture source, RenderTexture dest)
float off = 1.0f;
blurMaterial.SetFloat("_OffsetScale", off);
blurMaterial.SetTexture("_DepthTex", depthBuffer);
if (bBlueDepthTest)
blurMaterial.EnableKeyword("DEPTH_COMP_ON");
//blurMaterial.DisableKeyword("DEPTH_COMP_OFF");
Graphics.Blit(source, dest, blurMaterial);
渲染第一次Blur.
Shader "Hidden/Highlighted/Blur"
Properties
_MainTex("", 2D) = "" {}
_Intensity("", Range(0.25,0.5)) = 0.3
_DepthTex("", 2D) = "" {}
ZTest Always
ZWrite Off
Lighting Off
Fog { Mode Off }
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#pragma multi_compile __ DEPTH_COMP_ON
//DEPTH_COMP_OFF
#include "UnityCG.cginc"
uniform sampler2D _MainT
uniform half4 _MainTex_TexelS
uniform half _OffsetS
uniform fixed _I
#if defined(DEPTH_COMP_ON)
uniform sampler2D _DepthT
sampler2D_float _CameraDepthT
struct v2f
float4 pos : POSITION;
half2 duv : TEXCOORD0;
half2 uv[4] : TEXCOORD1;
v2f vert(appdata_img v)
// Shader code optimized for the Unity shader compiler
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
half2 offs = _MainTex_TexelSize.xy * _OffsetS
o.uv[0].x = v.texcoord.x - offs.x;
o.uv[0].y = v.texcoord.y - offs.y;
o.uv[1].x = v.texcoord.x + offs.x;
o.uv[1].y = v.texcoord.y - offs.y;
o.uv[2].x = v.texcoord.x + offs.x;
o.uv[2].y = v.texcoord.y + offs.y;
o.uv[3].x = v.texcoord.x - offs.x;
o.uv[3].y = v.texcoord.y + offs.y;
o.duv = v.texcoord.
if (_MainTex_TexelSize.y & 0)
o.duv.y = 1 - o.duv.y;
fixed4 frag(v2f i) : COLOR
fixed4 color1 = tex2D(_MainTex, i.uv[0]);
fixed4 color2 = tex2D(_MainTex, i.uv[1]);
fixed4 color3 = tex2D(_MainTex, i.uv[2]);
fixed4 color4 = tex2D(_MainTex, i.uv[3]);
color.rgb = max(color1.rgb, color2.rgb);
color.rgb = max(color.rgb, color3.rgb);
color.rgb = max(color.rgb, color4.rgb);
color.a = (color1.a + color2.a + color3.a + color4.a) * _I
#if defined(DEPTH_COMP_ON)
float cDepth = Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.duv));
float oDepth = tex2D(_DepthTex, i.duv).r;
//当Blur桢的深度 大于 当前桢的深度
if (abs(oDepth - cDepth) & 0.001)
color.rgba = fixed4(0,0,0,0);
Fallback off
Blur 添加深度比较
  注意:
  1 我们只需要比较第一张模糊图的深度,后面的模糊都是根据这张再重新模糊,因此我们在着色器定义编译符,使之第一次与后面几次根据编译符不同的执行。
  2 在这个Shader中,我们其实已经取不到顶点pos相应的值了,因为我们并不是渲染模型,而是相当于Ogre中的后处理PassQuad,因此,在这之前,需要将主摄像根据情况,先把设定主摄像头的depthTextureMode为Depth,这样在OnPreRender之后,主摄像头正常渲染前,先调用UpdateDepthTexture,渲染场景内所有模型的深度到_CameraDepthTexture上,这样在后面的OnRenderImage中,我们才能取到正常的深度值。
  有几次试错,都在于没搞清Unity里的执行过程,后来结合Untiy提供的Frame Debugger,才搞定这个简单的修改。
版权所有 爱编程 (C) Copyright 2012. . All Rights Reserved.
闽ICP备号-3
微信扫一扫关注爱编程,每天为您推送一篇经典技术文章。

我要回帖

更多关于 2017微信理财通安全吗 的文章

 

随机推荐