Estoy tratando de hacer un simple juego en 2D, y almaceno el mundo en una matriz 2D del bloque (una enumeración, con cada valor que tiene su textura).
Dado que estos son todos los azulejos opacos simples, al visualizarse en cierto modo me ellas por la textura y luego los hacen mediante la traducción a su coordenadas. Sin embargo, también necesito para especificar las coordenadas de textura y el vértice de cada baldosa que dibujo, a pesar de que estos también son los mismos.
Esto es lo que tengo actualmente:
public static void render() {
// Sorting...
for(SolidBlock block : xValues.keySet()) {
block.getTexture().bind();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
for(int coordinateIndex = 0; coordinateIndex < xValues.get(block).size(); coordinateIndex++) {
int x = xValues.get(block).get(coordinateIndex);
int y = yValues.get(block).get(coordinateIndex);
glTranslatef(x, y, Integer.MIN_VALUE);
// Here I use MIN_VALUE because I'll later have to do z sorting with other tiles
glBegin(GL_QUADS);
loadModel();
glEnd();
glLoadIdentity();
}
xValues.get(block).clear();
yValues.get(block).clear();
}
}
private static void loadModel() {
glTexCoord2f(0, 0);
glVertex2f(0, 0);
glTexCoord2f(1, 0);
glVertex2f(1, 0);
glTexCoord2f(1, 1);
glVertex2f(1, 1);
glTexCoord2f(0, 1);
glVertex2f(0, 1);
}
Me gustaría saber si es posible poner loadModel () antes de que el bucle principal, para no tener que cargar el modelo miles de veces con los mismos datos, y también qué otra cosa podía ser movido para que sea lo más rápido posible!
Algunas optimizaciones rápidas:
glTexParameteri
solo necesita ser llamada una vez por parámetro por la textura. Usted debe poner en la parte de su código donde se cargan las texturas.- Puede dibujar varios quads en uno
glBegin
/glEnd
par simplemente añadiendo más vértices. Sin embargo, no se puede hacer ninguna coordinar cambios entreglBegin
yglEnd
(comoglTranslatef
oglLoadIdentity
oglPushMatrix
) por lo que tendrá que pasarx
yy
que suloadModel
función (que en realidad debería llamarseaddQuad
de precisión). Asimismo, no está permitido volver a enlazar entre texturasglBegin
/glEnd
, por lo que tendrá que utilizar un conjunto deglBegin
/glEnd
por la textura. - Menor, pero en lugar de llamar
xValues.get(block)
a un montón de veces, sólo decirList<Integer> blockXValues = xValues.get(block)
al comienzo de su lazo externo y luego utilizarblockXValues
a partir de ahí.
Algunas optimizaciones más involucrados:
- Legado OpenGL tiene listas de sorteo, que son básicamente macros para OpenGL. Usted puede hacer todo el registro de OpenGL OpenGL llama que está haciendo entre
glNewList
yglEndList
(con algunas excepciones), y almacenarlos de alguna manera. La próxima vez que desee ejecutar esas llamadas exactas OpenGL, se puede utilizarglCallList
para hacer OpenGL hacer eso para usted. Algunas optimizaciones se hará sobre la lista de sorteo con el fin de acelerar los sorteos posteriores. - Textura de conmutación es relativamente caro, que ya se encuentra probablemente ha dado cuenta desde la ordenó su quads por la textura, pero no hay una solución mejor que las texturas de clasificación: Ponga todos sus texturas en un único atlas de textura . Usted querrá guardar las coordenadas subtexture de cada bloque dentro de sus
SolidBlock
s, y luego pasablock
aaddQuad
así para que pueda pasar las coordenadas apropiadas para subtextureglTexCoord2f
. Una vez que hayas hecho esto, no es necesario para ordenar por la textura más y sólo puede iterar sobre coordenadas X e Y.
Buenas practicas:
- Utilice sólo
glLoadIdentity
una vez por cuadro, al comienzo de su proceso de sorteo. A continuación, utiliceglPushMatrix
emparejado conglPopMatrix
guardar y restaurar el estado de las matrices. De esta manera las partes internas de su código no necesita saber acerca de las transformaciones de matriz las partes exteriores pueden o no pueden haber hecho de antemano. - No utilice
Integer.MIN_VALUE
como un vértice de coordenadas. Utilizar una constante de su propia elección, de preferencia uno que no hará que su rango de profundidad enorme (los dos últimos argumentos aglOrtho
que supongo que está utilizando). Precisión buffer de profundidad está limitada, se encontrará con problemas de extinción de Z si intenta coordenadas uso Z de 1 o 2 o así después de establecer su rango de ZInteger.MIN_VALUE
aInteger.MAX_VALUE
. Además, se está utilizandofloat
coordenadas, por lo queint
las constantes no tienen sentido aquí de todos modos.
Aquí está el código después de un pase rápido (sin la textura del atlas de cambios):
private static final float BLOCK_Z_DEPTH = -1; // change to whatever works for you
private int blockCallList;
private boolean regenerateBlockCallList; // set to true whenever you need to update some blocks
public static void init() {
blockCallList = glGenLists(1);
regenerateBlockCallList = true;
}
public static void render() {
if (regenerateBlockCallList) {
glNewList(blockCallList, GL_COMPILE_AND_EXECUTE);
drawBlocks();
glEndList();
regenerateBlockCallList = false;
} else {
glCallList(blockCallList);
}
}
private static void drawBlocks() {
// Sorting...
glPushMatrix();
glTranslatef(0, 0, BLOCK_Z_DEPTH);
for (SolidBlock block : xValues.keySet()) {
List<Integer> blockXValues = xValues.get(block);
List<Integer> blockYValues = yValues.get(block);
block.getTexture().bind();
glBegin(GL_QUADS);
for(int coordinateIndex = 0; coordinateIndex < blockXValues.size(); coordinateIndex++) {
int x = blockXValues.get(coordinateIndex);
int y = blockYValues.get(coordinateIndex);
addQuad(x,y);
}
glEnd();
blockXValues.clear();
blockYValues.clear();
}
glPopMatrix();
}
private static void addQuad(float x, float y) {
glTexCoord2f(0, 0);
glVertex2f(x, y);
glTexCoord2f(1, 0);
glVertex2f(x+1, y);
glTexCoord2f(1, 1);
glVertex2f(x+1, y+1);
glTexCoord2f(0, 1);
glVertex2f(x, y+1);
}
Con OpenGL moderna (buffers de vértices, shaders y la creación de instancias en lugar de las listas de visualización, transformaciones de matriz y pasando vértices uno por uno) que le acerque a este problema de manera muy diferente, pero lo tendré más allá del alcance de mi respuesta.