Cubemapping bei DirectX ist Vertikal gespiegelt



  • Hallo,

    ich versuche gerade eine Metallkugel bei OpenGL und DirectX anzuzeigen. Ich erzeuge dazu dynamisch eine Cubemap um die Spiegelung darzustellen. Dabei habe ich aber das Problem, dass die 6 einzelnen Cubemap-Texturen bei DirectX vertikal gespiegelt angezeigt werden.

    So sieht die Gesamtszene aus:
    [https://ibb.co/Qp8vWmB](Bild gesamt)

    Hier habe ich mehr an die Kugel herran gezoomt:
    [https://ibb.co/dfJK83H](Bild Metallkugel)

    Diese Cubemap nutze ich
    Dynamic Cubemap

    Bei OpenGL zeige ich die Cubemap im Fragmentshader wie folgt an:

    uniform samplerCube Cubemap;
    vec3 ReflectDir = normalize(reflect(posWorld - CameraPosition, normalVektor));  
    out_frag_color = texture(Cubemap, ReflectDir);
    

    Bei DirectX gebe ich im PixelShader die Farbe von der Metallkugel wie folgt aus:

    TextureCube CubeMapTexture;  //Cubemap-Texture
    SamplerState samAnisotropic
    {
    	Filter = ANISOTROPIC;
    	MaxAnisotropy = 4;
    
    	AddressU = WRAP;
    	AddressV = WRAP;
    };
    
    float3 reflectionVector = normalize(reflect(input.WorldPosition - CameraPosition, normalVektor));
    return CubeMapTexture.Sample(samAnisotropic, reflectionVector); 
    

    Der Fehler, warum bei DirectX das Cubemapping geflippt ist liegt entweder an der
    TextureCube.Sample-Funktion (Siehe Microsoft-Docs oder daran, bei DirectX der UV-Texturnullpunkt links oben liegt und bei OpenGL liegt der UV-Texturnullpunkt links unten.

    Um besser zu verstehen was beim Cubemapping intern passiert, habe ich auch in mein selbstgeschriebenen CPU-Rasterizer das Cubemapping nachgebaut. Dort funktioniert der Zugriff im Pixelshader wie folgt:

    Vektor reflectionVector = Vektor.GetReflectedDirection(v.Position - prop.CameraPosition, normalVektor);
    return TextureReader.GetCubemapSample(prop.textureDeck2, reflectionVector);
    

    Ich nutze für das Cubemapping die Funktion convert_xyz_to_cube_uv von hier
    https://en.wikipedia.org/wiki/Cube_mapping

    Das bedeutet OpenGL nutzt den gleichen Cubemapping-Algorithmus wie bei Wikipedia.

    Wenn ich bei DirectX das gleiche Ergebnis will, müsste ich den Quelltext von Wikipedia wie folgt noch ändern:

    // Convert range from -1 to 1 to 0 to 1
      *u = 0.5f * (uc / maxAxis + 1.0f);
      *v = 0.5f * (vc / maxAxis + 1.0f);
    
    *v = 1 - *v; //Hier erfolgt der vertikale Flip
    

    Ich benutzt mein Raytracer um als Referenz sehen zu können, wie die Spiegelung richtig aussehen muss. Von daher bin ich mir sicher, dass OpenGL und mein CPU-Rasterizer sich richtig verhält.

    Die Frage ist nun also wie schaffe ich es den HLSL-PixelShader-Cubemapping-Aufruf zu flippen? ALso das hier:

    CubeMapTexture.Sample(samAnisotropic, reflectionVector)
    

    Wenn ich eine 2D-Textur hätte, würde ich ja einfach die v(=y)-Koordinate beim Zugiff flippen:

    texture2D(MyTexture, vec2(texCoord.x, 1 - texCoord.y))
    

    Hier beim Zugriff auf die Cubemap gebe ich ja ein Richtungsvektor/3D-Vektor ein. DirectX rechnet intern diesen 3D-Vektor mittels Cubemapping in eine Cubemap-Side-Index (0 bis 5) und eine UV-Koordinate um. Ich komme also leider nicht intern so einfach ran außer es gibt eine Möglichkeit im Pixelshader ein Cubemap-Pixel per Cubemap-Side-Index und UV-Koordinate auszulesen.

    Für das Erstellen der Cubemap unter DirectX gehe ich wie in diesen Tutorial vor:
    DirectX-Cubemapping
    Soweit ich das verstehe, liegt die Cubemap als ein Array mit 6 2D-Texturen im Grafikspeicher. Es müsste also theoretisch gehen dort drauf zuzugreifen aber ich weiß nicht wie.

    Weiß jemand von euch, was ich tun kan, um die vertikale Spiegelung beim Cubemapping bei DirectX wegzubekommen?



  • @XMAMan sagte in Cubemapping bei DirectX ist Vertikal gespiegelt:

    Dabei habe ich aber das Problem, dass die 6 einzelnen Cubemap-Texturen bei DirectX vertikal gespiegelt angezeigt werden.

    Das OpenGL Texturen vertikal gespiegelt ausgibt, kenne ich wenn ich eine Textur in ein Bilddatei (png) speichere. Die Details dazu kenne ich nicht.

    Code um Pixel vertikal zu spiegeln.

    Der Loop geht von der ersten Zeile bis zur letzten Zeile und kopiert zeilenweise in die letzte Zeile bis zur ersten Zeile.

    void RenderTexture::VerticalFlip()
    {
    	std::vector<unsigned char> buffer(image);
    
    	for (auto index = 0; index < height; ++index)
    	{
    		auto rowsize = width * pixelsize;
    		auto subindex0 = index * rowsize;
    		auto subindex1 = subindex0 + rowsize;
    
    		std::copy(buffer.cbegin() + subindex0, buffer.cbegin() + subindex1, image.end() - subindex1);
    	}
    }
    


  • Wenn man wärend der Ausgabe einer Textur in eine Datei das Bild flippen muss, dann ist das ja auch nicht schlimmt. Das mach ich hier jetzt auch. Meine jetzige Lösung sieht nun so aus, dass ich die eingebaute Cubmapping-Funktion von DirectX nicht nutze sondern ich habe das Cubemapping von Wikipedia nach HLSL übersetzt.

    
    
    float3 Cubemapping(float3 direction)
    {
    	float x = direction.x;
    	float y = direction.y;
    	float z = direction.z;
    
    	float absX = abs(x);
    	float absY = abs(y);
    	float absZ = abs(z);
    	
    	bool isXPositive = x > 0 ? true : false;
    	bool isYPositive = y > 0 ? true : false;
    	bool isZPositive = z > 0 ? true : false;
    	
    	float maxAxis=-1, uc=-1, vc=-1;
    	float index = -1;
    
    	// POSITIVE X
    	if (isXPositive && absX >= absY && absX >= absZ) {
    	  // u (0 to 1) goes from +z to -z
    	  // v (0 to 1) goes from -y to +y
    	  maxAxis = absX;
    	  uc = -z;
    	  vc = y;
    	  index = 0;
    	}
    	// NEGATIVE X
    	if (!isXPositive && absX >= absY && absX >= absZ) {
    	  // u (0 to 1) goes from -z to +z
    	  // v (0 to 1) goes from -y to +y
    	  maxAxis = absX;
    	  uc = z;
    	  vc = y;
    	  index = 1;
    	}
    	// POSITIVE Y
    	if (isYPositive && absY >= absX && absY >= absZ) {
    	  // u (0 to 1) goes from -x to +x
    	  // v (0 to 1) goes from +z to -z
    	  maxAxis = absY;
    	  uc = x;
    	  vc = -z;
    	  index = 2;
    	}
    	// NEGATIVE Y
    	if (!isYPositive && absY >= absX && absY >= absZ) {
    	  // u (0 to 1) goes from -x to +x
    	  // v (0 to 1) goes from -z to +z
    	  maxAxis = absY;
    	  uc = x;
    	  vc = z;
    	  index = 3;
    	}
    	// POSITIVE Z
    	if (isZPositive && absZ >= absX && absZ >= absY) {
    	  // u (0 to 1) goes from -x to +x
    	  // v (0 to 1) goes from -y to +y
    	  maxAxis = absZ;
    	  uc = x;
    	  vc = y;
    	  index = 4;
    	}
    	// NEGATIVE Z
    	if (!isZPositive && absZ >= absX && absZ >= absY) {
    	  // u (0 to 1) goes from +x to -x
    	  // v (0 to 1) goes from -y to +y
    	  maxAxis = absZ;
    	  uc = -x;
    	  vc = y;
    	  index = 5;
    	}
    
    	// Convert range from -1 to 1 to 0 to 1
    	float u = 0.5f * (uc / maxAxis + 1.0f);
    	float v = 0.5f * (vc / maxAxis + 1.0f);
    
    	return float3(u,v, index);
    ...
    
    TextureCube CubeMapTexture;	// Cubemap für Reflektionen (Hier wird das Bild Y-Mäßig gespiegelt)
    Texture2DArray CubeMapArrayTexture; // Der Einsatz eines Texture2DArray erlaubt mir mein eigenes Cubemapping zu machen
    
    //reflectionColor  = CubeMapTexture.Sample(samAnisotropic, reflectionVector); 
    reflectionColor  = CubeMapArrayTexture.Sample(TextureFilterScharf, Cubemapping(reflectionVector));
    }
    

    Mit dieser Lösung musste ich auch nichts mehr flippen oder sonste wie anpassen. Mich bestärkt das nur darin, dass die Funktion TextureCube .Sample bei DirectX ein Fehler enthält oder ich aber noch irgendwo beim Anlegen der Textur ein Schalter vergessen habe, welche ein wichtigen Einfluß hat.



  • Sieht auf den ersten Blick erstmal gut aus. Denke deshalb auch, dass es an dem TextureCube liegt, kann jetzt aber leider auch nichts genaueres sehen. Hoffe du findest den fehler bald!


Log in to reply