加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

46.Mesh与Shader

(2014-09-23 21:25:17)
标签:

it

分类: libGDX开发教程
本文使用的libgdx是1.2.0版本,可能和最新版有一些不同地方。全文内容仅供参考。

很早之前在我的教程中,给大家讲解了有关于图元mesh的内容,但是并不是很详尽,仅仅是讲解了有关于图元的一些使用,那么今天我们就来讲解下libGDX中Mesh与Shader的内容,以为这个对于我们开发者来说,是很重要的,所以今天我们就来学习下它。关于此讲的视频教程,情点击链接进行观看:本集视频

Libgdx游戏引擎(1群):187378034
Libgdx游戏引擎(2群):148848483
Libgdx游戏引擎(3群): 791684

                       视频教程

1.VertexAttributes 类

如果要介绍Mesh的话,那么就必须要先讲解下VertexAttributes,他的意思是“顶点数据”,熟悉3D模型的同学,可能都了解,mesh其实不仅仅是平面2D的东西,在3D方面也是可以使用的。既然mesh是网格,那么他就需要有顶点来确定这个mesh,下面我们就来介绍下 vertexAttributes ---- 顶点数据

PS这个类了解就行,一般都是用他的内部类。

预定义名称:

libGDX是基于OpenGL的游戏引擎,这个mesh也是OpenGL带过来的,在OpenGL中规定我们在使用mesh的时候,必须先确定其中组成元素的属性。VertexAttributes 即顶点数据,它指定了每个顶点的各种属性数据。在OpenGL ES1.0中,顶点属性有四个预定义的名字:position(位置), normal(法线), color(颜色), 和 texture coordinates(纹理坐标)在OpenGL ES2.0中,用户必须定义“顶点属性的名字”,这个也是目前0.98版本libGDX中新增加的一项。

构造方法:

VertexAttributeint usage, int numComponents, java.lang.String alias) 

   第一个参数:储存顶点的数据类型

   第二个参数:数据元素的组成个数,范围 1 - 4。

   第三个参数:数据名称,也是在shader中使用该元素的“别名”,构建后可以修改

功能方法:(这里介绍的是较为常用的VertexAttributes的方法

(1)VertexAttributes.Usage :内部类,常用主要是其中集合了几个常用的预定义的名称其实就是你要用它储存的数据类型,例如是位置型、颜色型等。

(2)equals (Object obj): 不常用,Object的方法,这里不赘述了。

(3)get(int index) :不常用,获取当前索引号,这个我们在下面会讲到。

(4)findByUsage(int usage) :返回使用到Usage,中的第一个Usage类型。

(5)getOffset(int usage)  :返回的好像是一个位置,这个土豆不是很清楚。不过,如果Mesh使用了顶点缓存(vertex buffer) ,那么这个获取的就是指定绘制的起端。

(6)size() 返回的是一个int类型,找到顶点数据的个数。

VertexAttributes.Usage 类

这是一个内部类,比较常用,所以土豆这里特别拿出来讲解下。

功能方法:

(1)ColorPacked  : 颜色数据类型.

(2)Normal 法线数据类型。(这个土豆也没用过,好像是翻译为“法线”)。

(3)Position 坐标数据类型,一般是定义顶点坐标,基本使用数组,常用。

(4)TextureCoordinates 纹理绑定类型,通俗讲就是使用图片,绑定顶点。


2.Mesh 类

图元的顶点是由VertexAttributes实例中所指定的各元素构成。在使用过程中VARM(帧存储器)和随机存储器mesh都是支持的。前者高性能是很优越的,如果硬件支持,它是首选。

图元用顶点和索引项来确定图形。每个顶点都拥有组成属性,比如位置,法线,颜色或纹理坐标。请注意,并非所有的这些属性必须在全部给定的。在使用OpenGL ES 2.0绘制一个Mesh的时候,每个属性都有一个别名。别名用于顶点属性和shader属性绑定。着色器源和别名的属性必须完全匹配这个工作。图元可以与任何的OpenGL ES 1.x或OpenGL ES 2.0的使用。

构造方法:

Mesh(boolean isStatic, int maxVertices, int maxIndices, VertexAttributes attributes) 

   第一个参数:定义Mesh是否静态,对于那些不需要经常改动的Mesh,设置为静态可以提高OpenGL性能。

   第二个参数:顶点数,范围 1 - 4。

   第三个参数:索引数,也就是libGDX绘制图形时,由哪个店开始绘制,绘制中各个顶点的绘制先后顺序

   第四个参数:指定Mesh将会储存什么类型的数据,比如: position ,color 等。

功能方法:

(1)bind() :在所有索引数给定的前提下,可以将VertexArray/VertexBufferObject and IndexBufferObject整合的方法。

(2)calculateBoundingBox() :根据mesh中给定的顶点创建一个新的BoundingBox实例。

(3)clearAllMeshes(Application app) :清除缓存。

(4)copy(boolean isStatic) :复制这个图元。

(5)create(boolean isStatic, Mesh[] meshes) :由参数内提供的mesh,构建一个新的mesh图元。

(6)getIndices(short[] indices) :获取当前索引数,得到的是一个数组。

(7)render(int primitiveType, int offset, int count)   其中primitiveType指定绘制的形状,offset如果Mesh 使用了顶点缓存(vertex buffer) ,那么这个数就是起点,最后一个参数是指定索引的个数

(8)setIndices(short[] indices) :设置mesh的索引数。

(9)setVertices(float[] vertices) :设置mesh的顶点。

在图元mesh中,还有一些其他的方法,不过都是重复的方法,只是参数变化而已,这里土豆每个类型的方法拿出一个来讲解,大家可以根据这个,来学习其他的方法,都是顾名思义的,很简单的方法。


三、Shader 类

1.API定义:Shader(着色器),在OpenGL中的Shaders类似于一个小工具,它是使用GLSL语言写的(GLSL语言类似于C语言),Shaders是运行在GPU上用于呈现图形图像的东西。

2.原理:Shaders可以视为运行在GPU上面的一个stage,大家可以这么理解。如果想在OpenGL ES 2.0渲染一些东西,渲染数据必须先通过顶点着色器,然后再通过片段着色器,才能完成渲染。

3.Vertex shaders(顶点着色器):顾名思义,顶点着色器是负责执行顶点的操作。

4.Fragment shaders(片段着色器):原理方法与定点着色器类似,但是不像定点着色器,片段着色器,我们可以理解为,对每一个像素进行处理,而不是处理每一个顶点。

三、GLSL 语言

1. 定义:OpenGL Shading Language 也称作 GLslang,是一个以C语言为基础的高阶着色语言。它是由 OpenGL ARB 所建立,提供开发者对绘图管线更多的直接控制,而无需使用汇编语言或硬件规格语言。

2. 优点:在渲染管线中的顶点(vertex)和片断(fragment)层次中,加入更具弹性的新功能。 达到在这个层次中,使用片断和顶点着色器的可编程性。

 使用 GLSL 有如下好处:

(1)具有跨平台的相容性,包括 Macintosh、Windows 和 Linux 等操作系统。

(2)所有支援 OpenGL 着色语言的绘图卡,都可以用来编写着色器。

(3)允许厂商为特定的绘图卡产生最佳化的代码。

3.语法定义
GLSL这里不做为重点理解,所以我们仅仅需要了解他的一些基本变量设置即可,有兴趣做着色编程的同学,可以自己去学习下。
如图:
四、参数详解

今天我们使用的实例,会涉及到一些复杂的数组设置,这里我讲解下有关于我们设置顶点属性的以为数组中变量代表的意思,以及设置索引顶点时的属性变量,是如何设置的。

 1.设置顶点:setVertices(new float[].....)

  (1)前三个坐标代表三位坐标系的顶点坐标。(x,y,z)
  (2)中间4个参数是代表颜色,RGBA。
  (3)最后2个是纹理坐标。
http://s7/mw690/002I6kPggy6Mh0h5te606&690
 2.纹理坐标:

(1)在二维纹理为中,规定纹理左下角的坐标为(0, 0),右上角的坐标为(1, 1)。

(2)于是纹理中的每一个像素的位置都可以用两个浮点数来表示(三维纹理会用三个浮点数,一维纹理则只用一个)。

(3)使用VertexAttribute.TexCoords(0)函数来指定纹理坐标.

如图:
                                       http://s3/mw690/002I6kPggy6Mh0lkhc622&690
 3.设置索引:setIndices( new short[] { 0, 1, 2, 2, 3, 0 })

(1)OpenGL中,使用Mesh绘制一个纹理,需要先绘制一个矩形区域,然后将纹理,以贴图的形式,贴在其上。

(2)贴图的过程中,我们需要将三维坐标系中的点绑定到纹理坐标系中的点。

(3)在绘制Mesh时,我们需要先绘制三角形,所有图形都是以三角形进行拼接而成的,所有需要设置索引点.

如图:

五、完整代码

(1)fragment.glsl代码。

#ifdef GL_ES
precision mediump float;    
#endif    
varying vec4 v_color;    
varying vec2 v_texCoords;    
uniform sampler2D u_texture;    
void main()                                      
                                               
  gl_FragColor v_color texture2D(u_texture, v_texCoords);   
}

(2)vertex.glsl代码。

attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord0;
uniform mat4 u_worldView;
varying vec4 v_color;
varying vec2 v_texCoords;
void main()             
                          
  v_color vec4(1111); 
  v_texCoords a_texCoord0; 
  gl_Position  u_worldView a_position; 
}

(3)MainGame代码

package com.androidgames.potato;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.VertexAttribute;
import com.badlogic.gdx.graphics.VertexAttributes;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Vector3;

public class MainGame extends ApplicationAdapter {

   ShaderProgram shader;
   Mesh mesh;
   Texture texture;
   Matrix4 matrix new Matrix4();

   @Override
   public void create() {

       String vertexShader Gdx.files.internal("vertex.glsl").readString();
       String fragmentShader Gdx.files.internal("fragment.glsl").readString();

       shader new ShaderProgram(vertexShader, fragmentShader);

       mesh new Mesh(true46VertexAttribute.Position(),
               VertexAttribute.ColorUnpacked(), VertexAttribute.TexCoords(0));
       
       mesh.setVertices(new float[]{
               //(x,y,z)坐标 + RGBA +纹理坐标
               -0.5f,-0.5f,0,1,1,1,1,0,1,
                0.5f,-0.5f,0,1,1,1,1,1,1,
                0.5f0.5f,0,1,1,1,1,1,0,
               -0.5f,0.5f0,1,1,1,1,0,0
       });
       
       mesh.setIndices(new short[]{0,1,2,2,3,0});
       
       texture new Texture(Gdx.files.internal("map.png"));

   }
   
   Vector3 axis new Vector3(0,0,1);
   float angle 0;

   @Override
   public void render() {
       
       angle += Gdx.graphics.getDeltaTime() 45;
       matrix.setToRotation(axis, angle);

       Gdx.gl20.glViewport(00Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
       Gdx.gl20.glClearColor(0.2f0.2f0.2f1);
       Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
       Gdx.gl20.glEnable(GL20.GL_TEXTURE_2D);
       Gdx.gl20.glEnable(GL20.GL_BLEND);
       Gdx.gl20.glBlendFunc(GL20.GL_SRC_ALPHAGL20.GL_ONE_MINUS_SRC_ALPHA);
       texture.bind();
       shader.begin();
       shader.setUniformMatrix("u_worldView"matrix);
       mesh.render(shader, GL20.GL_TRIANGLES);
       shader.end();

   }

   @Override
   public void resize(int width, int height) {

   }

   @Override
   public void resume() {
   }

   @Override
   public void dispose() {
       mesh.dispose();
       texture.dispose();
       shader.dispose();

   }

   @Override
   public void pause() {
   }
}

写在最后,关于liGDX中Shalder的使用,就暂时给大家介绍到这里,希望对大家有所帮助。如果大家有什么问题可以加我QQ:316344618,一起讨论下。PS:请大家多多留言交流,大家的评论土豆都会看的,也欢迎大家来libgdx的中文论坛来发帖交流,土豆也是会给大家及时解答的。

                                                              ------------  奋斗小土豆丶
                                                                                                          2014 年 9 月 23 日

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有