2012-12-13 6 views
13

Ich schreibe eine OpenGL ES 2.0 App, die eine 3D-Insel rendert. Ich habe bereits Code, um eine Himmelskuppel um die Insel herum zu erzeugen. Dies ist eine Halbkugel aus Dreiecken, die die Insel mit dem z-Punkt nach oben legen.Wie übertrage ich ein überzeugendes Skydome?

Die Kuppel hat einige sehr grundlegende bewegliche Wolken, die mit einer Perlin-Noise-Textur erstellt wurden, die über sich selbst gelegt wurde und unterschiedliche Geschwindigkeiten bewegte.

Aber letztlich muss ich die Kuppel auch machen:

  • Sun Moon (einschließlich Phase)
  • Sterne (in der Nacht)
  • Distant Land als statische Struktur (die über den Himmel Spuren)
  • Verschiedene Farben der Nacht, Dämmerung, Dämmerung, Tag

ich tun muss dies sehr effizient zu simulieren, da sie o landen n Android, obwohl es im Moment in einem Test-Kabelbaum läuft. So sind beispielsweise Sonne, Mond und Sterne nur Texturen, obwohl ihre Punkte mit angemessener Genauigkeit gezeichnet werden können.

Ich habe bereits den Code, um die Kuppel zu generieren, und Code, um eine Sonne gegen ein Datum und eine Zeit zu zeichnen. Hauptsächlich die Shader, die ich brauche und mit denen sie versorgt werden.

Gibt es ein Beispiel, das diese Dinge demonstriert? Ich habe eine Menge gefunden, die grundlegende Cube-Maps oder begrenzte Sachen, aber nichts auf dem Niveau der Raffinesse, die ich brauche. Offensichtlich, da dies OpenGL ES 2.0 ist, muss es in Shadern gemacht werden.

Der Shader für meine vorhandene Himmelskuppel rendert 2 Schichten Perlin Noise, um Wolken zu simulieren. Die Textur wird kontinuierlich umbrochen, so dass ich den Versatz basierend auf dem Winkel des Scheitelpunkts einer Kuppel in die xy-Ebene (indem man x und y in atan einspeist) und den v-Versatz mit dem Scheitelpunkt der Kuppel z berechnen kann.

Der Vertex-Shader zeigt, wie ich es tun:

#ifdef GL_ES 
precision mediump float; 
precision mediump int; 
#endif 

attribute vec4 aVertex; 

uniform mat4 uPMVMatrix; 
uniform float uTime; 
uniform float uSkyDomeRadius; 

const float PI = 3.1415926535897932384626433832795; 

varying vec2 texCoord0, texCoord1; 

void main() 
{ 
    vec2 centre = vec2(600., 600.); 

    gl_Position = uPMVMatrix * aVertex; 

    float slow_time = uTime/100.; 

    vec2 dome_point = aVertex.xy - centre; 
    float tex_u = atan(dome_point.x, dome_point.y);///(.25 * PI); 
    float tex_v = aVertex.z/(uSkyDomeRadius * .5); 

    texCoord0 = vec2(tex_u/2.0 + slow_time, tex_v/2.0); 
    texCoord1 = vec2(tex_u + slow_time/2.0, tex_v); 
} 

I u ein bisschen jeden Rahmen auch eine Zeit nutzen, um so versetzt, die Wolken bewegen. Dies funktioniert gut, außer atan geht von -PI zu PI und plötzlich die TexCoord0 und TexCoord1 Werte die Fragment Shader interpolates sind durch eine große Entfernung getrennt, die die Interpolation Schläuchen.

Der beste Weg, um es zu beschreiben ist, dass, wenn ich 16 Dreiecke an meiner Basis habe dann Interpolation von 0/16 bis 1/16 funktioniert, 1/16 bis 2/16 funktioniert und so weiter. Aber wenn ich zu 15/16 bis 0/16 komme, geht der Interpolator rückwärts und die große Variation bewirkt, dass der frag Shader die Textur in einem kleinen Feld wiederholt, was zu Streifen wie gezeigt führt.

Interpolation goes haywire as angle goes into reverse

kann ich sehen, jede mögliche Weise nicht eine nahtlose 360-Grad-Ansicht, die ich den einzige Weg, zu denken habe ich dieses Problem beheben werde, wenn ich die gesamte Kuppel drehen, damit die Naht immer hinter der Kamera, aber es könnte noch zeigen Sie an, ob die Kamera gerade auf die Spitze einer Kuppel zeigt.

Ein funktionierendes Beispiel mit Quelle wäre großartig, besonders wenn es diese Art von Problemen angeht.

+0

dumme Frage aber kann tex_x> PI oder <-PI – BevynQ

+0

tex_x wird immer zwischen PI und -PI sein, weil Atan diese Werte zurückgibt. Ich habe 16 Dreiecke an der Basis der Kuppel, so dass jede Dreiecksbasis einen Bogen von 2PI/16 oder PI/8 vorgibt. Also v0 könnte 3/16 der Weg herum sein und v1 4/16th und der so tex_x interpoliert richtig. Das Problem tritt auf, wenn v0 15/16 und v1 0/16 waren und die Interpolation vollständig geschraubt ist. Ich kann mir nicht vorstellen, wie ich das beheben kann, also spekuliere ich, dass ich die Kuppel drehen muss, so dass die Naht immer hinter der Kamera ist und versetze alles, was ich rendere, um einen entsprechenden Betrag. – locka

+0

Ich habe die Frage aktualisiert, um dies zu klären und tex_x und tex_y als tex_u und tex_v – locka

Antwort

3

Das Problem ist, dass Sie die gleichen Scheitelpunkte in einem Winkel von 0 ° und 360 ° verwenden. Sie haben jetzt ein Dreieck, in dem der erste Scheitelpunkt eine Texturkoordinate von 15/16, 0 und der zweite Scheitelpunkt 0, 0 anstelle von 1,0 hat.Um das zu beheben, müssen Sie die Kugel öffnen, so dass Sie ein Paar von Scheitelpunkten an den gleichen räumlichen Positionen haben, eine für 0 ° und eine für 360 °. Auf diese Weise können die zwei Vertices unterschiedliche Texturkoordinaten haben und es wird keine gestörten Texturen geben.

Um sie zu drehen, müssen Sie die Umbruchmodi verwenden, stellen Sie sicher, dass der Texturumbruch auf Wiederholen eingestellt ist. Wenn Sie es nicht geändert haben, sollte es korrekt eingerichtet sein, aber es kann mit der Funktion glTexParameter eingestellt werden, die Parameter sind GL_TEXTURE_WRAP_S und GL_TEXTURE_WRAP_T und der Wert muss GL_REPEAT sein. Wenn ein Texturwert> 1 ist, wird er nicht umgebrochen, sondern die Textur wiederholt. Jetzt müssen Sie nur noch die Scheitelpunkte am Anfang der Kugel (für Scheitelpunkte bei 0 °) von denen am Ende (für Scheitelpunkte bei 360 °) angeben können, damit Sie tex_u korrigieren können, Sie benötigen wahrscheinlich ein zusätzliches Attribut dafür .

+0

umbenannt. Danke, ich werde es versuchen. Ich bin mir bewusst, dass das Problem der Winkel ist, der effektiv auf Null zurückgeht, aber ich werde sehen, ob ich das Skydome auf irgendeine Weise erzeugen kann, die das kompensiert, wie etwa das, was du vorschlägst. – locka

Verwandte Themen