Seite 1 von 1
Heightmap aus BMP (DirectX 10)
Verfasst: 27.11.2010, 21:27
von Jonsc1
Hallo
Ich habe mich seit langer Zeit mal wieder auf meine C++ IDE gestürzt und versucht mich in DirectX 10 einzuarbeiten.
Dank einiger guter Tutorials, der Doku und gewaltig viel Frustrationstoleranz habe ich bisher auch alles umsetzen können was ich mir vorgestellt habe.
Bei meinem jetzigen Problem hänge ich allerdings gewaltig, weil ich keinen anständigen Ansatz habe es umzusetzen.
Ich habe einen kleinen Algorithmus der mir in einem quadratischen Gitter angeordnete Vertices erzeugt, und passende Indices um ein flaches "Terrain" zu rendern, sprich einfach nur eine grosse Fläche bestehend aus unnötig vielen Dreiecken.
Nun möchte ich den position.y Wert anhand einer "Heightmap" modulieren, sprich ein 24bit bmp File laden und entsprechend der Graustufe die Höhen anpassen.
Und genau da häng ich....
Ich hab das selbe mal mit DirectX 8 und der D3DX-Bibiothek gemacht, aber ich kann es einfach nicht portieren.
Das ist momentan mein Ansatz (und ich hatte schon etliche davor, die aber alle nicht funktioniert haben)
Code: Alles auswählen
// heightmap laden
ID3D10Resource* heightmaptex;
D3DX10CreateTextureFromFile(m_device, L"heightmap.bmp", NULL, NULL, &heightmaptex, NULL);
Ich bitte euch nun also um Hilfe, wie kann ich aus dieser geladenen Textur die Graustufen herrauslesen?
Ich würde wirklich nicht fragen wenn ich nicht schon vieles vergeblich versucht habe :roll:
Re: Heightmap aus BMP (DirectX 10)
Verfasst: 27.11.2010, 22:16
von eXile
Wichtig ist erst einmal, dass du beim Erstellen D3D10_USAGE_STAGING in der D3DX10_IMAGE_LOAD_INFO angibst. Nach dem Laden Mapst du die Textur mit D3D10_MAP_READ, und hast dann im Parameter pMappedTex2D die Pixeldaten stehen.
Ich würde aber eher das allgemeine Vorgehen überdenken: Da du wohl eher das Terrain im Vertex-Shader verändern willst, wäre es vielleicht sinnvoller, die Textur auf die GPU zu laden, anstatt vortransformierte Vertices zu verwenden. Aber das hängt vom Anwendungsfall ab.
Re: Heightmap aus BMP (DirectX 10)
Verfasst: 28.11.2010, 02:57
von Jonsc1
Hi!
Danke für die schnelle Antwort.
D3D10_USAGE_STAGING benötige ich, so nehme ich an, dass ich via CPU auf der Textur lesen kann (was ich ja tun möchte), alle anderen Parameter incl. dem Standard scheinen das auszuschliessen.
Korrigiere mich bitte wenn ich das falsch verstanden habe.
Ich würde die Textur nun gerne Mappen, allerdings existiert keine Funktion ID3D10Resource::Map(), allerdings existiert ID3D10Texture2D::Map(), Problem dabei ist nun allerdings dass D3DX10CreateTextureFromFile nunmal explizit einen Pointer auf eine ID3D10Resource zurückgibt.
Gehe ich richtig in der Annahme dass ich das irgendwie ineinander überführen muss?
Noch eine Frage:
Was habe ich für einen Vorteil die Höhendaten erst im Vertexshader einfliessen zu lassen, schliesslich soll es ja ein statisches Terrain sein.
Ich nehme an ich würde dass für solche Dinge wie Wasser benötigen? In welchen Situationen ist es noch von Vorteil?
Re: Heightmap aus BMP (DirectX 10)
Verfasst: 28.11.2010, 11:53
von Altair
Du kannst ganz einfach:
Code: Alles auswählen
ID3D10Texture2D* heightmaptex;
D3DX10CreateTextureFromFile(m_device, L"heightmap.bmp", NULL, NULL, (ID3D10Resource**)&heightmaptex, NULL);
schreiben. Denn ID3D10Texture ist von ID3D10Resource abgeleitet und deswegen kannst du das umcasten.
Mfg Altair
Re: Heightmap aus BMP (DirectX 10)
Verfasst: 28.11.2010, 12:34
von eXile
Jonsc1 hat geschrieben:Was habe ich für einen Vorteil die Höhendaten erst im Vertexshader einfliessen zu lassen, schliesslich soll es ja ein statisches Terrain sein.
Ich nehme an ich würde dass für solche Dinge wie Wasser benötigen? In welchen Situationen ist es noch von Vorteil?
Für ein statisches Terrain alleine ist das eine legitime Lösung! Aber ganz generell gibt es Situationen beim Rendern von vollkommen anderen Objekten, wo du auf die Höheninformationen aus der Heightmap zugreifen willst: Wie du schon gesagt hast, wenn du Wasser rendern möchtest, und dieses in z.B. tiefen Regionen dunkler erscheinen soll. Oder wenn du ein Partikelsystem einbaust, das auf dem Terrain arbeitet. Oder einen Nebel in tieferen Regionen malen willst. Oder ein komplexes Animationssystem, bei welchem du die Füße von Personen genau auf dem Terrain ausrichten möchtest, und keine schwebenden Füße haben willst. Oder ganz allgemein: Es hält dir mehr Möglichkeiten offen ;)
Re: Heightmap aus BMP (DirectX 10)
Verfasst: 28.11.2010, 14:36
von Jonsc1
Ich habe halt immer Angst dass sowas sehr zu Lasten der Performance geht, aber ich nehme an das die Hardware mit ein paar extra Multiplikationen mittlerweile kein Problem mehr hat :)
Denke das Prinzip ist die Heightmap als Shader Resource zu laden und dann im Vertexshader die Farbwerte in den position.y Wert einzurechnen... nur wie mach ich das?
Bin nicht besonders gut mit HLSL, hab die Textur nun Geladen und im Pixelshader auch Zugriff darauf, aber im Vertexshader? :/
Re: Heightmap aus BMP (DirectX 10)
Verfasst: 28.11.2010, 15:01
von eXile
Ich sehe da prinzipiell zwei Möglichkeiten: Einmal via Vertex Texture Fetch im Vertex-Shader (SM 3.0) oder einen Geometry-Shader benutzen (SM 4.0). Meiner Meinung nach (hoffentlich stimmt das auch alles) würde ich letzteres benutzen. Eine "Standard-Möglichkeit" wäre auch gleich die benutzung von Clipmaps, siehe
hier (das benutzt auch gleich Vertex Texture Fetch). Im Forum gabs dazu auch schon einmal einen Thread, siehe
hier.
Oder zu bleibst einfach bei deiner statischen Geometrie ;)
Re: Heightmap aus BMP (DirectX 10)
Verfasst: 28.11.2010, 15:51
von Jonsc1
Sorry wenn ich so dumm frage, aber ich bekomm es einfach nicht hin.
Mein Shader kompiliert einfach nicht, was daran liegt dass ich es anscheinend nicht richtig verstehe.
tex2Dlod nimmt garkeinen Bezug auf irgendeine Textur, ich verstehe die Funktionsweise vorne und hinten nicht.
Wenn ich im Pixelshader auf meine Textur bezug nehme dann so:
Texture.Sample(ss, Tex);
Aber im Vertexshader? Kann mir da jemand ein Codeschnipsel posten?
Re: Heightmap aus BMP (DirectX 10)
Verfasst: 28.11.2010, 16:22
von Krishty
SampleLevel()
Ich habe auch ehrlich gesagt nie verstanden, wo man die
tex*-Funktionen einsetzen kann.
Re: Heightmap aus BMP (DirectX 10)
Verfasst: 28.11.2010, 17:42
von Jonsc1
Habs jetzt mal nicht mit SampleLevel() versucht sonder mit tex2Dlod(), Problem ist nur, sobald ich die Kommentierung der Funktion wegnehme und versuche sie auszuführen, wird der Shader nicht mehr kompiliert
Code: Alles auswählen
float4x4 WorldMat;
float4x4 CamMat;
Texture2D Heightmap;
SamplerState displacementSampler
{
Texture = (Heightmap);
AddressU = Clamp;
AddressV = Clamp;
};
// Vertexshader - Rückgabe
struct VSOut
{
float4 Col : COLOR; // vertex farbe
float2 Tex : TEXCOORD; // texturkoordinaten
float4 Pos : SV_POSITION; // vertex position
};
// Vertexshader
VSOut VS(float4 Pos : POSITION, float4 Col : COLOR, float2 Tex : TEXCOORD)
{
VSOut Output;
//float4 height = tex2Dlod( displacementSampler, float4(Tex.x , Tex.y , 0,0 ) );
Output.Pos = mul(Pos, WorldMat); // World-Matrix-Transformation
Output.Pos = mul(Output.Pos, CamMat); // Kameratransformation
Output.Col = Col; //Farbe unverändert lassen
Output.Tex = Tex; // Texturkoordinaten unverändert lassen
return Output; // -> Rasterizer Stage
}
Re: Heightmap aus BMP (DirectX 10)
Verfasst: 30.11.2010, 04:08
von Jonsc1
Hat keiner eine Antwort warum das nicht kompiliert?
Ich bin mittlerweile soweit das mir Google wieder diesen Thread hier ausspuckt...
Re: Heightmap aus BMP (DirectX 10)
Verfasst: 30.11.2010, 10:13
von Krishty
Jonsc1 hat geschrieben:Hat keiner eine Antwort warum das nicht kompiliert?
Weil du
tex2Dlod() statt
SampleLevel() benutzt?
Re: Heightmap aus BMP (DirectX 10)
Verfasst: 30.11.2010, 21:20
von Jonsc1
Ich sollte mehr auf die Leute hören :)
So funktionierts tatsächlich:
Code: Alles auswählen
float4x4 WorldMat;
float4x4 CamMat;
Texture2D Heightmap;
sampler displacementSampler //this sampler will be used to read (sample) the heightmap
{
AddressU = Clamp;
AddressV = Clamp;
};
// a struct for the vertex shader return value
struct VSOut
{
float4 Col : COLOR; // vertex color
float2 Tex : TEXCOORD; // texturkoordinaten
float4 Pos : SV_POSITION; // vertex screen coordinates
};
// the vertex shader
VSOut VS(float4 Pos : POSITION, float4 Col : COLOR, float2 Tex : TEXCOORD)
{
VSOut Output;
float height = Heightmap.SampleLevel ( displacementSampler, Tex, 0 ).g;
Output.Pos = mul(Pos, WorldMat); //World Transformation
Output.Pos = mul(Output.Pos, CamMat); //View + Projection -Transformation
Output.Pos.y = Output.Pos.y + height * 50;
Output.Col = Col; // set the vertex color to the input's color
Output.Tex = Tex;
return Output; //-> Rasterizer Stage
}
Danke an alle :)
Re: Heightmap aus BMP (DirectX 10)
Verfasst: 30.11.2010, 21:23
von Krishty
Schön, das zu hören. Wenn wir schonmal da beisind: Warum existieren die tex*()-Funktionen? Haben die sich jemals irgendwo irgendwie kompilieren lassen?
Re: Heightmap aus BMP (DirectX 10)
Verfasst: 30.11.2010, 21:28
von Jonsc1
Wenn ich das im FXComposer compilieren will (also mit der tex2Lod Funktion), bekomme ich ne Meldung von wegen dafür müsste Abwärtskompatibilität aktiviert werden... event. laufen die nur unter VS_3.0... auch wenn ich dann den Grund nicht verstehe.
Re: Heightmap aus BMP (DirectX 10)
Verfasst: 30.11.2010, 21:30
von Krishty
Hm. Ich bin mir sicher, auch mit SM 2.0 immer die Sample*()-Funktionen benutzt zu haben, damit riecht die Sache eher nach SM 1.x-Legacy :/ Wahrscheinlich, weil Methoden in HLSL noch relativ neu sind …
Re: Heightmap aus BMP (DirectX 10)
Verfasst: 08.12.2010, 00:23
von Jonsc1
So, ich habe wie empfohlen die ganzen Berechnungen im Vertexshader gemacht, und es hat sich gezeigt dass es wirklich sehr sinnvoll war, da ich so die Höhendaten zur Verfügung hatte um z.B. dynamisch zu Texturieren.
Das funktioniert also soweit.
Nun benötige ich allerdings die Höhendaten auch auf der CPU, und möchte sie mir in ein Array speichern.
Allerdings lese ich anscheinen nur Mist aus, die ausgelesenen Floats sind negativ (erwartet hätte ich Werte zwischen 0 und 1 -> rgb Farben), manchmal erhalte ich auch NAN als Meldung.
Sieht also irgendwie so aus als würde ich an der falschen Stelle im Speicher lesen, aber ich habe mich eigentlich recht genau an das Beispiel aus der MSDN gehalten:
http://msdn.microsoft.com/en-us/library ... 85%29.aspx
Es tut mir leid dass der Code nicht anständig formatiert ist, aber das scheint ein Problem mit dem Forum hier zu sein... eigentlich ist er eingerückt
Code: Alles auswählen
HRESULT hr;
D3DX10_IMAGE_LOAD_INFO loadinfo;
ID3D10Texture2D* heightmaptex;
D3D10_MAPPED_TEXTURE2D mapped;
loadinfo.Usage = D3D10_USAGE_STAGING;
loadinfo.CpuAccessFlags = D3D10_CPU_ACCESS_READ;
loadinfo.BindFlags = 0;
hr = D3DX10CreateTextureFromFile(m_pDevice, L"heightmap.jpg", &loadinfo, NULL, (ID3D10Resource**)&heightmaptex, NULL);
if(FAILED(hr))
{
std::string errdesc = ws2s(DXGetErrorDescription(hr));
throw ISEN_Exception(__FILE__, __LINE__, "D3DX10CreateTextureFromFile", errdesc);
}
hr = heightmaptex->Map(0, D3D10_MAP_READ,0, &mapped);
if(FAILED(hr))
{
std::string errdesc = ws2s(DXGetErrorDescription(hr));
throw ISEN_Exception(__FILE__, __LINE__, "heightmaptex->Map", errdesc);
}
D3D10_TEXTURE2D_DESC desc;
heightmaptex->GetDesc( &desc );
const UINT WIDTH = desc.Width;
const UINT HEIGHT = desc.Height;
FLOAT* pTexels = (FLOAT*)mapped.pData;
for( UINT row = 0; row < HEIGHT; row++ )
{
UINT rowStart = row * mapped.RowPitch/4;
for( UINT col = 0; col < WIDTH; col++ )
{
int test = 0;
test = pTexels[rowStart + col*4 + 0]; // Red
pTexels[rowStart + col*4 + 1]; // Green
pTexels[rowStart + col*4 + 2]; // Blue
pTexels[rowStart + col*4 + 3]; // Alpha
MessageBox(0, s2ws(floatToString(test)).c_str() ,L"-",1);
}
}
heightmaptex->Unmap(0);
Re: Heightmap aus BMP (DirectX 10)
Verfasst: 08.12.2010, 11:52
von Krishty
So weit ich sehe, gibst du beim Laden der ursprünglichen Textur kein Format an, darum erzeugt DXGI die Textur in dem Format, was am nächsten an dem der Bilddatei liegt, und das ist R8G8B8X8_UNORM.
Du musst die Höhendaten also als Array von Höhe × Breite × RGBx unsigned chars interpretieren …
… aber damit ist es natürlich nicht getan, denn wenn jetzt z.B. jemand die BMP von RGB auf Graustufen umstellt liest du dreifach über den Speicher hinaus.
Und das ist dann der Punkt, wo du deine Heightmap manuell aus welchem Bildformat auch immer laden solltest, sie in das Format konvertierst, das du dir dafür überlegt hast (wenn es nur 256 Höhenabstufungen gibt (mehr kriegst du ja in eine BMP eh nicht rein) ist R8_UNORM okay, falls du mit R32_FLOAT besser arbeiten und den vierfachen Speicherverbrauch ohne Mehrwert in Kauf nehmen kannst, nimm eben floats) und direkt per D3D11 eine Textur aus diesen Daten erzeugst. Dann hast du nämlich auch keinen GPU-Download mehr.
Oder, einfacher: du gibst der DXGI-Funktion feste Parameter vor, mit denen sie die Textur zu laden hat und gehst beim Mappen der Textur sicher, dass sie in diesem Format vorliegt.
Und den Code musst du mit code=cpp ankündigen, dann wird er auch formatiert. Wir haben mal versucht, das als Standardeinstellung zu setzen, sind aber gescheitert -.-
Re: Heightmap aus BMP (DirectX 10)
Verfasst: 09.12.2010, 15:57
von Jonsc1
Danke, genau da lag das Problem.
Endlich hab ich das mit den Formaten mal richtig verstanden :)