2017-12-22 6 views
0

Ich benutze derzeit LWJGL 3 und baue eine einfache Skybox. Ich möchte, dass die Skybox eine HDR-Datei, eine equirektangulare Karte, aufnimmt. Ich kann eine Skybox mit einem PNG mit PNGDecoder bekommen, aber ich bin mir nicht sicher, wie es mit einer HDR-Datei funktionieren würde. Soweit ich weiß, ermöglicht STB (wie in C++) das Hochladen der HDR-Datei in das Programm und LWJGL 3 STB-Unterstützung.mit HDR Karten in LWJGL 3

Wie würde ich eine loadTexture-Funktion erstellen, die STB und eine HDR-Datei unterstützt?

EDIT: Ich werde meine Fortschritte veröffentlichen, damit jeder sehen kann, woran ich gearbeitet habe.

  1. Meine Loader-Klasse hält alle meine Methoden Loadtexture und ich bin mit einem int-Methode, die die Textur-ID speichert, die derzeit sieht das Verfahren wie folgt aus:

    public int loadCubeMap(String textureFile) throws IOException { 
    
    int texID = glGenTextures(); 
    glBindTexture(GL_TEXTURE_2D, texID); 
    
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    
    ByteBuffer imageBuffer; 
    IntBuffer w = BufferUtils.createIntBuffer(1); 
    IntBuffer h = BufferUtils.createIntBuffer(1); 
    IntBuffer comp = BufferUtils.createIntBuffer(1); 
    ByteBuffer image; 
    
    imageBuffer = IOUtil.ioResourceToByteBuffer(textureFile, 8 * 1024); 
    
    if (!stbi_info_from_memory(imageBuffer, w, h, comp)) 
        throw new IOException("Failed to read image information: " + stbi_failure_reason()); 
    
    image = stbi_load_from_memory(imageBuffer, w, h, comp, 3); 
    
    if (image == null) 
        throw new IOException("Failed to load image: " + stbi_failure_reason()); 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, w.get(0), h.get(0), 0, GL_RGB, GL_UNSIGNED_BYTE, image); 
    
    stbi_image_free(image); 
    
    return texID; } 
    

Was ich bekam aus Dieses Demo lwjgl3-demos here mit einem Beispiel für eine Umgebungskarte mit einer HDR-Textur und die Verwendung der STBImage Java-Bindungen. Die Methode verwendet auch eine Klasse in meinem util-Paket namens IOUtil, die aus dem Beispiel stammt und im Beispiel funktioniert. (Ich habe auch die HDR-Datei aus den learnOpengl Tutorials ausprobiert, die mit dem Beispiel funktioniert, aber nicht mit meinem eigenen Code);

Ich habe einen Skybox Shader und einen Skybox Renderer, die alle gut funktionieren. Der Skybox-Renderer wird wie unten geschrieben:

public class SkyboxRenderer {

private static final float SIZE = 500f; 

private static final float[] VERTICES = {   
    -SIZE, SIZE, -SIZE, 
    -SIZE, -SIZE, -SIZE, 
    SIZE, -SIZE, -SIZE, 
    SIZE, -SIZE, -SIZE, 
    SIZE, SIZE, -SIZE, 
    -SIZE, SIZE, -SIZE, 

    -SIZE, -SIZE, SIZE, 
    -SIZE, -SIZE, -SIZE, 
    -SIZE, SIZE, -SIZE, 
    -SIZE, SIZE, -SIZE, 
    -SIZE, SIZE, SIZE, 
    -SIZE, -SIZE, SIZE, 

    SIZE, -SIZE, -SIZE, 
    SIZE, -SIZE, SIZE, 
    SIZE, SIZE, SIZE, 
    SIZE, SIZE, SIZE, 
    SIZE, SIZE, -SIZE, 
    SIZE, -SIZE, -SIZE, 

    -SIZE, -SIZE, SIZE, 
    -SIZE, SIZE, SIZE, 
    SIZE, SIZE, SIZE, 
    SIZE, SIZE, SIZE, 
    SIZE, -SIZE, SIZE, 
    -SIZE, -SIZE, SIZE, 

    -SIZE, SIZE, -SIZE, 
    SIZE, SIZE, -SIZE, 
    SIZE, SIZE, SIZE, 
    SIZE, SIZE, SIZE, 
    -SIZE, SIZE, SIZE, 
    -SIZE, SIZE, -SIZE, 

    -SIZE, -SIZE, -SIZE, 
    -SIZE, -SIZE, SIZE, 
    SIZE, -SIZE, -SIZE, 
    SIZE, -SIZE, -SIZE, 
    -SIZE, -SIZE, SIZE, 
    SIZE, -SIZE, SIZE 
}; 

private RawModel cube; 
private int skyboxTexture; 
private SkyboxShader shader; 

public SkyboxRenderer(Loader loader, Matrix4f projectionMatrix) throws IOException { 
    cube = loader.loadToVAO(VERTICES, 3); 
    skyboxTexture = loader.loadCubeMap("res/newport_loft.hdr"); 
    shader = new SkyboxShader(); 
    shader.start(); 
    shader.loadProjectionMatrix(projectionMatrix); 
    shader.connectTextureUnits(); 
    shader.stop(); 
    } 

public void render(Camera camera) { 
    shader.start(); 
    shader.loadViewMatrix(camera); 
    GL30.glBindVertexArray(cube.getVaoID()); 
    GL20.glEnableVertexAttribArray(0); 

    GL11.glBindTexture(GL13.GL_TEXTURE_CUBE_MAP, skyboxTexture); 
    GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, cube.getVertexCount()); 
    GL20.glDisableVertexAttribArray(0); 
    GL30.glBindVertexArray(0); 
    shader.stop(); 
    } 
} 

ich einen Vertex und Fragment-Shader verwenden, die von learnOpengl der PBR Tutorial kam.

Vertex-Shader:

#version 330 core 

layout (location = 0) in vec3 aPos; 

out vec3 WorldPos; 

uniform mat4 projection; 
uniform mat4 view; 

void main() { 
    WorldPos = aPos; 
    gl_Position = projection * view * vec4(WorldPos, 1.0); } 

Fragment-Shader:

#version 330 core 
out vec4 FragColor; 
in vec3 WorldPos; 

uniform sampler2D equirectangularMap; 

const vec2 invAtan = vec2(0.1591, 0.3183); 
vec2 SampleSphericalMap(vec3 v) 
{ 
    vec2 uv = vec2(atan(v.z, v.x), asin(v.y)); 
    uv *= invAtan; 
    uv += 0.5; 
    return uv; 
} 

void main() 
{  
    vec2 uv = SampleSphericalMap(normalize(WorldPos)); 
    vec3 color = texture(equirectangularMap, uv).rgb; 

    FragColor = vec4(color, 1.0); 
} 

Der Code Shader auch funktioniert, wie es der Fall ist, von der Hilfe von Thinmatrix des Tutorials.

public class SkyboxShader erweitert ShaderProgram {

private static final String VERTEX_FILE = "src/skybox/cubemap.vs"; 
private static final String FRAGMENT_FILE = "src/skybox/cubemap.fs"; 

private int location_projectionMatrix; 
private int location_viewMatrix; 

private int location_equirectangularMap; 

public SkyboxShader() { 
    super(VERTEX_FILE, FRAGMENT_FILE); 
} 

public void loadProjectionMatrix(Matrix4f matrix){ 
    super.loadMatrix(location_projectionMatrix, matrix); 
} 

public void loadViewMatrix(Camera camera){ 
    Matrix4f matrix = Maths.createViewMatrix(camera); 
    super.loadMatrix(location_viewMatrix, matrix); 
} 

@Override 
protected void getAllUniformLocations() { 
    location_projectionMatrix = super.getUniformLocation("projection"); 
    location_viewMatrix = super.getUniformLocation("view"); 
    location_equirectangularMap = super.getUniformLocation("equirectangularMap"); 
} 

@Override 
protected void bindAttributes() { 
    super.bindAttribute(0, "aPos"); 
} 

public void connectTextureUnits() { 
    super.loadInt(location_equirectangularMap, 0); 
} } 

ich die loadCubeMap Funktion in der Skybox Renderer zusammen mit dem Dateinamen, dann initialisieren die Skybox Renderer in der Master-Renderer Klasse initialisieren.

Wenn ich es ausführe, bekomme ich keine Fehler über die HDR-Textur und den Loader, also gehe ich davon aus, dass es akzeptiert wird. Das meiste funktioniert.

here

ich eine Box und eine Textur, aber die Textur auf die falsche Textur ist verbindlich. Es bindet die Albedo-Bodentextur, die ich in meinem Terrain verwende, was ich als Standardbedingung ansehe, wenn Dinge nicht korrekt binden, sondern nur raten.

Edit: Ich habe gerade festgestellt, dass die HDR-Karte für eine Kugel verwendet wird, und ich rendere einen Würfel. (lol)

So da, ich kann nicht scheinen, das Problem herauszufinden.Ich werde es noch einmal drehen und sehen, was ich verbessern kann. Jede Hilfe würde sehr geschätzt werden.

Edit:

Also habe ich versucht, es überarbeitet. Die Bildvariable wurde in einen Float Buffer geändert und akzeptiert nun ein Image mit stbi_loadf_from_memory. Immer noch ein, aber verwirrt, glaube nicht, HDR-Karten würden so verwirrend sein.

public int loadCubeMap(String textureFile) throws IOException { 

     int texID = glGenTextures(); 
     //glActiveTexture(GL11.GL_TEXTURE); 
     glBindTexture(GL_TEXTURE_2D, texID); 

     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 

     ByteBuffer imageBuffer; 
     IntBuffer w = BufferUtils.createIntBuffer(1); 
     IntBuffer h = BufferUtils.createIntBuffer(1); 
     IntBuffer comp = BufferUtils.createIntBuffer(1); 
     FloatBuffer image; 

     imageBuffer = IOUtil.ioResourceToByteBuffer(textureFile, 8 * 1024); 

     if (!stbi_info_from_memory(imageBuffer, w, h, comp)) 
      throw new IOException("Failed to read image information: " + stbi_failure_reason()); 

     image = stbi_loadf_from_memory(imageBuffer, w, h, comp, 3); 



     if (image == null) 
      throw new IOException("Failed to load image: " + stbi_failure_reason()); 
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16, w.get(0), h.get(0), 0, GL_RGB16, GL_FLOAT, image); 

     stbi_image_free(image); 

     return texID; 

Antwort

0

Statt stbi_load_from_memory() sollten Sie stbi_loadf_from_memory() verwenden, die die Funktion, die HDR-Dateien liest. STB enthält auch Funktionen wie stbi_is_hdr_from_memory(), mit denen Sie sicherstellen können, dass der Puffer ein HDR-Bild enthält.

Beachten Sie, dass stbi_load_from_memory() einen FloatBuffer zurückgibt, der die Textur enthält.

  • ersetzen GL_UNSIGNED_BYTE mit GL_FLOAT, da der Puffer nun eine float für jede Komponente enthält, und
  • einen geeigneten Gleitkomma- interne Format auszuwählen, wie:

    Außerdem sollten Sie den Anruf glTexImage2D() modifizieren als GL_RGB16F ersetzen GL_RGB8.

+0

Danke für die Antwort! Bis jetzt ändere ich das Bytebuffer Bild in einen FloatBuffer. Und änderte das Bild = stbi_load_from_memory zu stbi_loadf_from_memory. Die Fehlerprüfung, die ich noch habe, bleibt gleich, und IntBuffers für die Variablen w, h und comp sind gleich. Der GL_RGB16F kann nicht gefunden werden, und ich bin sicher, dass ich aktuelle Versionen der Bibliotheken habe. – winnieTheWind

+0

Außerdem habe ich ein Beispiel, das scheint, das HDR-Bild fein zu laden, aber benötigt nicht das stbi_loadf oder das passende Fließkomma um zu arbeiten. Ich gehe davon aus, weil Sie es nur brauchen, wenn Sie das HDR-Bild in vollem Umfang nutzen wollen. – winnieTheWind

+0

(1) GL_RGB16F sollte verfügbar sein, siehe http://legacy.lwjgl.org/javadoc/org/lwjgl/opengl/GL30.html#GL_RGB16F, (2) HDR, wie im High Dynamic Range, erfordert in der Regel Fließkommawerte um einen viel größeren Wertebereich zu speichern. – sterin