2012-05-23 45 views
1

我使用下面的代碼合併多個網格:合併網格OpenGL和libgdx

import java.util.ArrayList; 
import java.util.Arrays; 

import org.obsgolem.crystalia.gfx.Renderer; 

import com.badlogic.gdx.graphics.Mesh; 
import com.badlogic.gdx.graphics.VertexAttribute; 
import com.badlogic.gdx.graphics.VertexAttributes.Usage; 
import com.badlogic.gdx.math.Vector3; 
import com.badlogic.gdx.utils.Array; 
import java.util.*; 

public class MeshBatch 
{ 

    private final static VertexAttribute[] attributeConfig = new VertexAttribute[]{ 
     new VertexAttribute(Usage.Position, 3, "a_position"), 
     new VertexAttribute(Usage.ColorPacked, 4, "a_color"), 
     new VertexAttribute(Usage.Normal, 3, "a_normal")}; 
    private final static int VERTEX_SIZE = 3 + 1 + 3; 

    private Mesh m; 
    private List<Float> vertices = new ArrayList<Float>(); 
    private List<Short> indices = new ArrayList<Short>(); 

    public void addMesh(float[] vert, short[] ind) 
    { 
     int offset = (vertices.size()/VERTEX_SIZE); 

     //You have to throw an exception when you get over the limit of short indices 
     if (offset + vert.length/VERTEX_SIZE > Short.MAX_VALUE) { 
      throw new RuntimeException("blablabla"); 
     } 

     for (short i : addOffset(ind, offset)) { 
      indices.add(i); 
     } 

     for (float v : vert) { 
      vertices.add(v); 
     } 
    } 

    public short[] addOffset(short[] ind, int offset) 
    { 
     short[] indarr = new short[ind.length]; 
     for (int i = 0; i < ind.length; ++i) { 
      //Do you really need this check? You are the only one using this code 
      //so make sure that you never provide a null value. If you really want to have a chekc throw an exception instead 
      short value = ind[i];//ind[i] == null ? 0 : ind[i]; 
      indarr[i] = (short) (value + offset); 
     } 
     return indarr; 
    } 


    public void end() 
    { 
     m = new Mesh(false, vertices.size(), indices.size(), attributeConfig); 
     m.setVertices(Renderer.makeFloatArray(vertices)); 
     m.setIndices(Renderer.makeShortArray(indices)); 
    } 

    public void render() 
    { 
     Renderer.getInstance().render(m); 
    } 
} 

然而,當我畫使用這個類,我與照明奇怪的效果。使用這個網格物體時,所有其他物體的光線都較亮,而渲染的物體則具有看起來平坦的照明。用正常的方式(每個對象分開單獨的網格),我可以很好的平滑點燃。這裏有兩個截圖我把:

隨着合併網:
Merged mesh lighting

沒有合併網:
Smooth per pixel lighting without merged mesh

是什麼原因造成的問題,以及它如何影響其他網的照明?我的頂點以適當的格式發送(3個頂點浮點數,1個顏色和3個法線)。我的指數也在起作用。僅當網格實際呈現時纔會出現問題。沒有它,照明完美地工作。我認爲這個問題與法線有關,但我無法弄清楚這個問題可能是什麼。

編輯:我想我已經解決了這個問題。當我使用單獨的網格物體切換到網格物體時,燈光會自行修復。這怎麼會發生?

+0

我不知道libgdx的想法,所以我不想回答。然而,有幾件事可能會有所幫助:(1)平面着色意味着臉部的所有法線指向相同的方向。所以請嘗試打印出來,看看是否是這種情況。 (2)計算遠離光線的距離也可能是一個問題。也許你所有的法線都指向相同的方向,但是你計算的距離與所有頂點的光線相同。我不知道你使用的是什麼燈光模型,所以我無法提供更多幫助。 – Max

+0

@Max我使用每個像素照明,只漫反射。每個網格都是一個立方體。不是立方體臉部應該有法線指向一個方向嗎? – jbills

+0

沒有足夠的信息來說出有用的東西。雖然如果您聲明它使用一個浮點數,但您將「4」發送給VertexAttribute以獲得顏色,這似乎很奇怪,但我不知道這個類是做什麼的。 – Tim

回答

0

這似乎很好地爲這個question的提問者的工作:

public static Mesh mergeMeshes(AbstractList<Mesh> meshes, AbstractList<Matrix4> transformations) 
{ 
    if(meshes.size() == 0) return null; 

    int vertexArrayTotalSize = 0; 
    int indexArrayTotalSize = 0; 

    VertexAttributes va = meshes.get(0).getVertexAttributes(); 
    int vaA[] = new int [va.size()]; 
    for(int i=0; i<va.size(); i++) 
    { 
     vaA[i] = va.get(i).usage; 
    } 

    for(int i=0; i<meshes.size(); i++) 
    { 
     Mesh mesh = meshes.get(i); 
     if(mesh.getVertexAttributes().size() != va.size()) 
     { 
      meshes.set(i, copyMesh(mesh, true, false, vaA)); 
     } 

     vertexArrayTotalSize += mesh.getNumVertices() * mesh.getVertexSize()/4; 
     indexArrayTotalSize += mesh.getNumIndices(); 
    } 

    final float vertices[] = new float[vertexArrayTotalSize]; 
    final short indices[] = new short[indexArrayTotalSize]; 

    int indexOffset = 0; 
    int vertexOffset = 0; 
    int vertexSizeOffset = 0; 
    int vertexSize = 0; 

    for(int i=0; i<meshes.size(); i++) 
    { 
     Mesh mesh = meshes.get(i); 

     int numIndices = mesh.getNumIndices(); 
     int numVertices = mesh.getNumVertices(); 
     vertexSize = mesh.getVertexSize()/4; 
     int baseSize = numVertices * vertexSize; 
     VertexAttribute posAttr = mesh.getVertexAttribute(Usage.Position); 
     int offset = posAttr.offset/4; 
     int numComponents = posAttr.numComponents; 

     { //uzupelnianie tablicy indeksow 
      mesh.getIndices(indices, indexOffset); 
      for(int c = indexOffset; c < (indexOffset + numIndices); c++) 
      { 
       indices[c] += vertexOffset; 
      } 
      indexOffset += numIndices; 
     } 

     mesh.getVertices(0, baseSize, vertices, vertexSizeOffset); 
     Mesh.transform(transformations.get(i), vertices, vertexSize, offset, numComponents, vertexOffset, numVertices); 
     vertexOffset += numVertices; 
     vertexSizeOffset += baseSize; 
    } 

    Mesh result = new Mesh(true, vertexOffset, indices.length, meshes.get(0).getVertexAttributes()); 
    result.setVertices(vertices); 
    result.setIndices(indices); 
    return result; 
} 

    public static Mesh copyMesh(Mesh meshToCopy, boolean isStatic, boolean removeDuplicates, final int[] usage) { 
    // TODO move this to a copy constructor? 
    // TODO duplicate the buffers without double copying the data if possible. 
    // TODO perhaps move this code to JNI if it turns out being too slow. 
    final int vertexSize = meshToCopy.getVertexSize()/4; 
    int numVertices = meshToCopy.getNumVertices(); 
    float[] vertices = new float[numVertices * vertexSize]; 
    meshToCopy.getVertices(0, vertices.length, vertices); 
    short[] checks = null; 
    VertexAttribute[] attrs = null; 
    int newVertexSize = 0; 
    if (usage != null) { 
     int size = 0; 
     int as = 0; 
     for (int i = 0; i < usage.length; i++) 
      if (meshToCopy.getVertexAttribute(usage[i]) != null) { 
       size += meshToCopy.getVertexAttribute(usage[i]).numComponents; 
       as++; 
      } 
     if (size > 0) { 
      attrs = new VertexAttribute[as]; 
      checks = new short[size]; 
      int idx = -1; 
      int ai = -1; 
      for (int i = 0; i < usage.length; i++) { 
       VertexAttribute a = meshToCopy.getVertexAttribute(usage[i]); 
       if (a == null) 
        continue; 
       for (int j = 0; j < a.numComponents; j++) 
        checks[++idx] = (short)(a.offset/4 + j); 
       attrs[++ai] = new VertexAttribute(a.usage, a.numComponents, a.alias); 
       newVertexSize += a.numComponents; 
      } 
     } 
    } 
    if (checks == null) { 
     checks = new short[vertexSize]; 
     for (short i = 0; i < vertexSize; i++) 
      checks[i] = i; 
     newVertexSize = vertexSize; 
    } 

    int numIndices = meshToCopy.getNumIndices(); 
    short[] indices = null; 
    if (numIndices > 0) { 
     indices = new short[numIndices]; 
     meshToCopy.getIndices(indices); 
     if (removeDuplicates || newVertexSize != vertexSize) { 
      float[] tmp = new float[vertices.length]; 
      int size = 0; 
      for (int i = 0; i < numIndices; i++) { 
       final int idx1 = indices[i] * vertexSize; 
       short newIndex = -1; 
       if (removeDuplicates) { 
        for (short j = 0; j < size && newIndex < 0; j++) { 
         final int idx2 = j*newVertexSize; 
         boolean found = true; 
         for (int k = 0; k < checks.length && found; k++) { 
          if (tmp[idx2+k] != vertices[idx1+checks[k]]) 
           found = false; 
         } 
         if (found) 
          newIndex = j; 
        } 
       } 
       if (newIndex > 0) 
        indices[i] = newIndex; 
       else { 
        final int idx = size * newVertexSize; 
        for (int j = 0; j < checks.length; j++) 
         tmp[idx+j] = vertices[idx1+checks[j]]; 
        indices[i] = (short)size; 
        size++; 
       } 
      } 
      vertices = tmp; 
      numVertices = size; 
     } 
    } 

    Mesh result; 
    if (attrs == null) 
     result = new Mesh(isStatic, numVertices, indices == null ? 0 : indices.length, meshToCopy.getVertexAttributes()); 
    else 
     result = new Mesh(isStatic, numVertices, indices == null ? 0 : indices.length, attrs); 
    result.setVertices(vertices, 0, numVertices * newVertexSize); 
    result.setIndices(indices); 
    return result; 
}