LIBGDX版NEHE OPENGL- 7. Texture Filters, Lighting & Keyboard Control

Libgdx的TextureFilter

  首先废话说一说“纹理映射的方式”,一个128*128的图片,在渲染的时候,很可能会被放到一个256*256的方形区域显示,也有可能放到64*64的方形区域显示。所以,图片在缩小时,一些相象就丢失了,在放大时,就需要填充一些像素。

GL_TEXTURE_MIN_FILTER 指的是缩小的情况,而GL_TEXTURE_MAG_FILTER 指的是放大的情况。那OpenGL在这种情况下怎么处理呢?我们称之为纹理过滤方式:

  1. 最近点采样 GL_NEAREST-效果最差,速度快
  2. 线性纹理过滤(双线性过滤)GL_LINEAR-效果较好,计算量较大
  3. mipmap纹理过滤(三线性过滤) GL_LINEAR_MIPMAP_LINEAR-效果最好,计算量最大
  4. 各向异性过滤

更多关于这三种渲染方式的讲解看这里吧,http://blog.csdn.net/kkk328/article/details/7055934,我这只管怎么用就好了,要说一下,Libgdx所实现的OpenGL ES里,只支持前面三种。可以看一下Libgdx中关于TextureFilter的定义:

	public enum TextureFilter {
		Nearest(GL10.GL_NEAREST), Linear(GL10.GL_LINEAR), MipMap(GL10.GL_LINEAR_MIPMAP_LINEAR), MipMapNearestNearest(
			GL10.GL_NEAREST_MIPMAP_NEAREST), MipMapLinearNearest(GL10.GL_LINEAR_MIPMAP_NEAREST), MipMapNearestLinear(
			GL10.GL_NEAREST_MIPMAP_LINEAR), MipMapLinearLinear(GL10.GL_LINEAR_MIPMAP_LINEAR);

		final int glEnum;

		TextureFilter (int glEnum) {
			this.glEnum = glEnum;
		}

		public boolean isMipMap () {
			return glEnum != GL10.GL_NEAREST && glEnum != GL10.GL_LINEAR;
		}

		public int getGLEnum () {
			return glEnum;
		}
	}

所以,三种类型的Texture就很好建立了:

	Texture[] textureArray = new Texture[3];
	textureArray[0] = new Texture(imageFileHandle);
	textureArray[0].setFilter(TextureFilter.Nearest, TextureFilter.Nearest);
	textureArray[1] = new Texture(imageFileHandle);
	textureArray[1].setFilter(TextureFilter.Linear, TextureFilter.Linear);
	textureArray[2] = new Texture(imageFileHandle, true); // true 指明这里要使用mipmap
	textureArray[2].setFilter(TextureFilter.MipMapLinearNearest,
			TextureFilter.Linear);

通过TextureFilter的定义可以看到,Libgdx可支持最多四种方式的MipMap, 高数好的可能会鄙视我了,Linear&Nearest最多就四种嘛。

MipMap(GL10.GL_LINEAR_MIPMAP_LINEAR), // 此种为默认的MipMap方式。等同于MinMapLinearLinear;

MipMapNearestNearest(GL10.GL_NEAREST_MIPMAP_NEAREST), 

MipMapLinearNearest(GL10.GL_LINEAR_MIPMAP_NEAREST), 

MipMapNearestLinear(GL10.GL_NEAREST_MIPMAP_LINEAR), 

MipMapLinearLinear(GL10.GL_LINEAR_MIPMAP_LINEAR);

我在学习TextureFilter的时候,Google到了一个好网站,名字为 Open GL Super Bible. 大家可以点去看看。当然,全英文。

Libgdx的Lighting:

在OpenGL中,最多支持8个光源。所以,Libgdx的GL10中,只能找到GL_LIGHT0 ~ GL_LIGHT7.

不好意思,我又要转帖了,这篇文章来自大龙的博客,对OpenGL ES的灯光做了不错的解释。

看完了大龙对灯光的介绍,再回来定义我们Libgdx里的光源:

	// Ambient Light 环境光
	float[] ambientLight = {0.5f, 0.5f, 0.5f, 1.0f};
	// Diffuse Light 漫射光
	float[] diffuseLight = {1.0f, 1.0f, 1.0f, 1.0f};

光的问题先略过,等不及加上键盘处理了,这样就可以与画面有一些交互。

使用“L”键来开关灯,使用"F"键来切换filter类型,使用"鼠标滚轮"来放大缩小。

package com.kyugao.screen;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.VertexAttribute;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;

public class FilterLightingKeyboard implements Screen, InputProcessor {

	private Mesh squareMesh;
	private PerspectiveCamera camera;
	private Texture[] textureArray;
	private int filter = 0;
	private float xrot = 0, yrot = 0;
	private float xspeed = 20, yspeed = 20;

	// indicator for controlling the light
	private boolean light;
	private boolean lp, fp;
	private float z = -5.0f;

	// Ambient Light
	float[] ambientLight = { 0.5f, 0.5f, 0.5f, 1.0f };
	// Diffuse Light
	float[] diffuseLight = { 1.0f, 1.0f, 1.0f, 1.0f };
	// Light Position
	float[] position = { 0.0f, 0.0f, 2.0f, 1.0f };

	@Override
	public void render(float delta) {

		camera.update();
		camera.apply(Gdx.graphics.getGL10());
		Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
		Gdx.gl.glEnable(GL10.GL_DEPTH_TEST);
		Gdx.gl.glEnable(GL10.GL_TEXTURE_2D);
		drawGLScene();
		xrot += xspeed * delta; // 每秒钟转20度,计算在每一次render的时间差里,要转的角度。比如0.5秒,那就应该转10度。
		xrot %= 360;
		yrot += yspeed * delta;
		yrot %= 360;
	}

	private boolean drawGLScene() {
		Gdx.gl10.glPushMatrix();
		Gdx.gl10.glLoadIdentity();
		Gdx.gl10.glTranslatef(0.0f, 0.0f, z);
		Gdx.gl10.glRotatef(xrot, 1.0f, 0.0f, 0.0f);
		Gdx.gl10.glRotatef(yrot, 0.0f, 1.0f, 0.0f);
		textureArray[filter].bind();
		for (int i = 0; i < squareMesh.getMaxVertices() / 4; i++) {
			squareMesh.render(GL10.GL_TRIANGLE_FAN, i * 4, 4); // 正方形的6个面分别画出.
		}
		Gdx.gl10.glPopMatrix();
		return true;
	}

	@Override
	public void show() {
		// init mesh
		squareMesh = new Mesh(true, 24, 24, new VertexAttribute(Usage.Position,
				3, "b_position"), new VertexAttribute(Usage.TextureCoordinates,
				2, "b_texture"));

		squareMesh.setVertices(new float[] {
				// Front face:
				-1f, 1.0f, 1.0f, 0f, 0f, // TL
				-1f, -1.0f, 1.0f, 0f, 1f, // BL
				1f, -1.0f, 1.0f, 1f, 1f, // BR
				1f, 1.0f, 1.0f, 1f, 0f, // TR
				// Top face:
				-1f, 1.0f, -1.0f, 0f, 0f, // LR
				-1f, 1.0f, 1.0f, 0f, 1f, // LN
				1f, 1.0f, 1.0f, 1f, 1f, // RN
				1f, 1.0f, -1.0f, 1f, 0f, // RR
				// Rear face
				1f, 1.0f, -1f, 0f, 0f, // TR
				1f, -1.0f, -1f, 0f, 1f, // BR
				-1f, -1.0f, -1f, 1f, 1f, // BL
				-1f, 1.0f, -1f, 1f, 0f, // TL
				// Bottom face
				-1f, -1.0f, 1f, 0f, 0f, // LN
				1f, -1.0f, 1f, 0f, 1f,// RN
				1f, -1.0f, -1f, 1f, 1f, // RR
				-1f, -1.0f, -1f, 1f, 0f, // LR
				// Left face
				-1f, 1.0f, -1f, 0f, 0f, // TR
				-1f, 1.0f, 1f, 0f, 1f, // TN
				-1f, -1.0f, 1f, 1f, 1f, // BN
				-1f, -1.0f, -1f, 1f, 0f, // BR
				// Right face
				1f, 1.0f, 1f, 0f, 0f, // TN
				1f, 1.0f, -1f, 1f, 0f, // TR
				1f, -1.0f, -1f, 1f, 1f, // BR
				1f, -1.0f, 1f, 0f, 1f // BN
				});
		squareMesh.setIndices(new short[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
				11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 });

		// init texture
		FileHandle imageFileHandle = Gdx.files.internal("data/Crate.bmp");
		textureArray = new Texture[3];
		textureArray[0] = new Texture(imageFileHandle);
		textureArray[0].setFilter(TextureFilter.Nearest, TextureFilter.Nearest);
		textureArray[1] = new Texture(imageFileHandle);
		textureArray[1].setFilter(TextureFilter.Linear, TextureFilter.Linear);
		textureArray[2] = new Texture(imageFileHandle, true);
		textureArray[2].setFilter(TextureFilter.MipMap, TextureFilter.Linear);

		// init light
		Gdx.gl.glEnable(GL10.GL_LIGHT1);
		Gdx.gl10.glLightfv(GL10.GL_LIGHT1, GL10.GL_AMBIENT, ambientLight, 0);
		Gdx.gl10.glLightfv(GL10.GL_LIGHT1, GL10.GL_DIFFUSE, diffuseLight, 0);
		Gdx.gl10.glLightfv(GL10.GL_LIGHT1, GL10.GL_POSITION, position, 0);

		// Set input processor
		Gdx.input.setInputProcessor(this);
	}

	@Override
	public void hide() {
	}

	@Override
	public void pause() {
	}

	@Override
	public void resume() {
	}

	@Override
	public void dispose() {
	}

	@Override
	public void resize(int width, int height) {
		float aspectRatio = (float) width / (float) height;
		camera = new PerspectiveCamera(45, 2f * aspectRatio, 2f);
	}

	@Override
	public boolean keyDown(int keycode) {
		if (keycode == Input.Keys.L && !lp) {
			lp = true;
			light = !light;
			if (light) {
				Gdx.gl.glEnable(GL10.GL_LIGHTING);
			} else {
				Gdx.gl.glDisable(GL10.GL_LIGHTING);
			}
		} else if (keycode == Input.Keys.F && !fp) {
			fp = true;
			filter = (filter + 1) % 3;
		}
		return false;
	}

	@Override
	public boolean keyUp(int keycode) {
		if (keycode == Input.Keys.L && lp) {
			lp = false;
		} else if (keycode == Input.Keys.F && fp) {
			fp = false;
		}
		return false;
	}

	@Override
	public boolean keyTyped(char character) {
		return false;
	}

	@Override
	public boolean touchDown(int screenX, int screenY, int pointer, int button) {
		return false;
	}

	@Override
	public boolean touchUp(int screenX, int screenY, int pointer, int button) {
		return false;
	}

	@Override
	public boolean touchDragged(int screenX, int screenY, int pointer) {
		return false;
	}

	@Override
	public boolean mouseMoved(int screenX, int screenY) {
		return false;
	}

	@Override
	public boolean scrolled(int amount) {
		z += amount;
		return false;
	}

}

上面代码,下面效果图:

缩小:


放大


放大到箱子里面:


使用mipmap的显示效果。(有点模糊)


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值