L'abattage des techniques pour un rendu beaucoup de cubes
Je suis en train de travailler sur un projet d'apprentissage pour faire un Minecraft clone. Il fonctionne très bien à part une chose. Similaire à Minecraft, mon terrain a beaucoup de cubes empilés sur l'axe de sorte que vous pouvez creuser. Bien que je ne frustum culling, cela signifie que je ne pas en tirer toutes les couches de cubes en dessous de moi. Les cubes sont X, Y et Z commandé (bien que dans 1 sens, si ce n'est pas techniquement Z a ordonné à la caméra). J'ai essentiellement à partir de la position du joueur seulement ajouter des pointeurs sur des cubes autour du joueur. Ensuite, je ne frustum culling contre ces. Je ne fais pas oct arbre de la subdivision. J'ai pensé tout simplement pas rendu les couches en dessous du lecteur, à l'exception de ce qui ne fonctionne pas si le joueur regarde vers le bas dans un trou. Compte tenu de cela, comment pourrais-je éviter de rendu des cubes en dessous de moi que je ne peux pas le voir, ou aussi les cubes qui sont cachés par d'autres cubes.
Grâce
void CCubeGame::SetPlayerPosition()
{
PlayerPosition.x = Camera.x / 3;
PlayerPosition.y = ((Camera.y - 2.9) / 3) - 1;
PlayerPosition.z = Camera.z / 3;
}
void CCubeGame::SetCollids()
{
SetPlayerPosition();
int xamount = 70;
int zamount = 70;
int yamount = 17;
int xamountd = xamount * 2;
int zamountd = zamount * 2;
int yamountd = yamount * 2;
PlayerPosition.x -= xamount;
PlayerPosition.y -= yamount;
PlayerPosition.z -= zamount;
collids.clear();
CBox* tmp;
for(int i = 0; i < xamountd; ++i)
{
for(int j = yamountd; j > 0; --j)
{
for(int k = zamountd; k > 0; --k)
{
tmp = GetCube(PlayerPosition.x + i, PlayerPosition.y + j, PlayerPosition.z + k);
if(tmp != 0)
{
if(frustum.sphereInFrustum(tmp->center,25) != NULL)
{
collids.push_back(tmp);
}
}
}
}
}
- Au moins, lorsque vous effectuez le rendu de tri d'avant en arrière, de sorte que vous rejetez tous les bas cubes rapidement. Mais un oct-arbre sera une bonne idée.
- Comment puis-je rendre à partir de l'avant vers l'arrière si mon angle est comme, 65 degrés sur x, 70 on y, dans ce cas, comment pourrais-je le faire sans faire une distance de vérifier à partir de la caméra du joueur?
- Le clonage d'un clone. Je suis très heureux que j'ai décidé de ne pas essayer de faire mon propre.
- La première utilisation d'un octree de minimiser le nombre de cubes que vous allez tirer. Puis trier par le carré de la distance. ("L'Occlusion de requête" est une chose que vous voudrez peut-être regarder ainsi.)
Vous devez vous connecter pour publier un commentaire.
Rendu de l'avant vers l'arrière. Pour ce faire, vous n'avez pas besoin de tri, utilisation octrees. Les feuilles ne seront pas en cubes, plutôt de grands groupes de personnes.
Un maillage pour chaque feuille doit être mis en cache dans un affichage de liste (comme Bobmitch suggéré) ou encore mieux dans un vertex buffer (moins cher à mettre à jour). Lorsque vous générez ce maillage ne pas générer tous les cubes dans un brute-force manière. Au lieu de cela, pour chaque face du cube vérifier si il est opaque voisin dans la même feuille, si vous n'avez pas besoin de générer ce visage. Vous pouvez également unifier voisins faces avec le même matériel en un seul long rectangle. Vous pouvez aussi séparer le maillage de six ensembles, un pour chaque direction principale: +/-XYZ visages. Dessiner uniquement les ensembles de faces qui peuvent faire face à la caméra.
Rendu de l'avant à l'arrière ne permet pas par elle-même. Cependant, vous pouvez utiliser l'occlusion culling offertes par les techniques modernes de matériel pour bénéficier de cette commande. Avant d'effectuer le rendu d'un octree de feuilles, de vérifier si sa bbox passe à l'occlusion de la requête. Si il ne passe pas, vous n'avez pas besoin de le dessiner à tous.
Approche Alternative à l'occlusion de la requête peut être de ray-tracing. Le lancer de rayons est bon pour le rendu d'un tel environnement. Vous pouvez jeter un éparses ensemble de rayons de rapprocher ce que les feuilles sont visibles et les feuilles seulement. Cependant, ce sera sous-estimer la visibilité de l'ensemble.
Voici ce que j'ai appris lors de l'écriture de mon propre clone:
D'autres choses que j'ai remarqué:
Organisations sises à vienne et l'affichage des listes de performance très similaire. C'est tout à fait possible que la mise en œuvre OpenGL utilise un VBO en interne pour stocker une liste d'affichage. J'ai sauté à droite par vertex arrays (une sorte de client-côté VBO) donc je ne suis pas sûr au sujet de ceux-ci. Utiliser le CEA extension version des Organisations sises à vienne à la place du GL de 1,5 standard, car les pilotes Intel seulement de mettre en œuvre l'extension (en dépit de se réclamant de 1,5) et la nvidia et ATI pilotes n'avez pas de soins.
Texture atlas de la règle. Si vous utilisez une texture par face, regardez comment les atlas de travail.
Si vous voulez voir mon code, me trouver sur github.
Comme les autres, j'ai été jouer avec un bloc de monde "moteur" à l'aide de l'Ogre et de l'écriture de certains articles que je vais (voir Bloc De Monde Articles). L'approche de base, j'ai été prise:
Juste à l'aide de ces pouvez-vous obtenir de très bonnes performances sur les gros bloc simple mondes (par exemple, 1024x1024x1024 sur matériel décent).
Je suis actuellement en train de travailler sur un clone de minecraft en python/pyglet, juste pour la curiosité.
J'ai décomposer les données en morceaux, comme dans minecraft, puis pour chaque morceau de créer un opengl displaylist basé sur le cube de la visibilité. J'ai ensuite effectuer une simple 2d frustum culling sur ces morceaux et chaque appel de la liste d'affichage à l'intérieur d'une certaine distance du joueur.
Sur cube ajout /retrait-je recréer la displaylist pour le bloc.
Il n'y a pas d'occlusion culling, sauf pour les cubes qui sont complètement entourés par d'autres cubes.
Pour de simples scènes, cela peut atteindre plus de 600fps sur une modeste carte gfx avec une distance de vue de près de 200 cubes.
Octtree etc. va travailler pour vous, mais une autre voie possible pour résoudre votre problème spécifique peut-être à la boutique pour ajouter un
usigned char visible
pour chaque objet cube. La valeur de lavisible
champ est calculé comme suit:Chaque fois que le joueur creuse un cube de suite, vous devez mettre à jour les
visible
champ de tous il est voisin des cubes.Mais comment cette aide? Si un cube est un
visible
valeur de 0, alors il est facile - le cube sera jamais montré. Mais disons que le cube a unvisible
valeur de 1. Puis le cube (pourrait) être visible, siXplayer < Xcube
. Les autres côtés de travail similaire, et je pense que comme une fonction qui décide si un cube peut être visible sera assez rapide et est capable de sauter un grand nombre de cubes cachés.L'inconvénient de cela, c'est que ce test n'est qu'une par-cube de test, et vous ne pouvez pas sauter complète des groupes avec qui. Alors, peut-être un octtree (pour sauter de compléter les régions), et un champ visible comme décrit ici, pour sauter le nombre élevé de caché cubes (Puisque ces cubes sont empilés, le nombre de cubes cachés sera beaucoup plus élevé que le nombre de ceux qui sont visibles) à l'intérieur de cette région pourrait être une bonne solution.
Vous pouvez utiliser PVS(Potentiellement visible à définir) pour cela, bien que son généralement pour le terrain, les mêmes principes s'appliquent, de les réformer ce qui ne peut être vu. Gamedev.net dispose d'un terrain de morphing article portant sur ce ainsi.
Dans le cas où seul le dessin est le problème (et pas la rotation de la partie inutilisée des sommets), ne pouvait pas être quelque chose comme c-tampon utile? Je l'ai utilisé avec un succès, il nécessite triés polygones (par exemple par l'algorithme du peintre) et à près de zéro de la mémoire (à l'inverse de z-buffer).
Seulement de garder la trace des cubes dans la description de votre surface. Vous pouvez le faire par un simple structure de données où chaque cube conserve une référence à ses voisins. Sur n'importe quelle carte graphique il ne devrait pas être un problème pour pousser tous ces triangles. Le rendu de l'arrière vers l'avant. Aussi seulement rendre des cubes rapproche alors d'une certaine distance à l'observateur. Le "monde" peut commencer avec un énorme "cube de cubes", la coquille externe du cube, formé par les cubes. Si quelqu'un creuse, vous avez le vérifier si le voisin endroits contient déjà des cubes ou pas, si ce n'est vous de créer les cubes et les lier dans.
Exemple: Creuser une surface plane: Supprimer le cube qui est placé à l'endroit où le creusement est fait, ajouter 9 nouveaux cubes en-dessous (Mais de vérifier si ces positions sont déjà en cours d'utilisation, en cas d'utilisation de ceux-ci), de lier l'ensemble de la surface, mais en reliant les nouveaux cubes pour le voisin cubes de celui qui a été déposé.
Donc:
Pour un monde contenant des 1000x1000x1000 cubes, vous obtenez: 1000*1000*2+998*999*4 = 5988008 au lieu de 1000*1000*1000 = 1000000000, ou un facteur de 167 moins nombre de cubes.
Bien sûr, vous ne devriez pas dessiner tous ces cubes, commencer avec de simples distance à l'observateur de faire une sous-sélection.
Vous pouvez aussi aller dans le regroupement de 8 cubes(groupes) ainsi que 1 un groupe, puis continuer comme ça jusqu'au niveau supérieur, vous avez juste un cube de groupe (oct-arbre déjà mentionné). Cet arbre peut être utilisé pour ray-trace dans quelle partie du monde vous avez besoin de tirer et de ne pas tirer. Si un groupe contient des références à 8 autres cubes-groupes, ceux de derrière n'est pas montré. Avec du retard dans ce seraient ceux cube-groupes qui ne se croisent pas ou de mise à l'extérieur d'un rayon du cône de départ de l'utilisateur et passe par le bord du groupe utilisé pour le test. (Mauvaise description, mais j'espère que vous obtenir quelques conseils de toute façon sur ce qui pourrait être fait pour l'optimisation). Ce ne serait probablement pas nécessaire sur les cartes graphiques d'aujourd'hui de toute façon.
Bonne chance avec votre projet.