製作簡易碰撞體線框

製作簡易碰撞體線框

來自專欄高品質遊戲開發11 人贊了文章

前言:

之做過鏡頭上的線框,物體上的線框。現在做一個使用GL庫的線框,再做一個用幾何shader做的線框,之前用的是三角形來做。自帶的幾何著色器有,線點面都有。

第一個例子:

先用一個u3d內置的cube,再加入GL演算法。就是每線每線地造出來,其實 又要實時生成材質shader消耗相當的大代碼如下:本來網上是一個顯示碰撞體的例子,我改造了一下

優:可控性強,顯示不錯

缺:消耗大,而且不改線條寬窄。

不說這麼多上代碼:WireFrameDemo.cs

using UnityEngine;

public class WireFrameDemo : MonoBehaviour

{

public Color FrameDemoColor=Color.cyan;

void OnRenderObject()

{

CreateLineMaterial();

lineMaterial.SetPass(0);

GL.PushMatrix();

GL.MultMatrix(transform.localToWorldMatrix); //如果是自身的需要空間本地轉換

Vector3[] vertices = this.GetComponent<MeshFilter>().mesh.vertices;

//畫線

Vector3 p0 = vertices[1], p1 = vertices[0], p2 = vertices[6], p3 = vertices[7];

Vector3 p4 = vertices[3], p5 = vertices[2], p6 = vertices[4], p7 = vertices[5];

GL.Begin(GL.LINES);

GL.Color(FrameDemoColor);

GL.Vertex(p0);

GL.Vertex(p1);

GL.End();

GL.Begin(GL.LINES);

GL.Color(FrameDemoColor);

GL.Vertex(p1);

GL.Vertex(p2);

GL.End();

GL.Begin(GL.LINES);

GL.Color(FrameDemoColor);

GL.Vertex(p2);

GL.Vertex(p3);

GL.End();

GL.Begin(GL.LINES);

GL.Color(FrameDemoColor);

GL.Vertex(p0);

GL.Vertex(p3);

GL.End();

GL.Begin(GL.LINES);

GL.Color(FrameDemoColor);

GL.Vertex(p4);

GL.Vertex(p5);

GL.End();

GL.Begin(GL.LINES);

GL.Color(FrameDemoColor);

GL.Vertex(p5);

GL.Vertex(p6);

GL.End();

GL.Begin(GL.LINES);

GL.Color(FrameDemoColor);

GL.Vertex(p6);

GL.Vertex(p7);

GL.End();

GL.Begin(GL.LINES);

GL.Color(FrameDemoColor);

GL.Vertex(p4);

GL.Vertex(p7);

GL.End();

GL.Begin(GL.LINES);

GL.Color(FrameDemoColor);

GL.Vertex(p0);

GL.Vertex(p4);

GL.End();

GL.Begin(GL.LINES);

GL.Color(FrameDemoColor);

GL.Vertex(p1);

GL.Vertex(p5);

GL.End();

GL.Begin(GL.LINES);

GL.Color(FrameDemoColor);

GL.Vertex(p2);

GL.Vertex(p6);

GL.End();

GL.Begin(GL.LINES);

GL.Color(FrameDemoColor);

GL.Vertex(p3);

GL.Vertex(p7);

GL.End();

GL.PopMatrix();

}

static Material lineMaterial;

static void CreateLineMaterial()

{

if (!lineMaterial)

{

// Unity3d使用該默認的Shader作為線條材質

Shader shader = Shader.Find("Hidden/Internal-Colored");

lineMaterial = new Material(shader);

lineMaterial.hideFlags = HideFlags.HideAndDontSave;

// 開啟 alpha blending

lineMaterial.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);

lineMaterial.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);

// 開啟背面遮擋

lineMaterial.SetInt("_Cull", (int)UnityEngine.Rendering.CullMode.Off);

// Turn off depth writes

lineMaterial.SetInt("_ZWrite", 0);

}

}

}

說完腳本的方式生成,我們可以直接用geo 幾何 shader來做。先上一個三角邊的

先上三角邊的:

圖片有漸變色效果好

// Upgrade NOTE: replaced mul(UNITY_MATRIX_MVP,*) with UnityObjectToClipPos(*)

優:只要一個cube的meshfilter就行,效果不差,運行快

缺:只用4.0以上shader才行,線框大小不可控,不是我們需要四邊形模型

Shader "MyCC/ThickLine2"

{

Properties

{

_Color("Main Color", Color) = (1,1,1,1)

}

SubShader

{

Pass

{

CGPROGRAM

#pragma target 5.0

#pragma vertex vert

#pragma fragment frag

#pragma geometry geom

struct v2g

{

float4 vertex : SV_POSITION;

};

struct g2f

{

float4 pos: POSITION;

float4 c: COLOR;

};

fixed4 _Color;

v2g vert (float4 position : POSITION)

{

v2g o;

o.vertex = position;

return o;

}

[maxvertexcount(3)]

void geom(lineadj v2g p[4], inout LineStream<g2f> triStream)

{

//float4x4 vp = UnityObjectToClipPos(_World2Object);

g2f o;

float4 pos0 = UnityObjectToClipPos(p[0].vertex);

float4 pos1 = UnityObjectToClipPos(p[1].vertex);

float4 pos2 = UnityObjectToClipPos(p[2].vertex);

// float4 pos3 = UnityObjectToClipPos(p[3].vertex);

o.pos = pos0;

o.c = half4(1,0,0,1);

triStream.Append(o);

o.pos = pos1;

o.c = half4(0,1,0,1);

triStream.Append(o);

o.pos = pos2;

o.c = half4(1,1,0,1);

triStream.Append(o);

triStream.RestartStrip();

}

fixed4 frag (g2f i) : SV_Target

{

return i.c;

}

ENDCG

}

}

}

最終版:

上面的優缺點都一樣,就是這個不可支持所有模型都是4邊形顯示,因為三角化,模型發生在大的轉變

Shader "MyCC/ThickLine3"

{

Properties

{

_StartColor("Start Color", Color) = (1,0,0,1)

_EndColor("End Color", Color) = (0,1,0,1)

}

SubShader

{

Pass

{

CGPROGRAM

#pragma target 5.0

#pragma vertex vert

#pragma fragment frag

#pragma geometry geom

struct v2g

{

float4 vertex : SV_POSITION;

};

struct g2f

{

float4 pos: POSITION;

float4 c: COLOR;

};

fixed4 _StartColor,_EndColor;

v2g vert (float4 position : POSITION)

{

v2g o;

o.vertex = position;

return o;

}

[maxvertexcount(3)]

void geom(lineadj v2g p[4], inout LineStream<g2f> triStream)

{

g2f o;

float4 pos0 = UnityObjectToClipPos(p[0].vertex);

float4 pos1 = UnityObjectToClipPos(p[1].vertex);

float4 pos2 = UnityObjectToClipPos(p[2].vertex);

//下面是我想的三種去除對角線的方法,都可以在u3d上使用

//先說 對角線法 ,

//第一種,求連線長度,不可以大於(根號2=1.414213562373095),用1.4代替

//float dis01 = distance(p[0].vertex,p[1].vertex);

//float dis02 = distance(p[0].vertex,p[2].vertex);

//float dis12 = distance(p[1].vertex,p[2].vertex);

//if(dis01>1.4 && dis12>1.4 || dis02>1.4)

if(p[1].vertex.x==0.5&&p[1].vertex.y==-0.5||p[0].vertex.y==0.5&&p[0].vertex.z==-0.5&&p[1].vertex.x==0.5)//第二種續個排查法,一點排查開,只排查0,其他不排查,難點在"||"

{

o.pos = pos0;

o.c = _StartColor;

triStream.Append(o);

}

//第三種,因為線框向量,如果dot 點乘為0,那麼必定垂直

//有個比較反人類的是,上面的對角線都也是垂直的線,垂直於一個平面上面的線必須也垂直

//float3 dis01 =p[0].vertex-p[1].vertex;

//float3 dis12 = p[1].vertex-p[2].vertex;

//if(dot(dis12,dis01)==0)

//{

// o.pos = pos0;

// o.c = _StartColor;

// triStream.Append(o);

//}

//其他演算法,也可以算.x==.y或者.z,因為.x與.y同時不為0時才能顯示。。。。

o.pos = pos1;

o.c = _EndColor;

triStream.Append(o);

o.pos = pos2;

o.c = _StartColor;

triStream.Append(o);

triStream.RestartStrip();

}

fixed4 frag (g2f i) : SV_Target

{

return i.c;

}

ENDCG

}

}

}


推薦閱讀:

TAG:Unity遊戲引擎 | shader | 計算機圖形學 |