libgdx 学习笔记六 Projection,Viewport,Camera (投影,视口,相机)
来源:互联网 发布:加工中心编程 编辑:程序博客网 时间:2024/05/21 01:42
Introduction(介绍)
在学习笔记4 MyFirstTriangle 和学习笔记5 ColorMeshTexture 中, 我们学习了建立和渲染mesh的基础。你注意到没,三角形出现了拉伸 。让我们开始用一个例子来解决这个问题
Creating a Square(创建一个正方形)
创建一个新的libgdx桌面工程叫projection-viewport-camera。创建一个名叫ProjectionViewportCamera的类 继承ApplicationListener,然后包名 为 com.example.projectionviewportcamera。详细说明怎么建立一个libgdx桌面或者android工程,请看学习笔记4 MyFirstTriangle 教程。不同于学习笔记4,我们准备显示一个正方形。以下是ProjectionViewportCamera中的代码
- package com.example.projectionviewportcamera;
- import com.badlogic.gdx.ApplicationListener;
- import com.badlogic.gdx.Gdx;
- import com.badlogic.gdx.graphics.Color;
- import com.badlogic.gdx.graphics.GL10;
- import com.badlogic.gdx.graphics.Mesh;
- import com.badlogic.gdx.graphics.VertexAttribute;
- import com.badlogic.gdx.graphics.VertexAttributes.Usage;
- public class ProjectionViewportCameraimplements ApplicationListener {
- private Mesh squarePartOne;
- private Mesh squarePartTwo;
- @Override
- public void create() {
- if (squarePartOne == null) {
- squarePartOne = new Mesh(true,3, 3,
- new VertexAttribute(Usage.Position,3, "a_position"),
- new VertexAttribute(Usage.ColorPacked,4, "a_color"));
- squarePartOne.setVertices(newfloat[] {
- -0.5f, -0.5f,0, Color.toFloatBits(128,0, 0,255),
- 0.5f, -0.5f,0, Color.toFloatBits(192,0, 0,255),
- -0.5f, 0.5f,0, Color.toFloatBits(192,0, 0,255) });
- squarePartOne.setIndices(newshort[] { 0,1, 2});
- }
- if (squarePartTwo ==null) {
- squarePartTwo = new Mesh(true,3, 3,
- new VertexAttribute(Usage.Position,3, "a_position"),
- new VertexAttribute(Usage.ColorPacked,4, "a_color"));
- squarePartTwo.setVertices(newfloat[] {
- 0.5f, -0.5f,0, Color.toFloatBits(192,0, 0,255),
- -0.5f, 0.5f,0, Color.toFloatBits(192,0, 0,255),
- 0.5f, 0.5f,0, Color.toFloatBits(255,0, 0,255) });
- squarePartTwo.setIndices(newshort[] { 0,1, 2});
- }
- }
- @Override
- public void dispose() { }
- @Override
- public void pause() { }
- @Override
- public void render() {
- Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
- squarePartOne.render(GL10.GL_TRIANGLES, 0,3);
- squarePartTwo.render(GL10.GL_TRIANGLES, 0,3);
- }
- @Override
- public void resize(int width,int height) { }
- @Override
- public void resume() { }
- }
package com.example.projectionviewportcamera; import com.badlogic.gdx.ApplicationListener; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.GL10; import com.badlogic.gdx.graphics.Mesh; import com.badlogic.gdx.graphics.VertexAttribute; import com.badlogic.gdx.graphics.VertexAttributes.Usage; public class ProjectionViewportCamera implements ApplicationListener { private Mesh squarePartOne; private Mesh squarePartTwo; @Override public void create() { if (squarePartOne == null) { squarePartOne = new Mesh(true, 3, 3, new VertexAttribute(Usage.Position, 3, "a_position"), new VertexAttribute(Usage.ColorPacked, 4, "a_color")); squarePartOne.setVertices(new float[] { -0.5f, -0.5f, 0, Color.toFloatBits(128, 0, 0, 255), 0.5f, -0.5f, 0, Color.toFloatBits(192, 0, 0, 255), -0.5f, 0.5f, 0, Color.toFloatBits(192, 0, 0, 255) }); squarePartOne.setIndices(new short[] { 0, 1, 2}); } if (squarePartTwo == null) { squarePartTwo = new Mesh(true, 3, 3, new VertexAttribute(Usage.Position, 3, "a_position"), new VertexAttribute(Usage.ColorPacked, 4, "a_color")); squarePartTwo.setVertices(new float[] { 0.5f, -0.5f, 0, Color.toFloatBits(192, 0, 0, 255), -0.5f, 0.5f, 0, Color.toFloatBits(192, 0, 0, 255), 0.5f, 0.5f, 0, Color.toFloatBits(255, 0, 0, 255) }); squarePartTwo.setIndices(new short[] { 0, 1, 2}); } } @Override public void dispose() { } @Override public void pause() { } @Override public void render() { Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT); squarePartOne.render(GL10.GL_TRIANGLES, 0, 3); squarePartTwo.render(GL10.GL_TRIANGLES, 0, 3); } @Override public void resize(int width, int height) { } @Override public void resume() { } }
上面代码和MyFirstTriangle教程中用了很相似的内容除了他用2个三角形代替了1个。把2个三角形放在的位置形成一个正方形,用二维坐标(-0.5,-0.5),(0.5,-0.5),(0.5,0.5)(-0.5,0.5)。
运行程序效果如下:
明显的,虽然我们指定正方形的坐标, 但结果却变成一个长方形。在讨论这个问题之前,我将偏离主题一会,为这个正方形优化一下渲染。2个三角形有1个顶点在(0.5,-0.5)还有一个在(-0.5,0.5)。在相同坐标中,我们排除顶点的副本 ,用三角带(TRIANGLE_STRIP)实现的正方形。用三角带(TRIANGLE_STRIP)允许2个三角形共享顶点所以更节约内存。
(看看Jeff LaMarche's tutorial 有更好的说明)。下面是改后的代码:
- <SPAN style="FONT-SIZE: 16px">package com.example.projectionviewportcamera;
- import com.badlogic.gdx.ApplicationListener;
- import com.badlogic.gdx.Gdx;
- import com.badlogic.gdx.graphics.Color;
- import com.badlogic.gdx.graphics.GL10;
- import com.badlogic.gdx.graphics.Mesh;
- import com.badlogic.gdx.graphics.VertexAttribute;
- import com.badlogic.gdx.graphics.VertexAttributes.Usage;
- public class ProjectionViewportCameraimplements ApplicationListener {
- private Mesh squareMesh;
- @Override
- public void create() {
- if (squareMesh ==null) {
- squareMesh = new Mesh(true,4, 4,
- new VertexAttribute(Usage.Position,3, "a_position"),
- new VertexAttribute(Usage.ColorPacked,4, "a_color"));
- squareMesh.setVertices(newfloat[] {
- -0.5f, -0.5f,0, Color.toFloatBits(128,0, 0,255),
- 0.5f, -0.5f,0, Color.toFloatBits(192,0, 0,255),
- -0.5f, 0.5f,0, Color.toFloatBits(192,0, 0,255),
- 0.5f, 0.5f,0, Color.toFloatBits(255,0, 0,255) });
- squareMesh.setIndices(new short[] { 0,1, 2,3});16
- }
- }
- @Override
- public void dispose() { }
- @Override
- public void pause() { }
- @Override
- public void render() {
- Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
- squareMesh.render(GL10.GL_TRIANGLE_STRIP, 0,4);
- }
- @Override
- public void resize(int width,int height) { }
- @Override
- public void resume() { }
- }
- </SPAN>
package com.example.projectionviewportcamera; import com.badlogic.gdx.ApplicationListener; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.GL10; import com.badlogic.gdx.graphics.Mesh; import com.badlogic.gdx.graphics.VertexAttribute; import com.badlogic.gdx.graphics.VertexAttributes.Usage; public class ProjectionViewportCamera implements ApplicationListener { private Mesh squareMesh; @Override public void create() { if (squareMesh == null) { squareMesh = new Mesh(true, 4, 4, new VertexAttribute(Usage.Position, 3, "a_position"), new VertexAttribute(Usage.ColorPacked, 4, "a_color")); squareMesh.setVertices(new float[] { -0.5f, -0.5f, 0, Color.toFloatBits(128, 0, 0, 255), 0.5f, -0.5f, 0, Color.toFloatBits(192, 0, 0, 255), -0.5f, 0.5f, 0, Color.toFloatBits(192, 0, 0, 255), 0.5f, 0.5f, 0, Color.toFloatBits(255, 0, 0, 255) }); squareMesh.setIndices(new short[] { 0, 1, 2, 3});16 } } @Override public void dispose() { } @Override public void pause() { } @Override public void render() { Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT); squareMesh.render(GL10.GL_TRIANGLE_STRIP, 0, 4); } @Override public void resize(int width, int height) { } @Override public void resume() { } }
2个三角形在单个mesh中用四个顶点和4个索引被连到一起了。在render()中,我们指定正方形用triangle strips来定义。顶点越少越好而且代码也比较简单
Viewport
回到正方形拉伸的问题上来。默认viewport 用左边距 x=-1,右边距x=1,顶部边距 y=1,底部边距y=-1展现了一个矩形区域。如果我们创建一个原型看起来像空白区域的图片:
当我们红色的正方形在那个区域时,结果看起来是这样:
然而,viewport 它自己比正方形更大。为了填满边上额外的空间,这个区域被延伸。想象一个画家 延伸一个正方形画布变成一个矩形框。结果如下:
Camera
修正这个效果,我们允许viewport渲染一个代替正方形的矩形区域 。这个区域的形状将匹配viewport的形状,有那么点像一个画家选择一个基于图片框尺寸的画布尺寸。完成这个,
我们用Camera类,在本例中一个子类叫OrthographicCamera。Camera类允许我们根据viewport改变显示区域。以下是代码:
- <SPAN style="FONT-SIZE: 16px">package com.example.projectionviewportcamera;
- import com.badlogic.gdx.ApplicationListener;
- import com.badlogic.gdx.Gdx;
- import com.badlogic.gdx.graphics.Color;
- import com.badlogic.gdx.graphics.GL10;
- import com.badlogic.gdx.graphics.Mesh;
- import com.badlogic.gdx.graphics.OrthographicCamera;
- import com.badlogic.gdx.graphics.VertexAttribute;
- import com.badlogic.gdx.graphics.VertexAttributes.Usage;
- public class ProjectionViewportCameraimplements ApplicationListener {
- private Mesh squareMesh;
- private OrthographicCamera camera;
- @Override
- public void create() {
- if (squareMesh ==null) {
- squareMesh = new Mesh(true,4, 4,
- new VertexAttribute(Usage.Position,3, "a_position"),
- new VertexAttribute(Usage.ColorPacked,4, "a_color"));
- squareMesh.setVertices(newfloat[] {
- -0.5f, -0.5f,0, Color.toFloatBits(128,0, 0,255),
- 0.5f, -0.5f,0, Color.toFloatBits(192,0, 0,255),
- -0.5f, 0.5f,0, Color.toFloatBits(192,0, 0,255),
- 0.5f, 0.5f,0, Color.toFloatBits(255,0, 0,255) });
- squareMesh.setIndices(new short[] { 0,1, 2,3});
- }
- }
- @Override
- public void dispose() { }
- @Override
- public void pause() { }
- @Override
- public void render() {
- camera.update();
- camera.apply(Gdx.gl10);
- Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
- squareMesh.render(GL10.GL_TRIANGLE_STRIP, 0,4);
- }
- @Override
- public void resize(int width,int height) {
- float aspectRatio = (float) width / (float) height;
- camera = new OrthographicCamera(2f * aspectRatio, 2f);
- }
- @Override
- public void resume() { }
- }
- </SPAN>
package com.example.projectionviewportcamera; import com.badlogic.gdx.ApplicationListener; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.GL10; import com.badlogic.gdx.graphics.Mesh; import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.VertexAttribute; import com.badlogic.gdx.graphics.VertexAttributes.Usage; public class ProjectionViewportCamera implements ApplicationListener { private Mesh squareMesh; private OrthographicCamera camera; @Override public void create() { if (squareMesh == null) { squareMesh = new Mesh(true, 4, 4, new VertexAttribute(Usage.Position, 3, "a_position"), new VertexAttribute(Usage.ColorPacked, 4, "a_color")); squareMesh.setVertices(new float[] { -0.5f, -0.5f, 0, Color.toFloatBits(128, 0, 0, 255), 0.5f, -0.5f, 0, Color.toFloatBits(192, 0, 0, 255), -0.5f, 0.5f, 0, Color.toFloatBits(192, 0, 0, 255), 0.5f, 0.5f, 0, Color.toFloatBits(255, 0, 0, 255) }); squareMesh.setIndices(new short[] { 0, 1, 2, 3}); } } @Override public void dispose() { } @Override public void pause() { } @Override public void render() { camera.update(); camera.apply(Gdx.gl10); Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT); squareMesh.render(GL10.GL_TRIANGLE_STRIP, 0, 4); } @Override public void resize(int width, int height) { float aspectRatio = (float) width / (float) height; camera = new OrthographicCamera(2f * aspectRatio, 2f); } @Override public void resume() { } }
在resize()中,我们构造一个OrthographicCamera的实例。指定我们想要显示的区域。本例中,我们告诉Camera显示viewport的形状,用2*宽度/高度比值单位的区域
在render()中(这里就是表示屏幕相对宽度值=3 后面会说明),我们通过Camera实例调用update()和apply()。以下是运行效果:
桌面viewport 在我们的教程中分辨率为480X320。 当app启动和旋转时通过resize()传入的数字。屏幕宽度用来和数字的比例计算。例如 width=2 *480 / 320=3.下面就是坐标图
正方形的顶点仍然位于(x,y)坐标系。现在我们使用Camera改正它的先前的变形。
Camera and Sprites
在HelloWorld之后我们没有处理sprites。但值得注意的是SpriteBatch类真的有一个内部的camera ,它不同于我们前面构造的那个。例如在坐标(0,0)中绘制一个sprite,
我们创建一个在sprite覆盖正方形不必要的。在绘制的开始阶段同步2个cameras即可搞定这个问题。代码如下(包含MeshColorTexture教程,提醒注意载入assets。)
- <SPAN style="FONT-SIZE: 16px">package com.example.projectionviewportcamera;
- import com.badlogic.gdx.ApplicationListener;
- import com.badlogic.gdx.Gdx;
- import com.badlogic.gdx.graphics.Color;
- import com.badlogic.gdx.graphics.GL10;
- import com.badlogic.gdx.graphics.Mesh;
- import com.badlogic.gdx.graphics.OrthographicCamera;
- import com.badlogic.gdx.graphics.Texture;
- import com.badlogic.gdx.graphics.VertexAttribute;
- import com.badlogic.gdx.graphics.VertexAttributes.Usage;
- import com.badlogic.gdx.graphics.g2d.SpriteBatch;
- public class ProjectionViewportCameraimplements ApplicationListener {
- private Mesh squareMesh;
- private OrthographicCamera camera;
- private Texture texture;
- private SpriteBatch spriteBatch;
- @Override
- public void create() {
- if (squareMesh ==null) {
- squareMesh = new Mesh(true,4, 4,
- new VertexAttribute(Usage.Position,3, "a_position"),
- new VertexAttribute(Usage.ColorPacked,4, "a_color"));
- squareMesh.setVertices(newfloat[] {
- -0.5f, -0.5f,0, Color.toFloatBits(128,0, 0,255),
- 0.5f, -0.5f,0, Color.toFloatBits(192,0, 0,255),
- -0.5f, 0.5f,0, Color.toFloatBits(192,0, 0,255),
- 0.5f, 0.5f,0, Color.toFloatBits(255,0, 0,255) });
- squareMesh.setIndices(new short[] { 0,1, 2,3});
- }
- texture = new Texture(Gdx.files.internal("data/badlogic.jpg"));
- spriteBatch = new SpriteBatch();
- }
- @Override
- public void dispose() { }
- @Override
- public void pause() { }
- @Override
- public void render() {
- camera.update();
- camera.apply(Gdx.gl10);
- spriteBatch.setProjectionMatrix(camera.combined);
- Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
- squareMesh.render(GL10.GL_TRIANGLE_STRIP, 0,4);
- spriteBatch.begin();
- spriteBatch.draw(texture, 0,0, 1,1, 0,0,
- texture.getWidth(), texture.getHeight(), false,false);
- spriteBatch.end();
- }
- @Override
- public void resize(int width,int height) {
- float aspectRatio = (float) width / (float) height;
- camera = new OrthographicCamera(2f * aspectRatio, 2f);
- }
- @Override
- public void resume() { }
- }
- </SPAN>
package com.example.projectionviewportcamera; import com.badlogic.gdx.ApplicationListener; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.GL10; import com.badlogic.gdx.graphics.Mesh; import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.VertexAttribute; import com.badlogic.gdx.graphics.VertexAttributes.Usage; import com.badlogic.gdx.graphics.g2d.SpriteBatch; public class ProjectionViewportCamera implements ApplicationListener { private Mesh squareMesh; private OrthographicCamera camera; private Texture texture; private SpriteBatch spriteBatch; @Override public void create() { if (squareMesh == null) { squareMesh = new Mesh(true, 4, 4, new VertexAttribute(Usage.Position, 3, "a_position"), new VertexAttribute(Usage.ColorPacked, 4, "a_color")); squareMesh.setVertices(new float[] { -0.5f, -0.5f, 0, Color.toFloatBits(128, 0, 0, 255), 0.5f, -0.5f, 0, Color.toFloatBits(192, 0, 0, 255), -0.5f, 0.5f, 0, Color.toFloatBits(192, 0, 0, 255), 0.5f, 0.5f, 0, Color.toFloatBits(255, 0, 0, 255) }); squareMesh.setIndices(new short[] { 0, 1, 2, 3}); } texture = new Texture(Gdx.files.internal("data/badlogic.jpg")); spriteBatch = new SpriteBatch(); } @Override public void dispose() { } @Override public void pause() { } @Override public void render() { camera.update(); camera.apply(Gdx.gl10); spriteBatch.setProjectionMatrix(camera.combined); Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT); squareMesh.render(GL10.GL_TRIANGLE_STRIP, 0, 4); spriteBatch.begin(); spriteBatch.draw(texture, 0, 0, 1, 1, 0, 0, texture.getWidth(), texture.getHeight(), false, false); spriteBatch.end(); } @Override public void resize(int width, int height) { float aspectRatio = (float) width / (float) height; camera = new OrthographicCamera(2f * aspectRatio, 2f); } @Override public void resume() { } }
在render()中, 我们更新我们的相机,提供相机的投影信息到SpriteBatch实例中,我们用来绘制我们的sprite。效果如下:
需要注意绘制一个sprite会改变整个场景的投影到sprite的投影。如果你没有设置sprite的投影到同其余的场景。sprite也许改变其余的场景看起来像简单的画法。理想的效果,你的SpriteBatch实例,在这种情况下可能清空创建的第二个camera。
Projection(投影)
在这一点上,我们已经布局mesh和sprite如果他们在一个平坦的表面上。没有深度,面积,距离的概念。OrthographicCamera已经使用提供一个我们的场景的orthographic 投影。
这个投影类型仅仅意味着提供一个空间的2D概念,像奇特的马里奥或者吃豆子。为了显示深度和3D空间,我们需要用到透视投影。关于投影的学习,可以看看Mario's blog post on the Camera class或者Jeff LaMarche's article on the subject
在libgdx中使用透视投影的方法,让我们介绍另一个正方形mesh,代码如下:
- <SPAN style="FONT-SIZE: 16px">package com.example.projectionviewportcamera;
- import com.badlogic.gdx.ApplicationListener;
- import com.badlogic.gdx.Gdx;
- import com.badlogic.gdx.graphics.Camera;
- import com.badlogic.gdx.graphics.Color;
- import com.badlogic.gdx.graphics.GL10;
- import com.badlogic.gdx.graphics.Mesh;
- import com.badlogic.gdx.graphics.OrthographicCamera;
- import com.badlogic.gdx.graphics.VertexAttribute;
- import com.badlogic.gdx.graphics.VertexAttributes.Usage;
- public class ProjectionViewportCameraimplements ApplicationListener {
- private Mesh squareMesh;
- private Mesh nearSquare;
- private Camera camera;
- @Override
- public void create() {
- if (squareMesh ==null) {
- squareMesh = new Mesh(true,4, 4,
- new VertexAttribute(Usage.Position,3, "a_position"),
- new VertexAttribute(Usage.ColorPacked,4, "a_color"));
- squareMesh.setVertices(newfloat[] {
- 0, -0.5f, -4, Color.toFloatBits(128,0, 0,255),
- 1, -0.5f, -4, Color.toFloatBits(192,0, 0,255),
- 0, 0.5f, -4, Color.toFloatBits(192,0, 0,255),
- 1, 0.5f, -4, Color.toFloatBits(255,0, 0,255) });
- squareMesh.setIndices(new short[] { 0,1, 2,3});
- if (nearSquare ==null) {
- nearSquare = new Mesh(true,4, 4,
- new VertexAttribute(Usage.Position,3, "a_position"),
- new VertexAttribute(Usage.ColorPacked,4, "a_color"));
- nearSquare.setVertices(newfloat[] { -
- 1, -0.5f, -1.1f, Color.toFloatBits(0,0, 128,255),
- 0, -0.5f, -1.1f, Color.toFloatBits(0,0, 192,255),
- -1, 0.5f, -1.1f, Color.toFloatBits(0,0, 192,255),
- 0, 0.5f, -1.1f, Color.toFloatBits(0,0, 255,255) });
- nearSquare.setIndices(new short[] { 0,1, 2,3});
- }
- }
- @Override
- public void dispose() { }
- @Override
- public void pause() { }
- @Override
- public void render() {
- camera.update();
- camera.apply(Gdx.gl10);
- Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
- squareMesh.render(GL10.GL_TRIANGLE_STRIP, 0,4);
- nearSquare.render(GL10.GL_TRIANGLE_STRIP, 0,4);
- }
- @Override
- public void resize(int width,int height) {
- float aspectRatio = (float) width / (float) height;
- camera = new OrthographicCamera(2f * aspectRatio, 2f);
- }
- @Override
- public void resume() { }
- }
- </SPAN>
package com.example.projectionviewportcamera; import com.badlogic.gdx.ApplicationListener; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Camera; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.GL10; import com.badlogic.gdx.graphics.Mesh; import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.VertexAttribute; import com.badlogic.gdx.graphics.VertexAttributes.Usage; public class ProjectionViewportCamera implements ApplicationListener { private Mesh squareMesh; private Mesh nearSquare; private Camera camera; @Override public void create() { if (squareMesh == null) { squareMesh = new Mesh(true, 4, 4, new VertexAttribute(Usage.Position, 3, "a_position"), new VertexAttribute(Usage.ColorPacked, 4, "a_color")); squareMesh.setVertices(new float[] { 0, -0.5f, -4, Color.toFloatBits(128, 0, 0, 255), 1, -0.5f, -4, Color.toFloatBits(192, 0, 0, 255), 0, 0.5f, -4, Color.toFloatBits(192, 0, 0, 255), 1, 0.5f, -4, Color.toFloatBits(255, 0, 0, 255) }); squareMesh.setIndices(new short[] { 0, 1, 2, 3}); if (nearSquare == null) { nearSquare = new Mesh(true, 4, 4, new VertexAttribute(Usage.Position, 3, "a_position"), new VertexAttribute(Usage.ColorPacked, 4, "a_color")); nearSquare.setVertices(new float[] { -1, -0.5f, -1.1f, Color.toFloatBits(0, 0, 128, 255), 0, -0.5f, -1.1f, Color.toFloatBits(0, 0, 192, 255), -1, 0.5f, -1.1f, Color.toFloatBits(0, 0, 192, 255), 0, 0.5f, -1.1f, Color.toFloatBits(0, 0, 255, 255) }); nearSquare.setIndices(new short[] { 0, 1, 2, 3}); } } @Override public void dispose() { } @Override public void pause() { } @Override public void render() { camera.update(); camera.apply(Gdx.gl10); Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT); squareMesh.render(GL10.GL_TRIANGLE_STRIP, 0, 4); nearSquare.render(GL10.GL_TRIANGLE_STRIP, 0, 4); } @Override public void resize(int width, int height) { float aspectRatio = (float) width / (float) height; camera = new OrthographicCamera(2f * aspectRatio, 2f); } @Override public void resume() { } }
这个新的正方形像第一个正方形的副本 但颜色不同。红色的正方形在X的正方向远离。新的正方形在它的左边。效果如下:
另一件事就是我们改变正方形的z 位置。注意红色正方形的的位置远离Z的负方向,蓝色正方形在红色正方形和viewer之间坐着。看截图很难看出来,因为我们用orthographic camera
基本忽略了Z坐标。改变resize()方法使用透视相机(PerspectiveCamera):
- <SPAN style="FONT-SIZE: 16px">publicvoid resize(int width,int height) {
- float aspectRatio= (float) width/ (float) height;
- camera= new PerspectiveCamera(67, 2f* aspectRatio, 2f);
- }</SPAN>
publicvoid resize(int width,int height) {float aspectRatio= (float) width/ (float) height; camera= new PerspectiveCamera(67, 2f* aspectRatio, 2f); }
现在2个正方形区别就大了:
在PerspectiveCamera 构造函数和OrthographicCamera 构造函数不同,前者多了一个view参数。我们传的67。人类可视透视区域大约是60-70度左右。所以67提供一个正常的视角。
注意默认值, PerspectiveCamera 裁剪任何一个比远离它的一个单位还近的对象。如果你放置一个太靠近camera的对象,它将消失。它也默认从远处裁剪在它前方100个单位,所以对象太远也不能被渲染
当我们移动相机透视感会变得更加明显。修改render()方法:
- <SPAN style="FONT-SIZE: 16px">privateint total = 0;
- private float movementIncrement =0.0006f;
- @Override public void render() {
- total += 1;
- if (total > 500) {
- movementIncrement = -movementIncrement;
- total = -200;
- }
- camera.rotate(movementIncrement * 20,0, 1,0);
- camera.translate(movementIncrement, 0, movementIncrement);
- camera.update();
- camera.apply(Gdx.gl10);
- Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
- squareMesh.render(GL10.GL_TRIANGLE_STRIP, 0,4);
- nearSquare.render(GL10.GL_TRIANGLE_STRIP, 0,4);
- }</SPAN>
private int total = 0; private float movementIncrement = 0.0006f; @Override public void render() { total += 1; if (total > 500) { movementIncrement = -movementIncrement; total = -200; } camera.rotate(movementIncrement * 20, 0, 1, 0); camera.translate(movementIncrement, 0, movementIncrement); camera.update(); camera.apply(Gdx.gl10); Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT); squareMesh.render(GL10.GL_TRIANGLE_STRIP, 0, 4); nearSquare.render(GL10.GL_TRIANGLE_STRIP, 0, 4); }
我们使用camera的rotate()和tranlate()方法来移动场景周围的camera。如上所述,当相机移动到很靠近蓝色正方形时,你看见他开始裁剪和消失。在OrthographicCamera上调用translate()将在没有提供3D空间的一个sense周围移动camera。看Mario's post 其他使用方法并测试。
Running it on Android
按照MyFirstTriangle教程设置android。记得引用必要的库文件,参考桌面工作,添加assets。运行后效果好像很大:
这个结果是我们锁定了顶点可视区域到2个单位高。默认,android模拟器高度大于宽度,我们的水平可视范围比3个单位宽度更小,这个APP与桌面的很不同。最简单的方法就是使
android和桌面相似,方法是让android app横向显示。修改你的manifest 然后设置android:screenOrientation="landscape" ,代码如下:
- <SPANstyle="FONT-SIZE: 16px"><activityandroid:nameactivityandroid:name=".ProjectionViewportCameraAndroid"android:label="@string/app_name"android:screenOrientation="landscape">
- <intent-filter>
- <actionandroid:name="android.intent.action.MAIN"/>
- <categoryandroid:namecategoryandroid:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- </activity></SPAN>
<activityandroid:name=".ProjectionViewportCameraAndroid" android:label="@string/app_name" android:screenOrientation="landscape"><intent-filter><action android:name="android.intent.action.MAIN"/> <categoryandroid:name="android.intent.category.LAUNCHER"/> </intent-filter></activity>
下面是锁定横屏后的截图。你能改变模拟器的方向涌ctrl+F11 或ctrl+F12
因为android设备有这么多不同的屏幕尺寸,锁屏还不够,你必须在不同的分辨率下测试你的游戏。最简单的方法就是通过桌面项目。在桌面工程启动的类中,创建一个480X320分辨率
的viewport。你的游戏在不同的设备上获得一个sense来测试长宽比。
Conclusion(结论)
现在关于mesh,sprite和camera你拥有足够的知识,开始构建一个你想要的scene。更多例子,可以看看libgdxdemosandtests。在downloads page你能抓取关于这个工程的源文件
原文地址:http://www.cnblogs.com/tianjian/archive/2011/09/01/2162281.html
- libgdx 学习笔记六 Projection,Viewport,Camera (投影,视口,相机)
- Camera Projection (相机投影)
- Camera Projection——相机投影
- Projection, viewport, & camera
- OpenGL投影矩阵与相机模型(Set Projection Matrix for Pinhole Camera Model)
- Applying Projection and Camera Views 运用投影和相机视图
- OpenGL学习脚印: 投影矩阵和视口变换矩阵(math-projection and viewport matrix)
- Cesium学习笔记(四): 相机(camera)
- libgdx 学习笔记(二)相机和观察点
- OGRE 学习笔记(Camera和Viewport)
- OGRE 学习笔记(Camera和Viewport)
- OGRE 学习笔记(Camera和Viewport)
- 透视投影(Perspective Projection)
- opencv学习-imgprocess-反向投影Back Projection
- libgdx Viewport
- 透视投影(Perspective Projection)变换推导
- ExtJS学习笔记(六) 面板的使用(Ext.Panle、Ext.TabPanel、Ext.Viewport)
- LibGdx学习笔记(一)
- libgdx 学习笔记二 绘制图像
- libgdx 学习笔记三 HelloWorld
- libgdx 学习笔记四 MyFirstTriangle
- libgdx 学习笔记五 MeshColorTexture
- Mysql无法通过mysqladmin来修改密码的解决办法
- libgdx 学习笔记六 Projection,Viewport,Camera (投影,视口,相机)
- libgdx 学习笔记七 libgdx应用程序生命周期
- libgdx 学习笔记八 Libgdx模块概述
- Ubuntu下编译Android源代码
- 图书管理系统中UML应用之需求分析和建模设计解析
- CString解析
- Ubuntu下载Android源代码和内核
- timeGetTime函数用法
- Ubuntu下配置Eclipse开发Android应用