三维漫游的实现
一、本文主要是展示一个demo,实现的是画一个三维的立方体,通过滑动屏幕来旋转方向,上下左右来移动。直接上代码:
MainActivity:
package com.example.zp.a3dword;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.opengl.GLSurfaceView;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
public class MainActivity extends AppCompatActivity {
private GLSurfaceView glSurfaceView;
GLRenderer renderer;
//屏幕的宽高
int width;
int height;
float speed = 0.5f;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
glSurfaceView= (GLSurfaceView) findViewById(R.id.gl_surfaceView);
// glSurfaceView =new GLSurfaceView(this);
Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.ayx);
Bitmap bitmap2 = BitmapFactory.decodeResource(this.getResources(), R.drawable.ayx2);
Bitmap mBitmap[] = {bitmap,bitmap2};
renderer=new GLRenderer(mBitmap);
glSurfaceView.setRenderer(renderer);
// setContentView(glSurfaceView);
WindowManager wm = this.getWindowManager();
Point p = new Point(0,0);
wm.getDefaultDisplay().getSize(p);
width = p.x;
height =p.y;
}
int downX; //向一个方向的起始点坐标
int previewX; // 记住前一个点的x坐标
int currentX; //当前点的ex坐标
int downY; //向一个方向的起始点坐标
int previewY; // 记住前一个点的x坐标
int currentY; //当前点的ex坐标
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = (int) event.getX();
previewX = downX;
downY = (int) event.getY();
previewY= downY;
break;
case MotionEvent.ACTION_MOVE:
currentX = (int) event.getX();
currentY = (int) event.getY();
//****************************X方向旋转******************************************//
//判断运动的方向是否改变,大于0不改变
if((currentX - downX)*(currentX - previewX)>0)
{
int dis = currentX - downX;
float angle = (float) dis / (float) width * (float) Math.PI;
renderer.letfrightDirectionChange(angle);
previewX = currentX;
}
else
{
downX = previewX;
}
//****************************Y方向旋转******************************************//
currentY = (int) event.getY();
//判断运动的方向是否改变,大于0不改变
if((currentY - downY)*(currentY - previewY)>0)
{
int dis = currentY - downY;
float angle = (float) dis / (float) width * (float) Math.PI;
renderer.updownDirectionChange(angle);
previewY = currentY;
}
else
{
downY = previewY;
}
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
public void goBack(View view)
{
renderer.goAhead(-speed);
}
public void goAhead(View view)
{
renderer.goAhead(speed);
}
public void goLeft(View view)
{
renderer.goleft(speed);
}
public void goRight(View view)
{
renderer.goleft(-speed);
}
}
Render的实现:
package com.example.zp.a3dword;
import android.graphics.Bitmap;
import android.opengl.GLSurfaceView;
import android.opengl.GLUtils;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
/**
* Created by lenovo on 2016/9/7.
*/
public class GLRenderer implements GLSurfaceView.Renderer{
float xrot = 0;
float yrot = 0;
private float visonPointX=0f;
private float visonPointY=0f;
private float visonPointZ=-3f;
int size=3;
int one = 0x10000*size;
int textureSize = 2;
int texture[] = new int [textureSize];
private Bitmap mBitmap[];
//当正方体很小,为1个点位的时候发现在角落的时候两边出现黑条,这是因为屏幕显示的,即我们看到的视觉是一个以(0,0,0)为中心的平面,旋转函数是旋转整个三维世界,而
//视觉平面的大小位置永远不变,我自己定义为视觉坐标,视觉坐标是不变的,三维世界的坐标起初与视觉坐标是一致的,且视觉显示的是-1层即z为-1的那层只有小与-1的物体可以看到
// 当随着三维世界的旋转就会与视觉坐标产生差异,视觉坐标不变,当随着三维世界的旋转,三维世界的坐标对应的点对应与视觉坐标-1层及大于-1层的物体就不会显示
//正方体的6个面,4个点确定一个面
IntBuffer vertices = BufferUtil.intToBuffer(new int[]{
-one,-one,one,
one,-one,one,
-one,one,one, one,one,one,
-one,-one,-one,
-one,one,-one,
one,-one,-one,one,one,-one,
-one,one,-one,
-one,one,one,
one,one,-one, one,one,one,
-one,-one,-one,
one,-one,-one,
-one,-one,one,one,-one,one,
one,-one,-one,
one,one,-one,
one,-one,one, one,one,one,
-one,-one,-one,
-one,-one,one,
-one,one,-one,-one,one,one
});
//这里one 为几就贴几张,是指一个边贴几张,一个面就是one*one张了,one为1*5所以这里除以5,就会只贴一张
int one2 = one/size;
IntBuffer texCoords2 = BufferUtil.intToBuffer(new int[]{
0, one2, one2, one2, 0, 0, one2, 0,
0, 0, 0, one2, one2, 0, one2, one2,
one2, one2, one2, 0, 0, one2, 0, 0,
0, one2, one2, one2, 0, 0, one2, 0,
0, 0, 0, one2, one2, 0, one2, one2,
one2, 0, 0, 0, one2, one2, 0, one2,
});
public GLRenderer(Bitmap mBitmap[])
{
this.mBitmap = mBitmap;
}
@Override
public void onDrawFrame(GL10 gl)
{
// 清除屏幕和深度缓存
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// 重置当前的模型观察矩阵
// gl.glEnable(GL10.GL_LIGHTING);
gl.glLoadIdentity();
gl.glTranslatef(visonPointX,visonPointY,visonPointZ);
//设置3个方向的旋转
gl.glRotatef(xrot, 1.0f, 0.0f, 0.0f);
gl.glRotatef(yrot, 0.0f,1.0f, 0.0f);
// gl.glRotatef(zrot, 0.0f, 0.0f, 1.0f);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);//启用纹理映射
gl.glVertexPointer(3, GL10.GL_FIXED, 0, vertices);
gl.glTexCoordPointer(2, GL10.GL_FIXED, 0, texCoords2);
gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[1]);
for(int i = 0 ; i < 6 ; i ++)
{
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP , i*4 , 4);
gl.glFinish();
}
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height)
{
float ratio = (float) width / height;
//设置OpenGL场景的大小
gl.glViewport(0, 0, width, height);
//设置投影矩阵
gl.glMatrixMode(GL10.GL_PROJECTION);
//重置投影矩阵
gl.glLoadIdentity();
// 设置视口的大小
gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
// 选择模型观察矩阵
gl.glMatrixMode(GL10.GL_MODELVIEW);
// 重置模型观察矩阵
gl.glLoadIdentity();
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config)
{
// 黑色背景
gl.glClearColor(0, 0, 0, 0);
// gl.glEnable(GL10.GL_CULL_FACE);
// 启用阴影平滑
gl.glShadeModel(GL10.GL_SMOOTH);
// 启用深度测试
gl.glEnable(GL10.GL_DEPTH_TEST);
// 启用混合模式
gl.glEnable(GL10.GL_BLEND);
gl.glDisable(GL10.GL_DEPTH_TEST); // 关闭深度测试
//设置光线,,1.0f为全光线,a=50%
gl.glColor4f(1.0f,1.0f,1.0f,0.5f);
// 基于源象素alpha通道值的半透明混合函数
gl.glBlendFunc(GL10.GL_SRC_ALPHA,GL10.GL_ONE);
//启用纹理映射
gl.glClearDepthf(1.0f);
//深度测试的类型
gl.glDepthFunc(GL10.GL_LEQUAL);
//精细的透视修正
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
//允许2D贴图,纹理
gl.glEnable(GL10.GL_TEXTURE_2D);
getTextures(gl);
// //设置光颜色
// FloatBuffer lightAmbient = BufferUtil.floatToBuffer(new float[]{
// 1f, 1f, 1f, 1f
// } );
// FloatBuffer lightDiffuse = BufferUtil.floatToBuffer(new float[]{
// 1f,1f,1f,1f
// } );
// //定义光源位置
// FloatBuffer lightPosition = BufferUtil.floatToBuffer(new float[]{
// -2f,0f,-4f,1f
// } );
//
//// //设置环境光
// gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_AMBIENT, lightAmbient);
//
// //设置漫射光
// gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_DIFFUSE, lightDiffuse);
//
// //设置光源位置
// gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_POSITION, lightPosition);
//
// //开启一号光源
// gl.glEnable(GL10.GL_LIGHT1);
}
private void getTextures(GL10 gl)
{
IntBuffer intBuffer = IntBuffer.allocate(2);//申请2个纹理存储空间
// 创建纹理
gl.glGenTextures(2 , intBuffer); //创建2个纹理,绑定intuffer
texture[0] = intBuffer.get(); // 获取第一个纹理的存储指针,即纹理存储位置,位置+1
texture[1] = intBuffer.get(); //获取下一个纹理存储的位置
// 设置要使用的纹理
gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[0]);
//生成纹理
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0 , mBitmap[0] , 0);//利用图mBitmap[0]生成纹理,存储在texture[0]
// 线形滤波
gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
//生成第二个纹理
gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[1]);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0 , mBitmap[1] , 0);//利用图mBitmap[0]生成纹理,存储在texture[1]
gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
}
//三维世界向右旋转,我们的视觉就向左旋转了
public void letfrightDirectionChange( float angle)
{
yrot = yrot + angle;
}
public void updownDirectionChange(float angle)
{
xrot = xrot + angle;
}
public void goAhead (float dis)
{
visonPointZ = visonPointZ + dis;
}
public void goleft (float dis)
{
visonPointX = visonPointX + dis;
}
}
BufferUtil工具类前面展示过这里就省略了。