Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Di Jul 15, 2025 20:15

Foren-Übersicht » Programmierung » OpenGL
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 10 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: Heightmap -> Z-Koordinate errechnen
BeitragVerfasst: So Mär 20, 2011 13:17 
Offline
DGL Member

Registriert: So Mär 22, 2009 22:28
Beiträge: 26
Hallo,

Nochmal ne Frage...

Ich arbeite mit einer langsamen Scriptsprache, mal vorweg gesagt.
Für mein aktuelles Projekt möchte ich eine Heightmap verwenden, und mit einem Fahrzeug darauf herumgurken.
Ich habs jetzt erstmal so gelößt, dass die X und Y Koordinaten an einen Shader übergeben werden (glVertex2f) und der Shader errechnet anhand zweier Texturen die Z-Koordinate, Texturkoordinaten, sowie Texturierung für Gras (+Detailmap), Sand (+Detailmap) und Pflastersteine.

Jetzt stehe ich aber vor dem Problem, dass ich die Z-Koordinate von einem/mehreren beliebigen Punkt auf der Karte für die Physik brauche.
Ich hab versucht, mir diese Koordinate mit der Scriptsprache zu errechnen...
Code:
;Das ist ein Comment!

x := ((posx / heightmap_size) * heightmap_data_width)
fx := floor(x) ;Rundet die Zahl ab
dlx := x - fx ;Distanz zum nächst-niedrigeren Punkt
dux := 1 - dlx ;Distanz zum nächst-höheren Punkt

y := ((posy / heightmap_size) * heightmap_data_height)
fy := floor(y)
dly := y - fy
duy := 1 - dly
 
p11 := NumGet(heightmap_data, (fx + (fy * heightmap_data_height)) * 4, "float") ;Würde in C, so aussehen...    float p11 = heightmap_data[fx + (fy * heightmap_data_height)];
p21 := NumGet(heightmap_data, (fx + 1 + (fy * heightmap_data_height)) * 4, "float")
p12 := NumGet(heightmap_data, (fx + ((fy + 1) * heightmap_data_height)) * 4, "float")
p22 := NumGet(heightmap_data, (fx + 1 + ((fy + 1) * heightmap_data_height)) * 4, "float")
xz1 := (p11 * dlx) + (p12 * dux)
xz2 := (p21 * dlx) + (p22 * dux)
z := (dly * xz1) + (duy * xz2)

return z * heightmap_depth

Wenn ich aber mit meinem Fahrzeug, drüberbrettere, mit dieser Koordinate, hat es einen Treppeneffekt.
dux/y und dlx/y zu vertauschen bringt auch nicht das gewünschte Ergebniss.

Das selbe passiert, wenn ich versuche, den Teil der Heightmaptextur, im Hintergrund auf ein Quad zu rendern und die Farbe eines Pixels auslese.
Wobei jedoch, diese Lösung viel besser ist als die erste, obwohl ich nur GL_LUMINANCE als GL_FLOAT auslese.

Im Grunde errechnen beide Varianten, die korrekte Höhe, nur haben beide Varianten einen Treppeneffekt.
Ich hoffe mir kann da jemand damit helfen.

Anderes Thema:
Mich würde ausserdem auch interressieren, ob es möglich ist, bei einem Shader an einen Rückgabewert zu kommen.
Wenn ich einer uniform-Variable einen Wert zuweise gibts bei mir eine Compiler-Warnung (dachte das könnte Funktionieren, da es ja auch glGetUniform gibt)


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Mär 20, 2011 13:46 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Vielleicht solltest du genauer erklären was du unter "Treppeneffekt" verstehst. Mir ist das nämlich nicht klar. Stolpert dein Fahrzeug vielleicht einfach nur über die Kanten zwischen den Dreiecken?

Hier eine Delphi-Funktion die ich damals in Nettank benutzt habe. Das ganze ist wirklich verdammt alt...damals habe ich noch Delphi und DirectX benutzt...und Quelltext auf deutsch kommentiert :roll: ;)
Code:
// =============================================================================
// GetTerrainHeight
// =============================================================================
// Das ist die Funktion die den Panzer in meinem ersten Nettank auf dem
// Terrain ausrichtet. Rein kommt die aktuelle Position. Liegt diese Position
// z.B. unter oder in der Luft über dem Terrain, wird die y-Koordinate so
// angepasst das der Panzer auf dem Terrain ist.
// Die Terrainnormale wird "weich" berechnet, es gibt also keine "Sprünge" wenn
// der Panzer auf ein anderes Dreieck fährt.
// Die Funktionen quadTree.GetPoint() bzw. quadTree.GetNormal()
// machen nichts anderes als die Position (x,y,z) bzw. die Normale einer bestimmten
// Stelle (x,z) auf dem Terrain zurückzugeben.
function GetTerrainHeight( var pos: TD3DXVector3; getnormal: boolean ): TD3DXVector3;
var posA, posB, posC: TD3DXVector3;
    vecA, vecB, vecC: TD3DXVector3;
    facA, facB, facC: single;
    x, z: integer;
    polyN: TD3DXVector3;
    poly: TD3DXPlane;
begin
  if (pos.x < 0) then pos.x := 0;
  if (pos.z < 0) then pos.z := 0;
  if (pos.x > MapCount*(MapSize-1) ) then pos.x := MapCount*(MapSize-1);
  if (pos.z > MapCount*(MapSize-1) ) then pos.z := MapCount*(MapSize-1);
  //Minimal Punkt des Dreiecks
  x := trunc(pos.x);
  z := trunc(pos.z);
  //TerrainDreieck
  if ((pos.z - z) = 0) and ((pos.x - x) = 0) then begin
    //Wenn pos genau auf einem TerrainVertex liegt
    //(gibt sonst unten div!0   )
    pos := quadTree.GetPoint( x, z );
    result := quadTree.GetNormal( x, z );
    exit;
  end
  else if ((pos.z - z) >= (pos.x - x)) then begin
    //pos ist im Dreieck oben links
    posA := quadTree.GetPoint(     x,     z );
    posB := quadTree.GetPoint(     x, (z+1) );
    posC := quadTree.GetPoint( (x+1), (z+1) );
    if getnormal then begin
      vecA := quadTree.GetNormal(     x,     z );
      vecB := quadTree.GetNormal(     x, (z+1) );
      vecC := quadTree.GetNormal( (x+1), (z+1) );
    end;
  end
  else begin
    //pos ist im Dreieck unten rechts
    posA := quadTree.GetPoint(     x,     z );
    posB := quadTree.GetPoint( (x+1), (z+1) );
    posC := quadTree.GetPoint( (x+1),     z );
    if getnormal then begin
      vecA := quadTree.GetNormal(     x,     z );
      vecB := quadTree.GetNormal( (x+1), (z+1) );
      vecC := quadTree.GetNormal( (x+1),     z );
    end;
  end;
  //Normalenvektor des Dreiecks
  D3DXVec3Cross( polyN, D3DXVec3Subtract2( posC, posA ), D3DXVec3Subtract2( posB, posA ) );
  //Ebene aufstellen
  poly.a := polyN.x;
  poly.b := polyN.y;
  poly.c := polyN.z;
  poly.d := -( (poly.a*posA.x) + (poly.b*posA.y) + (poly.c*posA.z) );
  //Höhe ermitteln
  pos.y := -( (poly.a*pos.x) + (poly.c*pos.z) + poly.d ) / poly.b;
  if getnormal then begin
    //Normalvektor durchschnitt
    facA := 1 / sqrt( sqr(posA.x - pos.x) + sqr(posA.y - pos.y) + sqr(posA.z - pos.z) );
    facB := 1 / sqrt( sqr(posB.x - pos.x) + sqr(posB.y - pos.y) + sqr(posB.z - pos.z) );
    facC := 1 / sqrt( sqr(posC.x - pos.x) + sqr(posC.y - pos.y) + sqr(posC.z - pos.z) );
    result.x := ((vecA.x*facA)+(vecB.x*facB)+(vecC.x*facC)) / (facA+facB+facC);
    result.y := ((vecA.y*facA)+(vecB.y*facB)+(vecC.y*facC)) / (facA+facB+facC);
    result.z := ((vecA.z*facA)+(vecB.z*facB)+(vecC.z*facC)) / (facA+facB+facC);
    D3DXVec3Normalize( result, result );
  end
  else begin
    result.x := 0;
    result.y := 1;
    result.z := 0;
  end;
end;



Zitat:
Anderes Thema:
Mich würde ausserdem auch interressieren, ob es möglich ist, bei einem Shader an einen Rückgabewert zu kommen.
Wenn ich einer uniform-Variable einen Wert zuweise gibts bei mir eine Compiler-Warnung (dachte das könnte Funktionieren, da es ja auch glGetUniform gibt)

Uniforms können nicht im Shader gesetzt werden. Die Grafikkarte arbeitet hoch-parallel...also mit 100erten Instanzen des Shaders gleichzeitig. Wie soll den da das Ergebnis einer Shader-Instanz von der anderen Unterschieden werden? => Uniforms können nur gelesen werden.

Generell kannst du in ein Framebuffer-Objekt rendern und die erhaltene Textur wieder auslesen. Letzlich kommst du so als an Daten aus dem Fragmentshader. Eine andere Möglichkeit ist Transform-Feedback, was es erlaubt varying-Variablen aus dem Vertexshader (wenn Geometryshader benutzt wird: aus dem Geometryshader) abzufangen und in einem Buffer zu speichern. Dieser Buffer kann eine Textur oder ein Vertexbuffer-Objekt sein. Transform-Feedback benötigt relativ neue Hardware, während Framebuffer-Objekte schon älter sind.

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Mär 20, 2011 14:37 
Offline
DGL Member

Registriert: So Mär 22, 2009 22:28
Beiträge: 26
Der Treppeneffekt ist genau da wo ein Polygon endet und das nächste beginnt, an dieser Stelle "hüpft" das Fahrzeug auf oder ab, aber nur ein kleines Stück und links/rechts bzw oben/unten vom Polygon hab ich auch schon vertauscht.
Vielen dank, werde deinen Code mal genau unter die Lupe nehmen...

Danke auch für die Erklährung bezüglich der Rückgabe von Werten vom Shader.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Mär 20, 2011 15:53 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Naja, dann tritt der Treppeneffekt auf weil da ja auch wirklich ne Kante ist. ;)

Du kannst versuchen eine "weiche" Höhe zu berechnen statt dich an den tatsächlichen Dreiecken zu orientieren. Splines wären ein Stickwort dazu.

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Mär 20, 2011 17:30 
Offline
DGL Member

Registriert: Fr Okt 03, 2008 13:32
Beiträge: 367
Hm, also wenn ich deinen Code richtig interpretiere interpolierst du für die Höhe auf einem Quad. Das funktioniert allerdings nur wenn auch alle Punkte auf einer Ebene liegen. Versuch das mal indem du die Quads in 2 Dreiecke spaltest und bestimmst über welchen der Punkt sich befindet. Dann kannst du auf diesem die Höhe bestimmen.
Am besten ist du zeichnest das Terrain auch mit Triangles. Das Problem ist ja das sich die errechnete Höhe nicht mit dem deckt was man sieht. Das liegt daran das OpenGL Quads selbst teilt, weil es manchmal anders nicht zeichenbar wäre. Wenn es das so zeichnen würde wie du die Berechnungen anstellst, wären zwischen den Rechtecken Lücken, die genau die Stellen betreffen an denen das Fahrzeug springt.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Mär 21, 2011 14:40 
Offline
DGL Member

Registriert: So Mär 22, 2009 22:28
Beiträge: 26
Ok, ich habs jetzt für 3ecke berechnet, aber das Ergebniss ist das Selbe...
An einer weichen Berechnung liegt es auch nicht, denke ich mal.
Wenn es relativ Eben ist funktioniert es, wenn aber der Höhenunterschied größer ist, hüpft das Fahrzeug an den Kanten der Flächen.

Also die Blaue Linie zeigt, wie es in etwa sein soll.
Die Rote, wie es aktuell ist (etwas übertrieben).
Dateianhang:
hm.png


Der Code sieht jetzt so aus...
Code:
  x := x / heightmap_size * heightmap_data_width
  y := y / heightmap_size * heightmap_data_height
  x := (x<0) ? 0 : ((x>heightmap_data_width-1) ? heightmap_data_width-1 : x)
  y := (y<0) ? 0 : ((y>heightmap_data_height-1) ? heightmap_data_height-1 : y)

  fx := floor(x)
  fy := floor(y)


  if ((fx = x) && (fy = y))
    return NumGet(heightmap_data, (x + (y * heightmap_data_height)) * 4, "float")
  else if ((x - fx) > (y - fy))
  {
    A := NumGet(heightmap_data, (fx + (fy * heightmap_data_height)) * 4, "float")
    B := NumGet(heightmap_data, (fx + 1 + (fy * heightmap_data_height)) * 4, "float")
    C := NumGet(heightmap_data, (fx + 1 + ((fy + 1) * heightmap_data_height)) * 4, "float")

    hx := (A * ((fx+1)-x)) + (B * (x-fx))
    hy := (B * ((fy+1)-y)) + (C * (y-fy))
  }
  else
  {
    A := NumGet(heightmap_data, (fx + (fy * heightmap_data_height)) * 4, "float")
    B := NumGet(heightmap_data, (fx + 1 + ((fy + 1) * heightmap_data_height)) * 4, "float")
    C := NumGet(heightmap_data, (fx + 1 + (fy * heightmap_data_height)) * 4, "float")

    hx := (B * (x-fx)) + (C * ((fx+1)-x))
    hy := (C * (y-fy)) + (A * ((fy+1)-y))
  }
  return (hx + hy) * 0.5 * heightmap_depth

Ich denke mal eine weiche Berechnung kann ich mir auch sparen, da ich die Z-Koordinaten ja für jeden Reifen ermitteln will und die Rotation des Fahrzeuges auch danach ausrichten will.


Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Mär 21, 2011 18:23 
Offline
DGL Member
Benutzeravatar

Registriert: Mo Nov 08, 2010 18:41
Beiträge: 769
Programmiersprache: Gestern
bin ein bissl aus der übung was das angeht, aber ich versuchs einfach mal:

Code:
height = höhe(floor(reifen.xy))

dist.xy = abstand(reifen.xy,floor(reifen.xy))
if ( dist.x != 0)
{
      if(dist.x < 0)
           heightdiff = height- höhe(floor(reifen.xy) - (1.0,0.0))
      else
          heightdiff = height- höhe(floor(reifen.xy) + (1.0,0.0))
      trueheight.x = height - heightdiff* länge(dist.x);
}
else trueheight.x = height;

if ( dist.y != 0)
{
      if(dist.y < 0)
           heightdiff = height- höhe(floor(reifen.xy) - (0.0,1.0))
      else
          heightdiff = height- höhe(floor(reifen.xy) + (0.0,1.0))
      trueheight.y = height - heightdiff* länge(dist.y);
}
else trueheight.y = height;

reifen.z = (trueheight.x + trueheight.y)/2



oder so ähnlich :P

_________________
Meine Homepage


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Mo Mär 21, 2011 22:09 
Offline
DGL Member

Registriert: Fr Okt 03, 2008 13:32
Beiträge: 367
Bentschi hat geschrieben:
Ok, ich habs jetzt für 3ecke berechnet, aber das Ergebniss ist das Selbe...

Du verwendest in deimem Code 2mal dass selbe Dreieck, bloß das B und C vertauscht sind.
Wenn man das erste Dreieck so lässt, müsste der Punkt C für das 2te so aussehen:
Code:
C := NumGet(heightmap_data, (fx + ((fy + 1) * heightmap_data_height)) * 4, "float")

War möglicherweise einfach nur ein Schusselfehler.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Di Mär 22, 2011 16:14 
Offline
DGL Member

Registriert: So Mär 22, 2009 22:28
Beiträge: 26
Erstmal, danke an alle...
Ich denke mal, ich stehe kurz vor der Lösung, da ich jetzt nichtmehr das Verhältniss berechne, sondern Steigung/Gefälle-Berechnungen verwende.
Damit wäre es auch egal, wenn das 3eck nicht auf Linien ausgerichtet ist, wie bei einer Heightmap.
Wie dem auch sei..., ich melde mich sobald ich die Lösung herausgefunden habe.

Übrigens, auch nochmal danke, für meinen Schussel-Fehler, den hätte ich wohl so nicht bemerkt. :wink:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Mär 25, 2011 01:08 
Offline
DGL Member

Registriert: So Mär 22, 2009 22:28
Beiträge: 26
Ich hab jetzt eine simple Lösung gefunden...
Berechnet wirds aber für das gesamte quad und nicht 3eck.
Code:
  fx := floor(x)
  fy := floor(y)

  A := NumGet(heightmap_data, (fx + (fy * heightmap_data_height)) * 4, "float") * (fx+1-x) * (fy+1-y)
  B := NumGet(heightmap_data, (fx + 1 + (fy * heightmap_data_height)) * 4, "float") * (x-fx) * (fy+1-y)
  C := NumGet(heightmap_data, (fx + 1 + ((fy + 1) * heightmap_data_height)) * 4, "float") * (x-fx) * (y-fy)
  D := NumGet(heightmap_data, (fx + ((fy + 1) * heightmap_data_height)) * 4, "float") * (fx+1-x) * (y-fy)
  return (A+B+C+D) * heightmap_depth

Die Abweichung ist meist nur minimal, so dass ich es garnicht erst für 3ecke berechnen werde.
Also, danke auch an alle die geholfen haben! :wink:


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 10 Beiträge ] 
Foren-Übersicht » Programmierung » OpenGL


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 6 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.008s | 14 Queries | GZIP : On ]