User Tag List

Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 20 von 38

Thema: Noises und infinite Levels (Minecraft Style) (Voxel) Umsetzung?

  1. #1
    Mapping-Profi Avatar von eXi
    Registriert seit
    21.06.2010
    Ort
    Krefeld
    Alter
    28
    Beiträge
    2.554
    Renommee-Modifikator
    29

    Noises und infinite Levels (Minecraft Style) (Voxel) Umsetzung?

    Hey Leute,

    ganz am Anfang sei gesagt, bevor jemand umsonst weiter liest:

    Dieser Post dient der Diskussion zu dem Thema im Titel.

    Ich suche keine konkrete Hilfe, da ich nicht denke, dass jemand von euch sich damit schon beschäftigt hat.

    Da ihr aber alle recht wissenshunrig und diskussionsfreudig seid, fände ich es nett, wenn ihr vielleicht eure Ideen, Ratschläge und vielleicht sogar euer Wissen hier teilen könntet.
    Gleichermaßen teile ich gerne mein Wissen mit euch, vor allem in Form dieses Threads.

    Um das Thema mal konkret zu nennen: Die Erstellung einer Blockwelt, wie in Minecraft, welche zufällig erzeugt wird und endlos ist. (C# coding, Pseudecode)

    Wen das also nicht interessiert, der sollte nicht weiterlesen.

    Nun aber los.

    Ich bin momentan gedanklich ein wenig dabei mir ein Projekt für zwischendurch zu suchen. Einfach um mal nicht Ricochet zu machen und trotzdem etwas zum knobeln zu haben.
    Mein Auge fällt da recht schnell auf Voxelspiele. Also um es einfach auszudrücken auf Minecraft.

    Die Idee dahinter ist ja das Verfahren Noise (Unruhe) auf die Erstellung der Welt anzuwenden. Also eine Art "zufällige" Höhenkarte, wie man sie aus dem Atlas vielleicht kennt, auf die Höhe der Welt anzuwenden.

    Hier mal ein Bild einer solchen Noisemap.

    Spoiler für Feine Noisemap:




    Demnach geht man hin und definiert einen Chunk (ein Teilstück der Map, welches immer wieder geladen bzw gespeichert wird um die endlose Map darzustellen) mit zum Beispiel der Größe 20x20x20 Blöcken (1 Block 1x1x1 Units).
    Ohne Noise wäre das einfach "ein" Block 20x20x20 Units. Die Noisemap ändert dann allerdings die Höhen nach Graustufen.
    Lässt man nun in einer Renderreichweite, von zB 80 Units, Chunks laden, hätte man schon mal eine große Fläche mit Höhenunterschieden.
    Wenn ich das soweit richtig verstanden habe, lässt sich dort ein "Seed" einbauen, welcher bei gleicher Angabe die Welt immer gleich aussehen lässt, da die Verschiebung der Noisemap dann immer gleich ist.

    Soweit so gut. Jetzt kommt aber der schwierigere und interessantere Teil.

    Gehen wir mal davon aus wir haben 9 Chunks geladen. Also 3x3 Chunks mit jeweils 20x20x20 Blöcken und diese sind mit einer Noisemap erstellt.

    Nun fängt es an in meinem Kopf zu qualmen, denn angrenzende Chunks mit gleichen Übergängen zu erstellen, will mir nicht so recht in den Sinn kommen. Außerdem möchte ich auch unterschiedliche Blöcke innerhalb dieser Chunks haben.

    Also im Endeffekt, damit man sich das als Normalmensch mal vorstellen kann, wären das hier zB 9 Chunks:
    Spoiler:




    Was man relativ schnell sieht ist, dass man nicht direkt einen Block nimmt, sondern seine Faces (bzw die beiden Vertices eines Faces) rendert und zwar nur dann, wenn kein Face an ein anderes grenzt.
    Alles was unterhalb der Heightmap liegt, ist auch gar nicht erst vorhanden. Somit ist das, um es genauer auszudrücken, eine Fläche mit Würfelförmigen Erhöhungen (definiert durch die Noisemap). Die Bäume denken wir uns mal weg.

    Was auch noch auffällt ist, das es unter der normalen Bodenfläche Höhlen gibt. Nur aus Stein. Wenn ich mich nicht irre, dann ist das exakt die Art wie Minecraft momentan funktioniert und aussieht wenn man nur bestimmte Chunks hat, bzw wenn mal wieder der PC beim Rendern unter Java nicht nach kommt und man durch den Boden gucken kann.

    Gräbt man sich nun einen Block tiefer, so werden dort die alten Faces gelöscht und neue gerendert, weil ja keine weiteren mehr angrenzen.

    Soweit zum Verständnis, was das Resultat ist. Nun kommt aber mein Eingeschränktes Verständnis von Noises und Chunks ins Spiel. Denn wenn ich nach dem gezeigten Bild gehe, weiß der Chunk wie hoch die einzelnen Schichten sind und ersetzt dort die Textur und vor allem den Block Typ. Ich komme aber nur soweit, das ich alles aus einem Blocktypen erstelle. Also eine grüne Masse.
    Desweiteren hätten wir, wenn wir zum Beispiel auf dem Bild unser Auge auf den untersten Chunk werfen, würden wir nun einen weiteren Chunk dort unten links dran packen, bei dem Berg in den man so schön reingucken kann, eine grade abgeschnittene Fläche. Auf dem Bild sind die Übergänge zwischen den Chunks ja schon richtig, also würde das wohl nicht passieren. Das Wasser außer Acht gelassen, da ich dort noch keinen Gedanken dran verschwenden wollte.

    Also mein Problem, um den ganzen Text mal auf einen Nenner zu bringen, ist der Übergang zwischen Chunks und das nutzen verschiedener Blocktypen. Auch das Verständnis von Noises müsste erweitert werden.
    Wenn ich so eine Noisemap selber machen würde, müsste ich sie ja für jedes Biom (rein theoretisch) unterschiedlich machen. Also flach für Wüste und große Unterschiede für Berge.

    Mich würde jetzt, wie ganz oben geschrieben, eure Meinungen, Ideen, Erfahrung und euer Wissen dazu einmal interessieren.

    Wie würdet ihr das machen, habt ihr Ideen zu flüssigen Übergängen zwischen den Chunks?
    Wie könnte man so einen Chunk nach Höhen überprüfen? (Bei Minecraft ist zum Bespiel bekannt, auf welcher Höhe es Diamanten geben kann)
    Wie könnte man andere Blöcke einfügen, welche von der Höhe abhängen und ihr Anzahl und ihr Vorkommen rar machen?

    Angemerkt sei hier, das ich natürlich in Unity programmiere. Das ist für euch aber nicht vorausgesetzt. Es reicht Pseudocode, falls ihr Ideen habt. Unity arbeitet mit Vektoren. Demnach sind Punkt der Blöcke und Vertices festgelegt.

    Meine Idee zur Lösung ist momentan für jedes größere Gebiet eine große Noisemap zu erstellen und diese Abschnittweise für die Chunks zu nutzen. Am Rand der Noisemap, setzen wir eine fixe "Höhe" welche den Übergang zwischen zwei Biomen darstellt. Allerdings weiß ich nicht, wie das mit dem Seed dann funktionieren soll. Eine Verschiebung der Abschnitte auf der Noisemap würde nicht so viel Unterschied einbringen.
    Eine andere Idee wäre, die Chunks überlappen zu lassen von der Noisemap her. Das ist aber nur eine Idee in meinem Kopf und ich weiß gerade nicht wie das Umzusetzen ist.

    Naja, falls jemand von euch bis hier unten gelesen hat, würde ich mich über eine Antwort freuen. Vielleicht bleibt der Thread ja auch leer und ich knobel alleine weiter :'(

  2. #2
    Mapping-Profi Avatar von eMo
    Registriert seit
    10.12.2010
    Beiträge
    2.024
    Renommee-Modifikator
    21
    1.) Du lädst einfach immer 27 (3³) Chunks, so hast du einen fließenden Übergang zwischen den Chunks
    2.) Du speicherst die Chunkkoordinate mit oder gibst jedem, mit Textur belegtem, Voxel eine Koordinate mit. Ab einem bestimmten Z-Wert gibt es Diamant. Einfacher wäre wahrscheinlich ein Chunkkoordinatensystem.
    3.) Zufallszahlen. Wenn du auf einen neuen Chunk triffst, wird dieser sofort komplett generiert. Wird dabei bei der Koordinate (x,y,z) der Zufallswert von 0,99 überschritten (Zufallszahl zwischen (0,1) (ja, offenes Intervall, obwohl irrelevant, da Eintrittswahrscheinlichkeit in lR sowieso 0)) wird mit einer Wahrscheinlichkeit von 0,5^x, wobei x die Anzahl der erfolgreichen Durchgänge, in einer Koordinate außenrum ein weiterer Block des Blocktyps erstellt.
    Allgemein gehst du bei Erstellung des Chunks schichtweise vor, wobei die Wahrscheinlichkeit auf Luft immer weiter abnimmt (natürlich nur am obersten Chunk), unterirdische Chunks mit negativer Z-Koordinate haben dann auch einen Blocktyp Luft mit bestimmter Wahrscheinlichkeit.
    Ist dein Chunk fertig, glättest du ihn, sodass eine halbwegs nutzbare Fläche entsteht. Hierbei gehst du natürlich über die Chunkgrenzen hinaus, um auch außerhalb des Chunks zu glätten. Unbenutzte Chunks löscht du aus dem Speicher, speicherst sie aber ab und lädst die im Notfall wieder
    Ein kreativer Geist findet immer eine Möglichkeit, sich auszuleben.

  3. #3
    Stammgast Avatar von Nilo
    Registriert seit
    28.06.2010
    Beiträge
    1.192
    Renommee-Modifikator
    18
    eMo´s Lösungsvorschläge halte ich für sehr vielversprechend!
    Als erstes sind mir alte Videos von frühen Minecraft-Versionen in den Sinn gekommen. Da schien es genau die gleichen Probleme zu geben (Seeds, unterschiedliche Blöcke und Übergänge zwischen Chunks)
    Es gab früher noch keine Seeds, deutlich mehr abgeschnittene Berge und in einer der ersten Versionen auch noch Tests mit den unterschiedlichen Blöcken.
    Hier gibt es ein Video zum Entwicklungsverlauf in dem du das am Anfang ganz gut siehst: http://www.youtube.com/watch?v=W_-vFa-IyB8
    Reden ist Schweigen, Silber ist Gold

  4. #4
    Mapping-Profi Avatar von eXi
    Registriert seit
    21.06.2010
    Ort
    Krefeld
    Alter
    28
    Beiträge
    2.554
    Renommee-Modifikator
    29
    Gehen wir mal davon aus ich erstelle die Chunks über 3 for Schleifen von 0 bis 19, also 20 in alle Dimension. Dann müsste ich also die Position im Koordinatensystem überprüfen und ab einer bestimmten Höhe über eine if Abfrage die Zufallsvariable nutzen.

    Dennoch weiß ich nicht wie ich Chunks, welche "zufällig" über die Noisemap erstellt werden, fließend übergehen lassen soll. Der neue Chunk müsste ja demnach an der nächsten Stelle der Noisemap weitermachen. Irgendwann komm ich aber doch an den Punkt wo sich etwas wiederholt oder nicht?
    Wie gesagt, Noisemaps und ihre Benutzung hab ich noch nicht verstanden, obwohl ich mir schon Tuts reingezogen habe. Vielleicht denke ich auch zu quer.

    EDIT: @Nilo: Sehr interessant War Notch also auch nicht so intelligent am Anfang.

    Bei Version 0.0.14a hat er scheinbar mal das blockige weggelassen. Aber da sieh man, das die Koordinaten jedes Vertecis irgendwo gespeichert sind.
    Geändert von eXi (19.01.2014 um 23:28:06 Uhr)

  5. #5
    Mapping-Profi Avatar von eMo
    Registriert seit
    10.12.2010
    Beiträge
    2.024
    Renommee-Modifikator
    21
    Sagte ja, dass die Glättung anhand der schon vorhandenen Chunks entsteht. Sagen wir du nimmst eine einfache Glättung aus dem Mittel von 24 umherliegenden Voxeln (jeweils der höchste Voxel, der nicht vom Blocktyp Luft ist), so erhälst du am ende ein Chunk, der zu seinen Nachbarn passt
    Deswegen erstellst du ja zuerst für jeden Chunk eine eigene Noisemap, am besten lässt du die auch schonmal glätten, jedoch nur über die nächsten Nachbarn, und lässt den Chunk dann erst mit den Nachbarn glätten
    Ein kreativer Geist findet immer eine Möglichkeit, sich auszuleben.

  6. #6
    Mapping-Profi Avatar von eXi
    Registriert seit
    21.06.2010
    Ort
    Krefeld
    Alter
    28
    Beiträge
    2.554
    Renommee-Modifikator
    29
    Magst du mir vielleicht morgen einmal genauer darlegen was die Glättung ist. Also ich weiß was du damit meinst, aber Coding technisch kann ich mir das grad nicht vorstellen.
    Ich werde morgen mal fix ein Voxel und ein Chunk Script schreiben, welches Luft, Erde und Stein als Type hat und dann den Chunk per Noise aufbaut. Dann guck ich mal wie ich darauf das Glätten anwenden kann.

  7. #7
    Mapping-Profi Avatar von eMo
    Registriert seit
    10.12.2010
    Beiträge
    2.024
    Renommee-Modifikator
    21
    Nunja. Ist ein wenig schwierig zu erklären.
    (x-2,y-2) (x-1,y-2) (x,y-2) (x+1,y-2) (x+2,y-2)
    (x-2,y-1) (x-1,y-1) (x,y-1) (x+1,y-1) (x+2,y-1)
    (x-2,y) (x-1,y) (x,y) (x+1,y) (x+2,y)
    (x-2,y+1) (x-1,y+1) (x,y+1) (x+1,y+1) (x+2,y+1)
    (x-2,y+2) (x-1,y+2) (x,y+2) (x+1,y+2) (x+2,y+2)
    Du willst den geglätteten Wert der roten Koordinate (die z-Koordinate soll angepasst werden), also nimmst du die z + die Summe über alle 24 umliegenden z-Koordinaten von (x-2,y-2) bis (x+2,y+2) und teilst sie durch die Anzahl der Felder (25). Du erhälst einen geglätteten Wert, der im Mittel der anderen z-Koordinaten liegt.
    Ein kreativer Geist findet immer eine Möglichkeit, sich auszuleben.

  8. #8
    Mapping-Profi Avatar von eXi
    Registriert seit
    21.06.2010
    Ort
    Krefeld
    Alter
    28
    Beiträge
    2.554
    Renommee-Modifikator
    29
    Ok, ich versuch das morgen mal anzuwenden! Danke dir soweit (:

  9. #9
    Mapping-Profi Avatar von eMo
    Registriert seit
    10.12.2010
    Beiträge
    2.024
    Renommee-Modifikator
    21
    Kein Ding, helfe gerne, soweit ich es kann
    Ein kreativer Geist findet immer eine Möglichkeit, sich auszuleben.

  10. #10
    Ich habe nicht alles zu 100% gelesen, will aber was zum Aufbau vor allem zur Persistenz meine Meinung abgeben.

    Warum gibt es einen Seed und weshalb sieht eine Welt identisch aus wenn der Seed identisch ist?

    Antwort in einem Wort: Pseudo Zufallszahlen

    Wird auch in der Cryptografie eingesetzt. Über den Seed generiert ein Generator anscheinlich zufällige Zahlen die möglichst den ganzen Zahlenraum abdecken. Dadurch wird komplett alles berechnet. Es gibt keine wirklich zufällige zahl da sonst das Aussehen der World abweichen würde. Dadurch das diese "zufällige" Zahlen immer identisch ausgespuckt werden (wenn die Werte entsprechend stimmen) kann man darauf aufbauen. Das ist besonders Praktisch wenn weitere Chunks generiert werden sollen. Erst die Performance zwingt ja ein Spiel die Welt in kleinere Happen zu teilen damit alles noch in Echtzeit angezeigt werden kann. Wenn man den Ende eines vorhandenen chunks hat, kann man direkt mit den gespeicherten Werten weiter arbeiten. Grob sollte man sich das wie ein Offset vorstellen können wo der Generator seine Arbeit wieder aufnimmt und zwar mit den Daten die er zuletzt genutzt hat.

    Eine Glättung kann ich mir so nicht vorstellen aus dem einfachen Grund: Wenn der Client auf maximalen Radius gestellt hat dann sieht er den Rand der generierten Flächen. Diese müsste sich, wenn man sich der Chunks nähert, angeglichen werden je nachdem wie der nächste Chunk aussieht? Unwarscheinlich und auch unnötig.

    Es ist klar das solch ein Prozess nicht einfach ist. Es gibt aber einfache Teilschritte wie z.b. die Verteilung von Rohstoffen in der Erde. Zum Beispiel werden Diamanten zwischen lvl 15 und 0 vorkommen. Eisen von 50 runter. Es muss hier noch festgelegt werden wie stark sich ein Cluster bildet (anzahl der Rohstoffe insgesammt und anzahl der Rohstoffe in der direkten Umgebung), was bei Eisen viel höher liegt als bei Diamanten. Aber auch hier werden wohl konstanten verwendet (sonst, erneut, klappt es nicht mit dem 1:1 prinzip) die über den Pseudo Generator platziert werden.

    Was relativ einfach ist ist wohl Sand. Er ist im Grunde überall wo Wasser ist (Meer oder Fluss). Mit einem Festgelegten Bereich (z.b. 3) der mit dem Generator multipliziert wird (der die Position des Units weiß und z.b. 0,5 ausspuckt) = 1,5 = (int)1 Unit nach dem Wasser platziert wird. Clay, wie andere Erze, werden wohl im Nachhinein erzeugt mit der Bedingung das es nur Sand ersetzen kann.

    Will man sich selber was zusammenbauen dann sollte es so simpel wie möglich sein: Nur hügelland. Keine Höhlen, Bäume, Wasser (das sollten wohl alles nachträglich hinzugefügte erstellprozesse sein).
    Michael_Z <- -> Term!nator525

  11. #11
    Mapping-Profi Avatar von eMo
    Registriert seit
    10.12.2010
    Beiträge
    2.024
    Renommee-Modifikator
    21
    Das mit der Glättung siehst du eben falsch. Geglättet wird der generierte Chunk, nicht der vorhandene.
    Ich glaube schon, dass sie bei Minecraft auch eine Art Glättung benutzen um Chunks aufeinander abzustimmen.
    Ein kreativer Geist findet immer eine Möglichkeit, sich auszuleben.

  12. #12
    Mapping-Profi Avatar von eXi
    Registriert seit
    21.06.2010
    Ort
    Krefeld
    Alter
    28
    Beiträge
    2.554
    Renommee-Modifikator
    29
    Das mit der Glättung mach ich später. Sollte ich heute Abend Lust haben (denn gerade bin ich total kaputt), dann werde ich mal ein Voxel und ein Chunk Script schreiben. Dazu ein WorldGenerator der diese aufbaut und mit Blocktypen experimentieren. Also alles erstmal ohne Noise.

    Wenn ich den Verlauf von Minecraft mir angucke, hat Notch auch erstmal ohne Noise gearbeitet um die Chunks zu verstehen.

    @Michael Z. Das mit dem Seed ist richtig. Zufall gibt es nicht. Der einzige "Zufall" den man mit reinnehmen kann, ist die Zeit in der der PC gestartet wird, bzw hier wenn die Welt generiert wird. Allerdings kann ich dann keinen Seed mehr nehmen und ich will auch weniger eine Zufallsmap, sondern mehr eine durch Unruhe erzeugte Höhe. Ob die zufällig ist oder mit Faktoren exakt nachstelltbar, ist ja egal. Das ist eher sogar gut, wenn Spieler zB die Welt vom Lets Player nachspielen wollen.
    Geändert von eXi (20.01.2014 um 16:19:27 Uhr)

  13. #13
    Mapping-Profi Avatar von eMo
    Registriert seit
    10.12.2010
    Beiträge
    2.024
    Renommee-Modifikator
    21
    Soweit ich weiß, sind Seeds sowas wie Timestamps und in vielen Sprachen kann man damit den Zufallszahlengenerator neu initialisieren
    Ein kreativer Geist findet immer eine Möglichkeit, sich auszuleben.

  14. #14
    Mapping-Profi Avatar von eXi
    Registriert seit
    21.06.2010
    Ort
    Krefeld
    Alter
    28
    Beiträge
    2.554
    Renommee-Modifikator
    29
    Also bei Minecraft ist es meiner Meinung nach nur eine Zahl (auch wenn ich Buchstaben eintippe, ahoi ASCII Tabelle), welche als Offset, also wirklich nur als Verschiebung genutzt wird. Lass die von mir aus mal 1000 gerechnet sein, damit jede kleine Zahl große Wirkung hat.

  15. #15
    Mapping-Profi Avatar von eMo
    Registriert seit
    10.12.2010
    Beiträge
    2.024
    Renommee-Modifikator
    21
    Zitat Zitat von eXi Beitrag anzeigen
    Also bei Minecraft ist es meiner Meinung nach nur eine Zahl (auch wenn ich Buchstaben eintippe, ahoi ASCII Tabelle), welche als Offset, also wirklich nur als Verschiebung genutzt wird. Lass die von mir aus mal 1000 gerechnet sein, damit jede kleine Zahl große Wirkung hat.
    Wenn der Seed nur Offset wäre, würde das bedeuten, dass die Welt vor Generierung bereits bekannt ist. Ein Indie-Gamestudio will ein MMO mit der Technik rausbringen, irgendwas mit "No Man Sky", bei dem die Welt erforschbar und unbekannt, aber irgendwie vordefiniert ist, Minecraft hat das nicht, also muss der Seed doch die Zufallszahlen beeinflussen
    Ein kreativer Geist findet immer eine Möglichkeit, sich auszuleben.

  16. #16
    Mapping-Profi Avatar von eXi
    Registriert seit
    21.06.2010
    Ort
    Krefeld
    Alter
    28
    Beiträge
    2.554
    Renommee-Modifikator
    29
    Ja gut. Wir könnten beide mit dem selben Seed starten und so die selbe Welt haben. Was wir für den Seed bekommen, kann man nicht voraussagen. Das ist dann halt ein wenig Zahlendreherei. Aber grob gesagt ist es ein Offset.

  17. #17
    Mapping-Profi Avatar von eXi
    Registriert seit
    21.06.2010
    Ort
    Krefeld
    Alter
    28
    Beiträge
    2.554
    Renommee-Modifikator
    29
    Ok, also ich hab mich jetzt mal dran gesetzt. Ich hab allerdings ein wenig nach Tutorial gearbeitet, da ich bei Unity die Funktionen nicht alle zusammen suchen wollte.

    Ich hab die Code mal kommentiert (aber auf englisch, sollte wohl fitt gehen bei euch ).

    Momentan erstellt er mir einen 5x5x5 Chunk und setzt den type (0-2) je nach dem auf welcher Höhe j wir sind.
    0 = Luft, 1 = Erde, 2 = Stein

    War gar nicht mal so leicht die ganzen Seiten von dem Block zu definieren ohne sich andauernd im Kopf zu vertuen. Sah sehr lustig zwischendurch aus.

    So sieht das ganze momentan aus:

    Spoiler:




    Hier einmal die 4 Skripte:

    Spoiler für WorldGen:

    Code:
    using UnityEngine;
    using System.Collections;
    
    public class WorldGen : MonoBehaviour {
    
    	// New chunk
    
    	Chunk chunk;
    
    	// Use this for initialization
    	void Start() 
    	{
    		chunk = new Chunk();
    	}
    
    	void Update()
    	{
    		//chunk.Update();
    	}
    }


    Spoiler für VoxelMesh:

    Code:
    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    
    public class VoxelMesh
    {
    	// Mesh and material for each voxel
    
    	Mesh mesh;
    	Material mat;
    
    	// Lists of points, verticals and triangles to define the voxel
    
    	List<Vector3> Points;
    	List<Vector3> Verts;
    	List<int> Tris;
    
    	// List of UVs to draw a material on the voxel
    
    	List<Vector2> UVs;
    
    	// Creating the voxel as a GameObect (will be changed later due to limited numbers of GameObjects in Unity)
    
    	public GameObject gameobject;
    
    	// The half size of a Voxel that has width, height and depth = 1
    
    	float size = 0.5f;
    
    	// The position of the voxel
    
    	Vector3 position;
    
    	// Use this for initialization
    	public VoxelMesh(Vector3 ps, byte type) 
    	{
    		// Position, comes from the Voxel and the Chunk script to define the position of the new Voxel.
    		// The position is added on x, y and z
    
    		position = ps;
    
    		gameobject = new GameObject();
    
    		// Creating the Points List and adding the 8 points of the cube clockwise to the list
    
    		Points = new List<Vector3>();
    		Points.Add(new Vector3(position.x - size, position.y + size, position.z - size));
    		Points.Add(new Vector3(position.x + size, position.y + size, position.z - size));
    		Points.Add(new Vector3(position.x + size, position.y - size, position.z - size));
    		Points.Add(new Vector3(position.x - size, position.y - size, position.z - size));
    
    		Points.Add(new Vector3(position.x + size, position.y + size, position.z + size));
    		Points.Add(new Vector3(position.x - size, position.y + size, position.z + size));
    		Points.Add(new Vector3(position.x - size, position.y - size, position.z + size));
    		Points.Add(new Vector3(position.x + size, position.y - size, position.z + size));
    
    		// Creating the other Lists
    
    		Verts = new List<Vector3>();
    		Tris = new List<int>();
    		UVs = new List<Vector2>();
    
    		// Function to create the mesh. Gets the type to draw the right texture
    
    		CreateMesh(type);
    	}
    
    	private void CreateMesh(byte type)
    	{
    		// Adding the components that are needed to create the mesh
    
    		gameobject.AddComponent("MeshFilter");
    		gameobject.AddComponent("MeshRenderer");
    		gameobject.AddComponent("MeshCollider");
    
    		// Switch for loading the resources, based on the given type number
    
    		switch(type)
    		{
    			case 0:
    				mat = Resources.Load("Material/Air") as Material;
    				break;
    			case 1:
    				mat = Resources.Load("Material/Dirt") as Material;
    				break;
    			case 2:
    				mat = Resources.Load("Material/Stone") as Material;
    				break;
    			default:
    				Debug.LogWarning("Type no available, using default material!");
    				mat = Resources.Load("Material/Default") as Material;
    				break;
    		}
    
    		if(mat == null)
    		{
    			Debug.LogError("Material not found!");
    			return;
    		}
    
    		// Getting the Filter component and debug code
    
    		MeshFilter meshFilter = gameobject.GetComponent<MeshFilter>();
    
    		if(meshFilter == null)
    		{
    			Debug.LogError("MeshFilter not found!");
    			return;
    		}
    
    		// Sets "mesh" to the used mesh and the meshFilter and debug code
    
    		mesh = meshFilter.sharedMesh;
    
    		if(mesh == null)
    		{
    			meshFilter.mesh = new Mesh();
    			mesh = meshFilter.sharedMesh;
    		}
    
    		// Get the collider of the object and debug code
    
    		MeshCollider meshCollider = gameobject.GetComponent<MeshCollider>();
    
    		if(meshCollider == null)
    		{
    			Debug.LogError("MeshCollider not found!");
    			return;
    		}
    
    		// Clears the mesh, so that it can be updated again
    
    		mesh.Clear();
    		UpdateMesh();
    	}
    
    	private void UpdateMesh()
    	{
    		// Adds the vertecies based on the points to the list
    
    		// Front plane
    		Verts.Add(Points[0]); Verts.Add(Points[1]); Verts.Add(Points[2]); Verts.Add(Points[3]);
    		// Back plane
    		Verts.Add(Points[4]); Verts.Add(Points[5]); Verts.Add(Points[6]); Verts.Add(Points[7]);
    		// Left plane
    		Verts.Add(Points[5]); Verts.Add(Points[0]); Verts.Add(Points[3]); Verts.Add(Points[6]);
    		// Right plane
    		Verts.Add(Points[1]); Verts.Add(Points[4]); Verts.Add(Points[7]); Verts.Add(Points[2]);
    		// Top plane
    		Verts.Add(Points[5]); Verts.Add(Points[4]); Verts.Add(Points[1]); Verts.Add(Points[0]);
    		// Bottom plane
    		Verts.Add(Points[3]); Verts.Add(Points[2]); Verts.Add(Points[7]); Verts.Add(Points[6]);
    
    		// Adds the triangles clockwise to the list
    
    		// Front plane
    		Tris.Add(0); Tris.Add(1); Tris.Add(2);
    		Tris.Add(2); Tris.Add(3); Tris.Add(0);
    		// Back plane
    		Tris.Add(4); Tris.Add(5); Tris.Add(6);
    		Tris.Add(6); Tris.Add(7); Tris.Add(4);
    		// Left plane
    		Tris.Add(8); Tris.Add(9); Tris.Add(10);
    		Tris.Add(10); Tris.Add(11); Tris.Add(8);
    		// Right plane
    		Tris.Add(12); Tris.Add(13); Tris.Add(14);
    		Tris.Add(14); Tris.Add(15); Tris.Add(12);
    		// Top plane
    		Tris.Add(16); Tris.Add(17); Tris.Add(18);
    		Tris.Add(18); Tris.Add(19); Tris.Add(16);
    		// Bottom plane
    		Tris.Add(20); Tris.Add(21); Tris.Add(22);
    		Tris.Add(22); Tris.Add(23); Tris.Add(20);
    
    		// Adds the uv coordinates to the UVs list. It contains the coordinates of the face
    		// on which the texture will be drawn
    
    		// Front plane
    		UVs.Add(new Vector2(0,1));
    		UVs.Add(new Vector2(1,1));
    		UVs.Add(new Vector2(1,0));
    		UVs.Add(new Vector2(0,0));
    		// Back plane
    		UVs.Add(new Vector2(0,1));
    		UVs.Add(new Vector2(1,1));
    		UVs.Add(new Vector2(1,0));
    		UVs.Add(new Vector2(0,0));
    		// Left plane
    		UVs.Add(new Vector2(0,1));
    		UVs.Add(new Vector2(1,1));
    		UVs.Add(new Vector2(1,0));
    		UVs.Add(new Vector2(0,0));
    		// Right plane
    		UVs.Add(new Vector2(0,1));
    		UVs.Add(new Vector2(1,1));
    		UVs.Add(new Vector2(1,0));
    		UVs.Add(new Vector2(0,0));
    		// Top plane
    		UVs.Add(new Vector2(0,1));
    		UVs.Add(new Vector2(1,1));
    		UVs.Add(new Vector2(1,0));
    		UVs.Add(new Vector2(0,0));
    		// Bottom plane
    		UVs.Add(new Vector2(0,1));
    		UVs.Add(new Vector2(1,1));
    		UVs.Add(new Vector2(1,0));
    		UVs.Add(new Vector2(0,0));
    
    		// Adding the lists to the mesh
    
    		mesh.vertices = Verts.ToArray();
    		mesh.triangles = Tris.ToArray();
    		mesh.uv = UVs.ToArray();
    
    		// Clearing the lists, after they are already stored in the mesh
    
    		Verts.Clear();
    		Tris.Clear();
    		UVs.Clear();
    
    		// Gets the collider component from the gameobject
    
    		MeshCollider meshCollider = gameobject.GetComponent<MeshCollider>();
    
    		// Refreshs the calculated mesh
    
    		mesh.RecalculateNormals();
    		mesh.RecalculateBounds();
    
    		// Function for recalculating the tangents of the mesh
    
    		RecalculateTangents(mesh);
    
    		// Clears the mesh on the collider and sets it the constructed mesh from above
    
    		meshCollider.sharedMesh = null;
    		meshCollider.sharedMesh = mesh;
    
    		// Renders the material on the gameObject renderer
    
    		gameobject.renderer.material = mat;
    
    		// Some optimization code in background
    
    		mesh.Optimize();
    	}
    
    	private static void RecalculateTangents(Mesh mesh)
    	{
    		// Arrays for the mesh components
    
    		int[] triangles = mesh.triangles;
    		Vector3[] vertices = mesh.vertices;
    		Vector2[] uv = mesh.uv;
    		Vector3[] normals = mesh.normals;
    
    		// Length of the triangle and vertex array
    
    		int triangleCount = triangles.Length;
    		int vertexCount = vertices.Length;
    
    		// Two arrays of the size of the vertex array
    
    		Vector3[] tan1 = new Vector3[vertexCount];
    		Vector3[] tan2 = new Vector3[vertexCount];
    
    		// Not clear at the moment
    
    		Vector4[] tangents = new Vector4[vertexCount];
    	
    		for(long a = 0; a < triangleCount; a += 3)
    		{
    			long i1 = triangles[a];
    			long i2 = triangles[a + 1];
    			long i3 = triangles[a + 2];
    
    			Vector3 v1 = vertices[i1];
    			Vector3 v2 = vertices[i2];
    			Vector3 v3 = vertices[i3];
    
    			Vector2 w1 = uv[i1];
    			Vector2 w2 = uv[i2];
    			Vector2 w3 = uv[i3];
    
    			float x1 = v2.x - v1.x;
    			float x2 = v3.x - v1.x;
    			float y1 = v2.y - v1.y;
    			float y2 = v3.y - v1.y;
    			float z1 = v2.z - v1.z;
    			float z2 = v3.z - v1.z;
    
    			float s1 = w2.x - w1.x;
    			float s2 = w3.x - w1.x;
    			float t1 = w2.y - w1.y;
    			float t2 = w3.y - w1.y;
    
    			float div = s1 * t2 - s2 * t1;
    			float r = div == 0.0f ? 0.0f : 1.0f / div;
    
    			Vector3 sdir = new Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
    			Vector3 tdir = new Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);
    
    			tan1[i1] += sdir;
    			tan1[i2] += sdir;
    			tan1[i3] += sdir;
    
    			tan2[i1] += tdir;
    			tan2[i2] += tdir;
    			tan2[i3] += tdir;
    		}
    
    		for(long a = 0; a < vertexCount; ++a)
    		{
    			Vector3 n = normals[a];
    			Vector3 t = tan1[a];
    
    			Vector3.OrthoNormalize(ref n, ref t);
    			tangents[a].x = t.x;
    			tangents[a].y = t.y;
    			tangents[a].z = t.z;
    
    			tangents[a].w = (Vector3.Dot(Vector3.Cross(n, t), tan2[a]) < 0.0f) ? -1.0f : 1.0f;
    		}
    
    		// Setting the mesh.tangents to the recalculated tangents
    
    		mesh.tangents = tangents;
    	}
    }


    Spoiler für Voxel:

    Code:
    using UnityEngine;
    using System.Collections;
    
    public class Voxel
    {
    	// Position of the voxel
    
    	Vector3 position;
    
    	// A mesh from the VoxelMesh class
    
    	VoxelMesh mesh;
    
    	// The type for the block type
    
    	private byte Type;
    
    	// getter/setter function for other function to access this variable
    
    	public byte type
    	{
    		get { return Type;}
    		set { Type = value;}
    	}
    
    	// Creating the voxelMesh, based on the position and the type provided by the chunk function
    
    	public Voxel(Vector3 pos, byte t)
    	{
    		position = pos;
    		type = t;
    		mesh = new VoxelMesh(position, type);
    	}
    
    	// Not important at the moment (used for setting the air blocks to inactive in the
    	// checkNeighbor function
    
    	public void isActive(bool value)
    	{
    		mesh.gameobject.SetActive(value);
    	}
    
    }


    Spoiler für Chunk:

    Code:
    using UnityEngine;
    using System.Collections;
    
    public class Chunk
    {
    	// The size of the chunk
    
    	int width, height, depth;
    
    	// An 3 dimensional array for the voxels
    
    	Voxel[,,] voxels;
    
    	public Chunk()
    	{
    		// Setting the size of the array to the size of the chunk
    
    		width = 5;
    		height = 5;
    		depth = 5;
    
    		voxels = new Voxel[width,height,depth];
    
    		// Calling the function that will build the chunk
    
    		BuildChunk();
    	}
    
    	// Not important at the moment (used for checking the neighbors of each voxel and
    	// deactivating them, if they are air blocks)
    
    	public void Update()
    	{
    		//CheckNeighbors();
    	}
    
    	// Building the chunk of the size width, height and depth
    
    	private void BuildChunk()
    	{
    		for(int i = 0; i < width; i++)
    		{
    			for(int j = 0; j < height; j++)
    			{
    				for(int k = 0; k < depth; k++)
    				{
    					// Getting a random type of block between 0 and 3 (so 0,1 or 2)
    					// which is used for the block type 0 = air, 1 = dirt, 2 = stone
    
    					//byte type = (byte)Random.Range(0,3);
    					byte type = 0;
    
    					// Testing the types: Using the current height of the building chunk
    					// to set the type of the block
    
    					if(j < 3)
    						type = 2;
    					if(j == 3)
    						type = 1;
    					if(j == 4)
    						type = 0;
    
    					// Creating the Voxel only if the type is not 0 = air
    
    					if(type != 0)
    						voxels[i,j,k] = new Voxel(new Vector3(i,j,k), type);
    				}
    			}
    		}
    
    		//CheckNeighbors();
    	}
    
    	// Not important at the moment (used for checking the neighbors of each voxel and
    	// deactivating them, if they are air blocks)
    }


    Ganz am Ende vom Chunk Script hab ich was riesig langes zum Überprüfen der Voxelnachbarn (daher auch die CheckNeighbors() Funktion) mal raus geschnitten, da dies gerade unnütz ist und eh auskommentiert war.

    Ich weiß leider jetzt gerade nicht, ob das ein guter Start ist. Die erstellen GameObjects muss ich noch raus machen, weil Unity eine Begrenzung hat. Weiß gerade nicht wie sich das auswirken wird. Hinterher sollten nur noch die Chunks aus GameObject existieren.

    Irgendwelche Ideen wie man weiter machen könnte oder was man abändern muss, damit das Fortfahren einfacher wird.

    Fortfahren im Sinne von, mehrere Chunks und Noise.

    EDIT: Werde das morgen wohl nochmal um/neuschreiben. War eine schöne Übung um das zu verstehen, aber damit kann ich irgendwie nicht arbeiten.
    Geändert von eXi (21.01.2014 um 03:07:42 Uhr)

  18. #18
    Mapping-Profi Avatar von eXi
    Registriert seit
    21.06.2010
    Ort
    Krefeld
    Alter
    28
    Beiträge
    2.554
    Renommee-Modifikator
    29
    So, hab es neu gescripted. Nachdem ich gerafft hab, wie die Voxel funktionieren, hab ich diese nur noch als Chunks erstellt.

    Die Chunks sind momentan 16x128x16.
    Die erste Schicht ist nicht abbaubar.
    Die ersten 10 Schichten sind Stein mit vereinzelt Erde (einfach nur von einer Randomzahl abhängig gemacht).
    Die zweiten 10 Schichten sind Erde.
    Danach nur "Luft". Allerdings nicht als Blocktyp sondern einfach nicht gerendert.

    Steuerung:

    - WASD Laufen, Maus gucken
    - Linksklick Block entfernen
    - Rechtsklick ausgewählten Block setzen
    - Mausrad Blöcke wechseln. Momentan 4 verschiedene. Nummer auf dem Bildschirm zeigt Blocktyp an. Linksklick nutzt Block "0" also "Luft" für das entfernen
    - ESC beenden

    Lagt noch, da ich keine Ahnung hab wie man das optimieren kann.
    Chunks werden momentan nur erstellt und gelöscht, nicht gespeichert und geladen.
    Falls man mal durch Blöcke fällt liegt das am Collider vom Spieler. Hab da nur einen vorhandenen genommen. Auch das gucken durch Blöcke ist einfach nur nicht geändert. Geht gerade nur um die Chunks.
    Als nächstes käme die Noise einfügen. Hab das mal probiert, aber noch nichts dolles bei raus gekommen.

    Hier die Scripts:

    Spoiler für World:

    Code:
    using UnityEngine;
    using System.Collections;
    
    public class World : MonoBehaviour {
    
    
    
    	// Use this for initialization
    	void Start () 
    	{
    	
    	}
    	
    	// Update is called once per frame
    	void Update () 
    	{
    	
    	}
    
    	// Function to set a block a the position of the giving type "id"
    
    	public static void SetBlock(int id, Vector3 pos)
    	{
    		int x = (int) Mathf.Round(pos.x);
    		int y = (int) Mathf.Round(pos.y);
    		int z = (int) Mathf.Round(pos.z);
    
    		GameObject chunk = GetChunk(pos);
    	
    		// If the chunk is not empty and the pos.y is not over 128, than we
    		// are allowed to set a new block
    
    		if(chunk)
    		{
    			if(pos.y < 128 && pos.y != 0)
    			{
    				// Set the x,y,z to the pos of the new block and change the
    				// Block in the chunk Arraw at position x,y,z to the block
    				// of type "id"
    				x = x - (int)chunk.transform.position.x;
    				y = y - (int)chunk.transform.position.y;
    				z = z - (int)chunk.transform.position.z;
    
    				chunk.GetComponent<ChunkRenderer>().chunk[x,y,z] = id;
    
    				chunk.GetComponent<ChunkRenderer>().reRender = true;
    			}
    		}
    	}
    
    	// Function to "get" a chunk. We use a sphere collider to see if there are any 
    	// chunks in around the given position and return the founded colliders. Also
    	// we return "null" if we find nothing
    
    	public static GameObject GetChunk(Vector3 pos)
    	{
    		pos.x = (int)pos.x;
    		pos.y = (int)pos.y;
    		pos.z = (int)pos.z;
    
    		Collider[] chunksInPos = Physics.OverlapSphere(new Vector3(pos.x, 0, pos.z), 1);
    
    		foreach(Collider hit in chunksInPos)
    		{
    			for(int x = 0; x < 16; x++)
    			{
    				for(int z = 0; z < 16; z++)
    				{
    					if(hit.collider.gameObject.tag == "Chunk")
    					{
    						if(hit.collider.gameObject.transform.position + new Vector3(x,0,z) == new Vector3(pos.x,0,pos.z))
    						{
    							return hit.collider.gameObject;
    							break;
    						}
    					}
    				}
    			}
    		}
    
    		return null;
    	}
    
    }


    Spoiler für ChunkRenderer:

    Code:
    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    
    public class ChunkRenderer : MonoBehaviour {
    
    	// This is the actual chunk of the size 16x128x16. 128 is the heigth
    
    	public int[,,] chunk = new int[16,128,16];
    
    	// Used for generating the chunk
    
    	public int chunkSizeX = 16;
    	public int chunkSizeY = 128;
    	public int chunkSizeZ = 16;
    
    	// Used for the chunk position
    
    	public int chunkPositionX;
    	public int chunkPositionY;
    	public int chunkPositionZ;
    
    	// Reference to the player to destroy or generate chunks
    
    	public GameObject player;
    
    	// Used for rerendering the chunk and generate new chunks
    
    	public bool reRender = false;
    	public bool done = false;
    	public bool LastChunk = false;
    
    	// More Variable for trees etc.
    
    	// Use this for initialization
    	void Start () 
    	{
    		// Finding the player in the game
    
    		player = GameObject.Find("Player");
    
    		// Used for displaying the position in the name of the gameobject
    
    		chunkPositionX = (int)transform.position.x;
    		chunkPositionY = (int)transform.position.y;
    		chunkPositionZ = (int)transform.position.z;
    
    		this.name = "Chunk(" + chunkPositionX.ToString() + "," + chunkPositionY.ToString() + "," + chunkPositionZ.ToString() + ")";
    
    		// Filling the chunks with blocks. Later we are gonna change the id (atm 1) to the specific type of blocks
    
    		for(int x = 0; x < chunkSizeX; x++)
    		{
    			for(int y = 0; y < chunkSizeY; y++)
    			{
    				for(int z = 0; z < chunkSizeZ; z++)
    				{
    					int value = Random.Range(0, 200);
    					if(y == 0)
    						chunk[x,y,z] = 1;
    					if(y > 0 && y < 10)
    					{
    						if(value < 20)
    							chunk[x,y,z] = 2;
    						if(value >= 20)
    							chunk[x,y,z] = 1;
    					}
    					if(y >= 10 && y < 20)
    						chunk[x,y,z] = 2;
    					if(y >= 20)
    						chunk[x,y,z] = 0;
    
    				}
    			}
    		}
    
    		// Several other typs of blocks, for example trees
    
    
    
    		// Adding the MeshCollider for Colliding
    
    		if(!gameObject.GetComponent<MeshCollider>())
    		{
    			gameObject.AddComponent("MeshCollider");
    		}
    
    		ChunkRender(chunk);
    	}
    	
    	// Update is called once per frame
    	void Update () 
    	{
    		// Used for rerendering the chunk if for example a block was added or removed
    
    		if(reRender == true)
    		{
    			ChunkRender(chunk);
    			reRender = false;
    		}
    
    		// If the player is 16 units away from the chunk, destroy it. Later we will save the chunk
    		// And reload it if the player comes near it
    
    		if(Vector3.Distance(transform.position, player.transform.position) > 128)
    		{
    			Destroy(this.gameObject);
    		}
    
    		// If this chunk is the last Chunk (so he has chunks missing around him), we will add new chunks near him
    
    		if(LastChunk == true)
    		{
    			if(Vector3.Distance(transform.position, player.transform.position) < 64)
    			{
    				int Radius = 1;
    
    				for(int x = -Radius; x <= Radius; x++)
    				{
    					for(int z = -Radius; z <= Radius; z++)
    					{
    						// So if theres no chunk returned at this position, we gonna instatiate a new one
    
    						if(World.GetChunk(transform.position + new Vector3(x * 16,0,z *16)) == null)
    						{
    
    							Debug.Log("MORE CHUNKS!");
    							GameObject newChunk = Instantiate(this, transform.position + new Vector3(x * 16,0,z * 16), Quaternion.identity) as GameObject;
    
    							// Set LastChunk at this chunk to false and LastChunk to true at the new chunk
    
    							if(x == Radius || x == -Radius || z == Radius || z == -Radius)
    							{
    								if(newChunk)
    								{
    									LastChunk = false;
    									newChunk.GetComponent<ChunkRenderer>().LastChunk = true;
    								}
    							}
    						}
    					}
    				}
    			}
    		}
    	}
    
    	// Now the actual render progress for the chunk
    
    	Mesh ChunkRender(int[,,] chunk)
    	{
    		Mesh mesh = GetComponent<MeshFilter>().mesh;
    
    		if(mesh == null)
    		{
    			Debug.Log ("No Meshfilter found!");
    		}
    
    		// Lists for the mesh things
    
    		List<Vector3> vertices = new List<Vector3>();
    		List<Vector2> uvs = new List<Vector2>();
    		List<int> triangles = new List<int>();
    		List<int>[] indices = new List<int>[0];
    
    		int vertexIndex;
    
    		// Used to prevent out of bounce error
    
    		int top;
    		int bottom;
    		int front;
    		int back;
    		int left;
    		int right;
    
    		vertexIndex = 0;
    
    		// Clear the mesh to only have the new mesh in it
    
    		mesh.Clear();
    
    		for(int x = 0; x < chunkSizeX; x++)
    		{
    			for(int y = 0; y < chunkSizeY; y++)
    			{
    				for(int z = 0; z < chunkSizeZ; z++)
    				{
    					int block = chunk[x,y,z];
    
    					if(y == chunkSizeY - 1) { top = 0; } else { top = chunk[x,y + 1,z]; }
    					if(y == 0) { bottom = 0; } else { bottom = chunk[x,y - 1,z]; }
    					if(z == chunkSizeZ - 1) { right = 0; } else { right = chunk[x,y,z + 1]; }
    					if(z == 0) { left = 0; } else { left = chunk[x,y,z - 1]; }
    					if(x == chunkSizeX - 1) { front = 0; } else { front = chunk[x + 1,y,z]; }
    					if(x == 0) { back = 0; } else { back = chunk[x - 1,y,z]; }
    
    					int scale = renderer.material.mainTexture.width / 1024;
    					
    					float StartTexturePosition = -0.5F / scale + (float)block / 2 / scale + 0.005F;
    					float EndTexturePosition = StartTexturePosition + 0.5F / scale - 0.005F;
    
    					if(block > 0 && top == 0)
    					{
    						// Add vertices and triangles
    
    						vertices.Add(new Vector3(x, y + 1, z));
    						vertices.Add(new Vector3(x, y + 1, z + 1));
    						vertices.Add(new Vector3(x + 1, y + 1, z + 1));
    						vertices.Add(new Vector3(x + 1, y + 1, z));
    
    						triangles.Add(vertexIndex);
    						triangles.Add(vertexIndex + 1);
    						triangles.Add(vertexIndex + 2);
    						triangles.Add(vertexIndex + 2);
    						triangles.Add(vertexIndex + 3);
    						triangles.Add(vertexIndex);
    
    						// Add uvs
    
    						uvs.Add(new Vector2(StartTexturePosition, StartTexturePosition));
    						uvs.Add(new Vector2(StartTexturePosition, EndTexturePosition));
    						uvs.Add(new Vector2(EndTexturePosition, EndTexturePosition));
    						uvs.Add(new Vector2(EndTexturePosition, StartTexturePosition));
    
    						vertexIndex += 4;
    					}
    
    					if(block > 0 && bottom == 0)
    					{
    						// Add vertices and triangles
    						
    						vertices.Add(new Vector3(x, y, z));
    						vertices.Add(new Vector3(x + 1, y, z));
    						vertices.Add(new Vector3(x + 1, y, z + 1));
    						vertices.Add(new Vector3(x, y, z + 1));
    						
    						triangles.Add(vertexIndex);
    						triangles.Add(vertexIndex + 1);
    						triangles.Add(vertexIndex + 2);
    						triangles.Add(vertexIndex + 2);
    						triangles.Add(vertexIndex + 3);
    						triangles.Add(vertexIndex);
    						
    						// Add uvs
    						
    						uvs.Add(new Vector2(StartTexturePosition, StartTexturePosition));
    						uvs.Add(new Vector2(StartTexturePosition, EndTexturePosition));
    						uvs.Add(new Vector2(EndTexturePosition, EndTexturePosition));
    						uvs.Add(new Vector2(EndTexturePosition, StartTexturePosition));
    						
    						vertexIndex += 4;
    					}
    
    					if(block > 0 && right == 0)
    					{
    						// Add vertices and triangles
    						
    						vertices.Add(new Vector3(x, y, z + 1));
    						vertices.Add(new Vector3(x + 1, y, z + 1));
    						vertices.Add(new Vector3(x + 1, y + 1, z + 1));
    						vertices.Add(new Vector3(x, y + 1, z + 1));
    						
    						triangles.Add(vertexIndex);
    						triangles.Add(vertexIndex + 1);
    						triangles.Add(vertexIndex + 2);
    						triangles.Add(vertexIndex + 2);
    						triangles.Add(vertexIndex + 3);
    						triangles.Add(vertexIndex);
    						
    						// Add uvs
    						
    						uvs.Add(new Vector2(StartTexturePosition, StartTexturePosition));
    						uvs.Add(new Vector2(StartTexturePosition, EndTexturePosition));
    						uvs.Add(new Vector2(EndTexturePosition, EndTexturePosition));
    						uvs.Add(new Vector2(EndTexturePosition, StartTexturePosition));
    						
    						vertexIndex += 4;
    					}
    
    					if(block > 0 && left == 0)
    					{
    						// Add vertices and triangles
    						
    						vertices.Add(new Vector3(x, y, z));
    						vertices.Add(new Vector3(x, y + 1, z));
    						vertices.Add(new Vector3(x + 1, y + 1, z));
    						vertices.Add(new Vector3(x + 1, y, z));
    						
    						triangles.Add(vertexIndex);
    						triangles.Add(vertexIndex + 1);
    						triangles.Add(vertexIndex + 2);
    						triangles.Add(vertexIndex + 2);
    						triangles.Add(vertexIndex + 3);
    						triangles.Add(vertexIndex);
    						
    						// Add uvs
    						
    						uvs.Add(new Vector2(StartTexturePosition, StartTexturePosition));
    						uvs.Add(new Vector2(StartTexturePosition, EndTexturePosition));
    						uvs.Add(new Vector2(EndTexturePosition, EndTexturePosition));
    						uvs.Add(new Vector2(EndTexturePosition, StartTexturePosition));
    						
    						vertexIndex += 4;
    					}
    
    					if(block > 0 && front == 0)
    					{
    						// Add vertices and triangles
    						
    						vertices.Add(new Vector3(x + 1, y, z));
    						vertices.Add(new Vector3(x + 1, y + 1, z));
    						vertices.Add(new Vector3(x + 1, y + 1, z + 1));
    						vertices.Add(new Vector3(x + 1, y, z + 1));
    						
    						triangles.Add(vertexIndex);
    						triangles.Add(vertexIndex + 1);
    						triangles.Add(vertexIndex + 2);
    						triangles.Add(vertexIndex + 2);
    						triangles.Add(vertexIndex + 3);
    						triangles.Add(vertexIndex);
    						
    						// Add uvs
    						
    						uvs.Add(new Vector2(StartTexturePosition, StartTexturePosition));
    						uvs.Add(new Vector2(StartTexturePosition, EndTexturePosition));
    						uvs.Add(new Vector2(EndTexturePosition, EndTexturePosition));
    						uvs.Add(new Vector2(EndTexturePosition, StartTexturePosition));
    						
    						vertexIndex += 4;
    					}
    
    					if(block > 0 && back == 0)
    					{
    						// Add vertices and triangles
    						
    						vertices.Add(new Vector3(x, y, z + 1));
    						vertices.Add(new Vector3(x, y + 1, z + 1));
    						vertices.Add(new Vector3(x, y + 1, z));
    						vertices.Add(new Vector3(x, y, z));
    						
    						triangles.Add(vertexIndex);
    						triangles.Add(vertexIndex + 1);
    						triangles.Add(vertexIndex + 2);
    						triangles.Add(vertexIndex + 2);
    						triangles.Add(vertexIndex + 3);
    						triangles.Add(vertexIndex);
    						
    						// Add uvs
    						
    						uvs.Add(new Vector2(StartTexturePosition, StartTexturePosition));
    						uvs.Add(new Vector2(StartTexturePosition, EndTexturePosition));
    						uvs.Add(new Vector2(EndTexturePosition, EndTexturePosition));
    						uvs.Add(new Vector2(EndTexturePosition, StartTexturePosition));
    						
    						vertexIndex += 4;
    					}
    				}
    			}
    		}
    
    		// Add the vertices, triangles and uvs to the mesh
    
    		mesh.vertices = vertices.ToArray();
    		mesh.triangles = triangles.ToArray();
    		mesh.uv = uvs.ToArray();
    
    		// Recalculate it after that
    
    		mesh.RecalculateNormals();
    		mesh.RecalculateBounds();
    
    		// Set the mesh of the MeshCollider to the new mesh, but first clear it to be
    		// sure that only the new mesh is in it
    
    		GetComponent<MeshCollider>().sharedMesh = null;
    		GetComponent<MeshCollider>().sharedMesh = mesh;
    
    		return mesh;
    	}
    }


    Spoiler für ChunkGenerator:

    Code:
    using UnityEngine;
    using System.Collections;
    
    public class ChunkGenerator : MonoBehaviour {
    
    	public GameObject chunk;
    
    	public int PrevWorldSize;
    	public int WorldSize;
    
    	// Use this for initialization
    	void Start () 
    	{
    		PrevWorldSize = WorldSize;
    		GenerateChunks();
    	}
    	
    	// Update is called once per frame
    	void Update () 
    	{
    		
    	}
    
    	void GenerateChunks()
    	{
    		PrevWorldSize = WorldSize;
    
    		for(int x = -WorldSize; x <= WorldSize; x++)
    		{
    			for(int z = -WorldSize; z <= WorldSize; z++)
    			{
    				if(World.GetChunk(new Vector3(x * 16,0,z * 16)) == null)
    				{
    					Debug.Log("Chunk generated!");
    					GameObject newChunk = Instantiate(chunk, new Vector3(x * 16,0,z * 16), Quaternion.identity) as GameObject;
    					if(x == WorldSize || x == -WorldSize || z == WorldSize || z == -WorldSize)
    					{
    						newChunk.GetComponent<ChunkRenderer>().LastChunk = true;
    					}
    				}
    			}
    		}
    	}
    }


    Spoiler für PlayerScript:

    Code:
    using UnityEngine;
    using System.Collections;
    
    public class PlayerScript : MonoBehaviour {
    
    	public int currentBlockID;
    
    	public Vector3 position;
    
    	// Use this for initialization
    	void Start () 
    	{
    		Screen.lockCursor = true;
    	}
    	
    	// Update is called once per frame
    	void Update () 
    	{
    		Screen.showCursor = true;
    
    		ChooseBlockType();
    		ChangeBlock();
    
    		if(Input.GetKey(KeyCode.Escape))
    		{
    			Application.Quit();
    		}
    	}
    
    	void ChooseBlockType()
    	{
    		if(Input.GetMouseButtonDown(0) || Input.GetMouseButtonDown(1) || Input.GetAxis("Mouse ScrollWheel") > 0.0F || Input.GetAxis("Mouse ScrollWheel") < 0.0F) 
    		{
    			Screen.lockCursor = true;
    		}
    
    		if(Input.GetAxis("Mouse ScrollWheel") > 0.0F) 
    		{
    			if(currentBlockID > 1) 
    			{
    				currentBlockID -= 1;
    			} 
    			else 
    			{
    				currentBlockID = 8;
    			}
    		}
    		
    		
    		if(Input.GetAxis("Mouse ScrollWheel") < 0.0F)
    		{
    			if(currentBlockID < 8) 
    			{
    				currentBlockID += 1;
    			} 
    			else 
    			{
    				currentBlockID = 1;
    			}	
    		}
    	}
    
    	void ChangeBlock()
    	{
    		Ray ray = Camera.mainCamera.ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2, 0));
    		RaycastHit hit;
    		
    		if (Physics.Raycast(ray, out hit, 5F)) 
    		{		
    			position = new Vector3(Mathf.FloorToInt(hit.point.x - (hit.normal.x / 10)), Mathf.FloorToInt(hit.point.y - (hit.normal.y / 10)), Mathf.FloorToInt(hit.point.z - (hit.normal.z / 10)));
    			
    			position += hit.normal;
    			
    			if (Input.GetMouseButtonDown(1)) 
    			{	
    				if(Vector3.Distance(transform.position, position) > 0.5F)
    				{
    					World.SetBlock(currentBlockID, position);
    				}
    			}
    			
    			if (Input.GetMouseButtonDown(0)) 
    			{
    				position -= hit.normal;
    				World.SetBlock(0, position);
    			}
    		}
    	}
    
    	void OnGUI () 
    	{
    		GUI.Label(new Rect(Screen.width / 2 - 100,Screen.height / 2 - 299, 200, 20), currentBlockID.ToString());
    	}
    }


    Und hier das "Spiel".

    https://www.dropbox.com/s/w51bghs535...EngineTest.rar

    Falls das überhaupt noch jemanden interessiert
    Geändert von eXi (23.01.2014 um 00:06:58 Uhr)

  19. #19
    Stammgast Avatar von Nilo
    Registriert seit
    28.06.2010
    Beiträge
    1.192
    Renommee-Modifikator
    18
    Hört sich ja schon deutlich nach Fortschritt an
    Würde es gerne testen, aber ich bekommen folgende Fehlermeldung:
    There should be 'VoxelEngineTest_Data'
    folder next to the executable
    Geändert von Nilo (23.01.2014 um 00:04:11 Uhr)
    Reden ist Schweigen, Silber ist Gold

  20. #20
    Mapping-Profi Avatar von eXi
    Registriert seit
    21.06.2010
    Ort
    Krefeld
    Alter
    28
    Beiträge
    2.554
    Renommee-Modifikator
    29
    Ach, stimmt warte. Link wird geupdatet.

    Oben geupdated. Hier nochmal: https://www.dropbox.com/s/w51bghs535...EngineTest.rar
    Geändert von eXi (23.01.2014 um 00:07:59 Uhr)

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  
[email protected]