今天我们就系统的看一下unity3d编辑器和插件制作,不过有点长,想要学习的话就要耐心看了。好首先我们来想下 IOS 和android的 控件都是以四边形基础的。
接下来 我们来转像unity,在unity中 我们怎么去建立一个四边形那, 依照图形绘制的原理。三点一面的理论。我们可以使用6个点来建立一个两三角形组成的四边形。
我们先学会怎么去绘制一个view,也就是简单的一个色面。
我们知道 unity中得面也是采取这种的绘制方法,绘制一个面就会多一个drawcall,为了面绘制的节省,我们就会使用面合并的原理,来减少drawcall的产生(opengl自动处理)。
好,我们来定义六个点:
好了 有了这些东西 现在制作一个没有任何颜色的几条线组成的线框。
我们为了让这个面有颜色,必学要有 法线 和 材质,shader 这样才是一个完整的 色面。
法线
源码奉上!
公用类!
在unity中图片的种类分了很多,默认是:Texture, 还有其他的一些属性。
wrap mode 这个是图片选择 图片时候四方连续是会用到,也可以减轻,图片白边的影响。
filter mode 是 图片的 文件模式,说白一点就是 点,两角线,三角线。。越高图片质量越大,内存也就越高。
anise level 说白了 这个 我还没用到 ,貌似是位图才会用到。
max size 最大支持图片(注意哦是最大哦,假如我的图是100*100的 你选择1024 没关系的 不会浪费 内存的,因为这里说的是最大的图集支持,如果你的图片超过了1024,那这个值也要跟着变。)
Non power of 2 :如果你不想你的图变成 正方形符合2的n次方的图,就选择none,这样可以保证你图的大小的合理性。不然选自动适应,最大适应,最小适应。
cubemap: 一般不使用,这个是用在模型上面的贴图。
read/w:是否支持读写,建议勾选。
其他看下文档。
format:一般我们用32位的,也可以选择16位的。减少内存。
最后 送一句话,小图尽量拼成大图,对UV(也可以使用NGUI的自动压缩图,也可以自己压缩,后面会讲怎么制作自己的图集),大图最好不要超过1024,面的数量尽量的减少,尽量使面合并。 目的减少内存,减少drawcall。
好,下一步。我们开始做把图片渲染到场景里面。
前面讲了,我们绘制片,下面,我们做的之需要两部。
1.把shader换掉,前面使用的是,纯色的shader,下面我们将使用,带贴图的shader。
2. 前面我们使用的是固定的宽和高,因为图片的大小不是固定的,所以我们要把比例进行适配一下。
上代码:
shader部分,很简单:
unity中检测点击事件,使用NGUI的可能知道,NGUI使用的就是SendMessage的方式来进行事件的传递。没错,这也是 unity最为简便的方式,
(要注意一个问题哦,这个方式 如果 你要使用 大于 万次循环的话 会有延迟的哦,一般也不会同时发送万条事件的)。
我们知道了 事件的传送的方式,那么我们就开始制作这个规则,首先 要使用SendMessage的话我们要拿到gameobject的对象才能使用。
所以我们要想办法拿到点击的那个物体。怎么坐那,原理其实很简单,就是射线。我们都知道,unity的射线是用来探测使用的 正好,我们所有可以看到的物体都是存在camera下面,那么我们就可以使用,从camera上发射射线,来达到检测物体的作用,物体要有碰撞体哦。
先贴部分代码等这个章节完了我会贴完整的代码
说白了 就是button就来处理 摄像机发来的东西。虽然很简单的一句话,但我们写得东西还是有很多的。
依然,button还是继承前面的view
接下来 我们来转像unity,在unity中 我们怎么去建立一个四边形那, 依照图形绘制的原理。三点一面的理论。我们可以使用6个点来建立一个两三角形组成的四边形。
我们先学会怎么去绘制一个view,也就是简单的一个色面。
我们知道 unity中得面也是采取这种的绘制方法,绘制一个面就会多一个drawcall,为了面绘制的节省,我们就会使用面合并的原理,来减少drawcall的产生(opengl自动处理)。
好,我们来定义六个点:
- [csharp]
- public static int[] initTri(){
- int[] triangle = new int[6];
- triangle [0] = 0;
- triangle [1] = 2;
- triangle [2] = 1;
- triangle [3] = 2;
- triangle [4] = 3;
- triangle [5] = 1;
- return triangle;
- }
- [csharp]
- public static Vector3 [] initVertice(float width ,float height,float ancPointx,float ancPointY){
- Vector3 [] viewVer = new Vector3[4];
- viewVer [0] = new Vector3 (-ancPointx*-width,-ancPointY*height,0);
- viewVer [1] = new Vector3 ((1-ancPointx)*-width,-ancPointY*height,0);
- viewVer [2] = new Vector3 (-ancPointx*-width,(1-ancPointY)*height,0);
- viewVer [3] = new Vector3 ((1-ancPointx)*-width,(1-ancPointY)*height,0);
- return viewVer;
- }
好了 有了这些东西 现在制作一个没有任何颜色的几条线组成的线框。
我们为了让这个面有颜色,必学要有 法线 和 材质,shader 这样才是一个完整的 色面。
法线
- [csharp]
- public static Vector3[] initNormal(){
- Vector3[] normals = new Vector3[4];
- normals[0] = -Vector3.forward;
- normals[1] = -Vector3.forward;
- normals[2] = -Vector3.forward;
- normals[3] = -Vector3.forward;
- return normals;
- }
- [csharp]
- public static Vector2 [] initUV(){
- Vector2 [] uv = new Vector2[4];
- uv[0] = new Vector2(0, 0);
- uv[1] = new Vector2(1, 0);
- uv[2] = new Vector2(0, 1);
- uv[3] = new Vector2(1, 1);
- return uv;
- }
源码奉上!
公用类!
- [csharp]
- using UnityEngine;
- using System.Collections;
- public class InitBase : MonoBehaviour {
- public static Vector3 [] initVertice(float width ,float height,float ancPointx,float ancPointY){
- Vector3 [] viewVer = new Vector3[4];
- viewVer [0] = new Vector3 (-ancPointx*-width,-ancPointY*height,0);
- viewVer [1] = new Vector3 ((1-ancPointx)*-width,-ancPointY*height,0);
- viewVer [2] = new Vector3 (-ancPointx*-width,(1-ancPointY)*height,0);
- viewVer [3] = new Vector3 ((1-ancPointx)*-width,(1-ancPointY)*height,0);
- return viewVer;
- }
- public static int[] initTri(){
- int[] triangle = new int[6];
- triangle [0] = 0;
- triangle [1] = 2;
- triangle [2] = 1;
- triangle [3] = 2;
- triangle [4] = 3;
- triangle [5] = 1;
- return triangle;
- }
- public static Vector3[] initNormal(){
- Vector3[] normals = new Vector3[4];
- normals[0] = -Vector3.forward;
- normals[1] = -Vector3.forward;
- normals[2] = -Vector3.forward;
- normals[3] = -Vector3.forward;
- return normals;
- }
- public static Vector2 [] initUV(){
- Vector2 [] uv = new Vector2[4];
- uv[0] = new Vector2(0, 0);
- uv[1] = new Vector2(1, 0);
- uv[2] = new Vector2(0, 1);
- uv[3] = new Vector2(1, 1);
- return uv;
- }
- }
- [csharp]
- using UnityEngine;
- using System.Collections;
- [RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
- [ExecuteInEditMode]
- public class VKView : MonoBehaviour {
- Mesh viewMesh;
- Material viewDefultMat;
- bool isChange;
- [HideInInspector] public float ancPointx=0.5f,ancPointy = 0.5f;
- [HideInInspector] public int width = 100,height = 100;
- public string test;
- // Use this for initialization
- void Start () {
- viewDefultMat = new Material (Shader.Find ("VK/VKViewShader"));
- gameObject.GetComponent<MeshRenderer> ().sharedMaterial = viewDefultMat;
- viewMesh = new Mesh ();
- gameObject.GetComponent<MeshFilter> ().mesh = viewMesh;
- updateView();
- }
- public void updateView(){
- if (viewDefultMat != null) {
- viewMesh.vertices = InitBase.initVertice(width,height,ancPointx,ancPointy);
- viewMesh.triangles = InitBase.initTri();
- viewMesh.normals = InitBase.initNormal();
- viewMesh.uv = InitBase.initUV();
- }
- }
- #if UNITY_EDITOR
- void OnDrawGizmosSelected(){
- Gizmos.color = Color.blue;
- Gizmos.DrawWireCube (transform.position,new Vector3(width,height,0f));
- }
- #endif
- }
- [csharp]
- using UnityEngine;
- using System.Collections;
- using UnityEditor;
- [CustomEditor(typeof(VKView))]
- [ExecuteInEditMode]
- public class VKViewEditor : Editor {
- public override void OnInspectorGUI ()
- {
- base.OnInspectorGUI ();
- VKView vkView = (VKView)target;
- // vkView.tex = EditorGUILayout.ObjectField ("Texture",vkView.tex,typeof(Texture),true)as Texture;
- vkView.width=EditorGUILayout.IntField("Width",vkView.width);
- vkView.height=EditorGUILayout.IntField("Height",vkView.height);
- vkView.test = EditorGUILayout.TextField("面板显示的名字:",vkView.test);
- vkView.updateView ();
- EditorUtility.SetDirty(vkView);
- EditorUtility.UnloadUnusedAssets();
- }
- }
- [csharp]
- Shader "VK/VKViewShader" {
- Properties {
- _Color ("Main Color", Color) = (1,1,1,1)
- }
- SubShader {
- Pass {
- Cull Front
- Color [_Color]
- }
- }
- }
现在我们来讲述下,怎么绘制一个图片在场景里面。
首先 我们先做下图片的功课。在unity中图片的种类分了很多,默认是:Texture, 还有其他的一些属性。
有些人可以会遇到 我放进去的素材为什么编译之后会变模糊那,这是由于,在unity中你没有修改图片的属性,导致的。
在 texture模式下,
我们来分析下这种图片的属性,wrap mode 这个是图片选择 图片时候四方连续是会用到,也可以减轻,图片白边的影响。
filter mode 是 图片的 文件模式,说白一点就是 点,两角线,三角线。。越高图片质量越大,内存也就越高。
anise level 说白了 这个 我还没用到 ,貌似是位图才会用到。
max size 最大支持图片(注意哦是最大哦,假如我的图是100*100的 你选择1024 没关系的 不会浪费 内存的,因为这里说的是最大的图集支持,如果你的图片超过了1024,那这个值也要跟着变。)
format 这个就是 压缩模式了,决定内存的最重要的部分,三个选项,自动压缩(最节省),16位压缩(还可以说的过去),真彩色可以说没有压缩,保证质量的同时内存相应的增大了。
Non power of 2 :如果你不想你的图变成 正方形符合2的n次方的图,就选择none,这样可以保证你图的大小的合理性。不然选自动适应,最大适应,最小适应。
cubemap: 一般不使用,这个是用在模型上面的贴图。
read/w:是否支持读写,建议勾选。
其他看下文档。
format:一般我们用32位的,也可以选择16位的。减少内存。
最后 送一句话,小图尽量拼成大图,对UV(也可以使用NGUI的自动压缩图,也可以自己压缩,后面会讲怎么制作自己的图集),大图最好不要超过1024,面的数量尽量的减少,尽量使面合并。 目的减少内存,减少drawcall。
好,下一步。我们开始做把图片渲染到场景里面。
前面讲了,我们绘制片,下面,我们做的之需要两部。
1.把shader换掉,前面使用的是,纯色的shader,下面我们将使用,带贴图的shader。
2. 前面我们使用的是固定的宽和高,因为图片的大小不是固定的,所以我们要把比例进行适配一下。
上代码:
shader部分,很简单:
- [cpp]
- Shader "VK/VKTextureShader" {
- Properties {
- _Color ("Main Color", COLOR) = (1,1,1,1)
- _MainTex ("Base (RGB) Trans (A)", 2D) =""{}
- }
- SubShader {
- Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
- Pass {
- Blend SrcAlpha OneMinusSrcAlpha
- Cull off
- SetTexture [_MainTex] {
- constantColor [_Color]
- Combine texture *constant
- }
- }
- }
- }
- [cpp]
- using UnityEngine;
- using System.Collections;
- public class VKImageView : VKView {
- Material imgViewDefultMat;
- Mesh imgViewDefultMesh;
- [HideInInspector] public Texture imgViewTex,highLightedTex;
- [HideInInspector] public float scale =1;
- [HideInInspector] public string info= null;
- [HideInInspector] public bool highLighted = false;
- [HideInInspector] public float alpha =1;
- // Use this for initialization
- void Start () {
- imgViewDefultMat = new Material (Shader.Find("VK/VKTextureShader"));
- imgViewDefultMesh = new Mesh ();
- GetComponent<MeshFilter> ().mesh = imgViewDefultMesh;
- GetComponent<MeshRenderer>().material = imgViewDefultMat;
- updateImageView ();
- }
- public void updateImageView(){
- if(imgViewTex!=null){
- if(!highLighted){
- if(imgViewDefultMat!=null)
- imgViewDefultMat.mainTexture = imgViewTex;
- if(imgViewDefultMesh!=null)
- imgViewDefultMesh.vertices = InitBase.initVertice(imgViewTex.width *scale,imgViewTex.height*scale,ancPointx,ancPointy);
- height = imgViewTex.height;
- width = imgViewTex.width;
- }else{
- if(imgViewDefultMat!=null)
- imgViewDefultMat.mainTexture = highLightedTex;
- if(imgViewDefultMesh!=null)
- imgViewDefultMesh.vertices = InitBase.initVertice(highLightedTex.width *scale,highLightedTex.height*scale,ancPointx,ancPointy);
- height = highLightedTex.height;
- width = highLightedTex.width;
- }
- }else{
- if(imgViewDefultMat!=null)
- imgViewDefultMat.mainTexture = null;
- if(imgViewDefultMesh!=null)
- imgViewDefultMesh.vertices = InitBase.initVertice(width*scale,height*scale,ancPointx,ancPointy);
- }
- if(imgViewDefultMat!=null){
- Color newcolor = imgViewDefultMat.color;
- imgViewDefultMat.color = new Color(newcolor.r,newcolor.g,newcolor.b,alpha);
- }
- if(imgViewDefultMesh!= null){
- imgViewDefultMesh.triangles = InitBase.initTri ();
- imgViewDefultMesh.normals = InitBase.initNormal();
- imgViewDefultMesh.uv = InitBase.initUV();
- }
- }
- public void switchButton(){ //后面会讲到,可以先删掉,这个是转化按钮来用的。
- VKButton button = gameObject.AddComponent<VKButton> ();
- button.buttonDefultMesh = imgViewDefultMesh;
- button.buttonDefultMat = imgViewDefultMat;
- button.buttonTex = imgViewTex;
- button.pressButtonTex = highLightedTex;
- button.info = info;
- button.scale = scale;
- button.ancPointx = ancPointx;
- button.ancPointy = ancPointy;
- button.updateButton ();
- DestroyImmediate (GetComponent<VKImageView>());
- }
- }
- [cpp]
- using UnityEngine;
- using System.Collections;
- using UnityEditor;
- [CustomEditor(typeof(VKImageView))]
- public class VKImageViewEditor : Editor {
- public override void OnInspectorGUI ()
- {
- base.OnInspectorGUI ();
- VKImageView imgView = (VKImageView)target;
- imgView.imgViewTex = EditorGUILayout.ObjectField ("ImageTexture",imgView.imgViewTex,typeof(Texture),true)as Texture;
- imgView.highLightedTex = EditorGUILayout.ObjectField ("HighLightedTex",imgView.highLightedTex,typeof(Texture),true)as Texture;
- imgView.alpha = EditorGUILayout.Slider("Alpha",imgView.alpha,0.0f,1.0f);
- imgView.highLighted = EditorGUILayout.Toggle ("highLighted",imgView.highLighted);
- imgView.info = EditorGUILayout.TextField ("info",imgView.info);
- imgView.ancPointx = EditorGUILayout.Slider("AnchorX",imgView.ancPointx,0.0f,1.0f);
- imgView.ancPointy = EditorGUILayout.Slider("AnchorY",imgView.ancPointy,0.0f,1.0f);
- if(imgView.imgViewTex == null){
- imgView.width=EditorGUILayout.IntField("Width",imgView.width);
- imgView.height=EditorGUILayout.IntField("Height",imgView.height);
- }
- GUILayout.BeginHorizontal();
- if(GUILayout.Button("2X")){
- imgView.scale = 0.5f;
- }
- if(GUILayout.Button("1X")){
- imgView.scale = 1f;
- }
- if(GUILayout.Button("1.5X")){
- imgView.scale = 0.75f;
- }
- GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal();
- if(GUILayout.Button("ChangeName")){
- if(imgView.imgViewTex!=null){
- imgView.name = imgView.imgViewTex.name;
- }
- }
- if(GUILayout.Button("SwitchButton")){
- imgView.switchButton();
- }
- GUILayout.EndHorizontal();
- imgView.updateImageView();
- if(imgView!=null)
- EditorUtility.SetDirty (imgView);
- EditorUtility.UnloadUnusedAssets ();
- }
- }
这里我们要了解 unity的机制,button属性必须有的属性等。
首先 我们先说下 unity的机制:unity中检测点击事件,使用NGUI的可能知道,NGUI使用的就是SendMessage的方式来进行事件的传递。没错,这也是 unity最为简便的方式,
(要注意一个问题哦,这个方式 如果 你要使用 大于 万次循环的话 会有延迟的哦,一般也不会同时发送万条事件的)。
我们知道了 事件的传送的方式,那么我们就开始制作这个规则,首先 要使用SendMessage的话我们要拿到gameobject的对象才能使用。
所以我们要想办法拿到点击的那个物体。怎么坐那,原理其实很简单,就是射线。我们都知道,unity的射线是用来探测使用的 正好,我们所有可以看到的物体都是存在camera下面,那么我们就可以使用,从camera上发射射线,来达到检测物体的作用,物体要有碰撞体哦。
先贴部分代码等这个章节完了我会贴完整的代码
- [cpp]
- Ray cameraRay;
- RaycastHit hit;
- Vector3 touchPos,pressOffSet;
- public static GameObject touchObj = null;
- public static VKCamera shareVkCamera;
- [cpp]
- void Update ( {
- #if UNITY_EDITOR
- if(Input.GetMouseButtonDown(0){
- onPressDown(Input.mousePosition);
- }else if(Input.GetMouseButtonUp(0)){
- onPressUp(Input.mousePosition);
- }else if(Input.GetMouseButton(0)){
- onDrag(Input.mousePosition);
- }
- #endif
- #if UNITY_IPHONE || UNITY_ANDROID
- Touch touch;
- if(Input.touchCount==1){
- touch = Input.GetTouch (0);
- switch(touch.phase){
- case TouchPhase.Began:
- onPressDown(touch.position);
- break;
- case TouchPhase.Moved:
- onPressUp(touch.position);
- break;
- case TouchPhase.Ended:
- case TouchPhase.Canceled:
- onDrag(touch.position);
- break;
- }
- }
- #else
- if(Input.GetMouseButtonDown(0)){
- onPressDown(Input.mousePosition);
- }else if(Input.GetMouseButtonUp(0)){
- onPressUp(Input.mousePosition);
- }else if(Input.GetMouseButton(0)){
- onDrag(Input.mousePosition);
- }
- #endif
- }
- [cpp]
- public void onPressDown(Vector2 vec){
- touchPos = vec;
- for(int i=0 ; i<Camera.allCameras.Length;i++){
- cameraRay = Camera.allCameras[i].ScreenPointToRay(touchPos);
- if(Physics.Raycast(cameraRay,out hit,9999,Camera.allCameras[i].cullingMask) && touchObj == null){
- touchObj = hit.transform.gameObject;
- if(touchObj!=null && touchObj.GetComponent<VKButton>()){
- touchPos = Camera.allCameras[i].ScreenToWorldPoint(touchPos);
- pressOffSet =touchObj.transform.position-touchPos;
- VKButton button = touchObj.GetComponent<VKButton>();
- if(!iSNull(button.pressEventName) && button.eventObj!=null)
- button.eventObj.SendMessage(button.pressEventName,button);
- if(button.pressButtonTex!=null){
- button.renderer.sharedMaterial.mainTexture = button.pressButtonTex;
- }
- if(button.isDrag && !iSNull(button.dragStartEventName)){
- button.eventObj.SendMessage(button.dragStartEventName,vec);
- }
- if(button.isAni){
- button.SendMessage("onPressAni");
- }
- }
- }
- }
- }
- [cpp]
- public void onPressUp(Vector2 vec){
- if(touchObj!=null){
- VKButton button = touchObj.GetComponent<VKButton>();
- if(button!=null){
- if(button.buttonTex!=null){
- touchObj.renderer.sharedMaterial.mainTexture = touchObj.GetComponent<VKButton>().buttonTex;
- }
- if(!iSNull(button.clickEventName) && button.eventObj!=null){
- button.eventObj.SendMessage(button.clickEventName,button);
- }
- if(button.isDrag && !iSNull(button.dragEndEventName)){
- button.SendMessage(button.dragEndEventName,vec);
- }
- if(button.isAni){
- button.SendMessage("onClickAni");
- }
- }
- touchObj = null;
- }
- }
- [cpp]
- public void onDrag(Vector2 vec){
- if(touchObj!=null){
- VKButton button = touchObj.GetComponent<VKButton>();
- if(button!=null && button.isDrag){
- for(int i= 0;i<Camera.allCameras.Length;i++){
- Vector2 worldVec = Camera.allCameras[i].ScreenToWorldPoint(vec);
- touchObj.transform.position = new Vector3(worldVec.x+pressOffSet.x,worldVec.y+pressOffSet.y,touchObj.transform.position.z);
- if(!iSNull(button.dragEventName))
- button.eventObj.SendMessage(button.dragEventName,worldVec);
- }
- }
- }
- }
- [cpp]
- bool iSNull(string eventName){
- bool buttonIsNull = false;
- if(eventName== null || eventName.Equals("null")){
- buttonIsNull =true;
- }
- return buttonIsNull;
- }
- [cpp]
- public void initVKCamere(){
- gameObject.name = "VKCamere";
- this.camera.orthographic = true;
- this.camera.backgroundColor = Color.black;
- this.camera.nearClipPlane = 0;
- this.camera.farClipPlane = 9999;
- this.camera.orthographic =true;
- this.camera.orthographicSize = getCameraSize ();
- this.transform.position = new Vector3(0,0,-1000);
- this.transform.rotation = Quaternion.Euler(Vector3.zero);
- this.transform.localScale = Vector3.one;
- Application.targetFrameRate=60;
- if(GetComponent<AudioListener>()){
- //DestroyImmediate(GetComponent<AudioListener>());
- }
- }
- int getCameraSize(){
- int size = 384;
- bool isLandscape=(Camera.main.pixelWidth>Camera.main.pixelHeight);
- float rad = Camera.main.pixelWidth/Camera.main.pixelHeight;
- bool isIPad= (Mathf.Abs(rad-1.3333f)<0.001f) || (Mathf.Abs(rad-0.75f)<0.001f);
- if(isIPad){
- if(isLandscape){
- size=400;
- }else{
- size=533;
- }
- }else{
- if(isLandscape){
- size=400;
- }else{
- //iPhone 5
- if(Camera.main.pixelHeight/Camera.main.pixelWidth>1.6){
- size=710;
- }else{
- size=600;
- }
- }
- }
- return size;
- }
- [cpp]
- using UnityEditor;
- using UnityEngine;
- using System.Collections;
- [CustomEditor(typeof(VKCamera))]
- public class VKCameraEditor : Editor {
- public override void OnInspectorGUI (){
- base.OnInspectorGUI();
- VKCamera vkCamere = (VKCamera)target;
- if(GUILayout.Button("ReSetCamera")){
- vkCamere.initVKCamere();
- }
- EditorUtility.SetDirty(vkCamere);
- EditorUtility.UnloadUnusedAssets();
- }
- }
说白了 就是button就来处理 摄像机发来的东西。虽然很简单的一句话,但我们写得东西还是有很多的。
依然,button还是继承前面的view