在随机地形的Libgdx网格上实现纹理的问题

我在理解如何将纹理应用到非矩形对象时遇到问题。 下面的代码创建如下的纹理:

在这里输入图像描述

从debugging渲染器,我认为我已经得到了“地球”的物理形状正确。 但是,我不知道如何应用纹理。 我有一个50×50像素的图像(在“dirt.png”的环境构造函数),我想申请山丘。 我有一个模糊的想法,这似乎涉及到网格类和可能的ShapeRenderer,但我在网上find的小只是让我感到困惑。

贝娄(Bellow)是一个代码,它是在一个单独的文件中制作和调节地形和代码的类,它应该呈现它(但是在mesh.render()调用中崩溃)。 任何指针将不胜感激。

public class Environment extends Actor{ Pixmap sky; public Texture groundTexture; Texture skyTexture; double tankypos; //TODO delete, temp public Tank etank; //TODO delete, temp int destructionRes; // how wide is a static pixel private final float viewWidth; private final float viewHeight; private ChainShape terrain; public Texture dirtTexture; private World world; public Mesh terrainMesh; private static final String LOG = Environment.class.getSimpleName(); // Constructor public Environment(Tank tank, FileHandle sfileHandle, float w, float h, int destructionRes) { world = new World(new Vector2(0, -10), true); this.destructionRes = destructionRes; sky = new Pixmap(sfileHandle); viewWidth = w; viewHeight = h; skyTexture = new Texture(sky); terrain = new ChainShape(); genTerrain((int)w, (int)h, 6); Texture tankSprite = new Texture(Gdx.files.internal("TankSpriteBase.png")); Texture turretSprite = new Texture(Gdx.files.internal("TankSpriteTurret.png")); tank = new Tank(0, true, tankSprite, turretSprite); Rectangle tankrect = new Rectangle(300, (int)tankypos, 44, 45); tank.setRect(tankrect); BodyDef terrainDef = new BodyDef(); terrainDef.type = BodyType.StaticBody; terrainDef.position.set(0, 0); Body terrainBody = world.createBody(terrainDef); FixtureDef fixtureDef = new FixtureDef(); fixtureDef.shape = terrain; terrainBody.createFixture(fixtureDef); BodyDef tankDef = new BodyDef(); Rectangle rect = tank.getRect(); tankDef.type = BodyType.DynamicBody; tankDef.position.set(0,0); tankDef.position.x = rect.x; tankDef.position.y = rect.y; Body tankBody = world.createBody(tankDef); FixtureDef tankFixture = new FixtureDef(); PolygonShape shape = new PolygonShape(); shape.setAsBox(rect.width*WORLD_TO_BOX, rect.height*WORLD_TO_BOX); fixtureDef.shape = shape; dirtTexture = new Texture(Gdx.files.internal("dirt.png")); etank = tank; } private void genTerrain(int w, int h, int hillnessFactor){ int width = w; int height = h; Random rand = new Random(); //min and max bracket the freq's of the sin/cos series //The higher the max the hillier the environment int min = 1; //allocating horizon for screen width Vector2[] horizon = new Vector2[width+2]; horizon[0] = new Vector2(0,0); double[] skyline = new double[width]; //TODO skyline necessary as an array? //ratio of amplitude of screen height to landscape variation double r = (int) 2.0/5.0; //number of terms to be used in sine/cosine series int n = 4; int[] f = new int[n*2]; //calculating omegas for sine series for(int i = 0; i < n*2 ; i ++){ f[i] = rand.nextInt(hillnessFactor - min + 1) + min; } //amp is the amplitude of the series int amp = (int) (r*height); double lastPoint = 0.0; for(int i = 0 ; i < width; i ++){ skyline[i] = 0; for(int j = 0; j < n; j++){ skyline[i] += ( Math.sin( (f[j]*Math.PI*i/height) ) + Math.cos(f[j+n]*Math.PI*i/height) ); } skyline[i] *= amp/(n*2); skyline[i] += (height/2); skyline[i] = (int)skyline[i]; //TODO Possible un-necessary float to int to float conversions tankypos = skyline[i]; horizon[i+1] = new Vector2((float)i, (float)skyline[i]); if(i == width) lastPoint = skyline[i]; } horizon[width+1] = new Vector2(800, (float)lastPoint); terrain.createChain(horizon); terrain.createLoop(horizon); //I have no idea if the following does anything useful :( terrainMesh = new Mesh(true, (width+2)*2, (width+2)*2, new VertexAttribute(Usage.Position, (width+2)*2, "a_position")); float[] vertices = new float[(width+2)*2]; short[] indices = new short[(width+2)*2]; for(int i=0; i < (width+2); i+=2){ vertices[i] = horizon[i].x; vertices[i+1] = horizon[i].y; indices[i] = (short)i; indices[i+1] = (short)(i+1); } terrainMesh.setVertices(vertices); terrainMesh.setIndices(indices); } 

这是(应该)呈现地形的代码。

 @Override public void render(float delta) { Gdx.gl.glClearColor(1, 1, 1, 1); Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT); // tell the camera to update its matrices. camera.update(); // tell the SpriteBatch to render in the // coordinate system specified by the camera. backgroundStage.draw(); backgroundStage.act(delta); uistage.draw(); uistage.act(delta); batch.begin(); debugRenderer.render(this.ground.getWorld(), camera.combined); batch.end(); //Gdx.graphics.getGL10().glEnable(GL10.GL_TEXTURE_2D); ground.dirtTexture.bind(); ground.terrainMesh.render(GL10.GL_TRIANGLE_FAN); //I'm particularly lost on this ground.step(); } 

那么,你需要做很多事情,以纹理随机地形。 在这一点上,你甚至没有纹理坐标在你的顶点。 但是假设你可以实现所有其他必需的步骤,一般方法很简单。

  1. 使用包装X和Y的纹理模式(在libgdx,Texture.TextureWrap.Repeat中)
  2. 使纹理坐标与顶点的世界位置成比例。

(现在我想起来,可能会使用“过度的巧妙”来避免纹理坐标,并且使着色器根据顶点的世界位置对纹理进行采样,但不知何故,这似乎是一个普遍不好的想法。


我的一些实现:

 private Mesh MakeMesh(float[] heights) { // SEGMENT_WIDTH = magic number for space between heights float[] verts = new float[10 * heights.length]; for (int i = 1; i <= (heights.length); i++){ verts[10 * i - 10] = (i - 1) * SEGMENT_WIDTH; verts[10 * i - 9] = heights[i - 1]; verts[10 * i - 8] = 0; verts[10 * i - 7] = (i - 1); verts[10 * i - 6] = 0; verts[10 * i - 5] = (i - 1) * SEGMENT_WIDTH; verts[10 * i - 4] = 0; verts[10 * i - 3] = 0; verts[10 * i - 2] = (i - 1); verts[10 * i - 1] = heights[i - 1] / SEGMENT_WIDTH; } short[] indices = new short[6 * heights.length]; for (short i = 1; i < heights.length; i++) { indices[6 * i - 6] = (short) (i * 2 - 2); indices[6 * i - 5] = (short) (i * 2 - 1); indices[6 * i - 4] = (short) (i * 2 - 0); indices[6 * i - 3] = (short) (i * 2 - 1); indices[6 * i - 2] = (short) (i * 2 - 0); indices[6 * i - 1] = (short) (i * 2 + 1); } mesh = new Mesh(Mesh.VertexDataType.VertexArray, true, verts.length / 5, indices.length, VertexAttribute.Position(), VertexAttribute.TexCoords(0)); mesh.setVertices(verts); mesh.setIndices(indices); return mesh; } 

并绘制:

 public void draw(Matrix4 worldView){ texture.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.Repeat); texture.bind(0); shader.begin(); shader.setUniformMatrix("u_worldView", worldView); shader.setUniformi("u_texture", 0); mesh.render(shader, GL20.GL_TRIANGLES); shader.end(); }