簡體   English   中英

在LWJGL 3中使用HDR映射

[英]using HDR maps in LWJGL 3

我目前正在使用LWJGL 3並構建一個簡單的skybox。 我希望Skybox接收HDR文件,即等角圖。 我可以使用PNGDecoder讓Skybox與PNG一起運行,但不確定如何與HDR文件配合使用。 據我了解,STB(在c ++中)允許將HDR文件上傳到程序中,並且LWJGL 3具有STB支持。

我將如何制作支持STB和HDR文件的loadTexture函數?

編輯:我將要發布的進度,以便任何人都可以看到我正在從事的工作。

  1. 我的加載程序類包含我所有的loadTexture方法,並且我使用的是存儲紋理ID的int方法,當前該方法如下所示:

     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; } 

這是我從這個演示lwjgl3,演示了在這里使用了HDR紋理,並使用STBImage Java綁定的環境地圖的一個例子。 該方法還在我的utils包中使用了一個名為IOUtil的類,該類來自示例,可在示例中使用。 (我還嘗試了LearnOpengl教程中的HDR文件,該文件在示例中工作正常,但不適用於我自己的代碼);

我有一個Skybox着色器和一個Skybox渲染器,它們似乎都可以正常工作。 天空盒渲染器的編寫方式如下:

公共類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();
    }
}

我正在使用來自learningOpengl的PBR教程的頂點和片段着色器。

頂點着色器:

#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); }

片段着色器:

#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);
}

在Thinmatrix的教程的幫助下,着色器代碼可以正常工作。

公共類SkyboxShader擴展了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);
} }

我在天空盒渲染器中初始化loadCubeMap函數以及文件名,然后在主渲染器類中初始化天空盒渲染器。

在運行它時,我對HDR紋理和加載程序沒有任何錯誤,因此我假定它已接受它。 大部分有效。

這里

我得到一個盒子和一個紋理,但是紋理綁定到錯誤的紋理。 它綁定了我在地形中使用的反照率地面紋理,我猜這是事物未正確綁定(只是猜測)時的默認條件。

編輯:我剛剛意識到HDR貼圖用於一個球體,並且正在渲染一個立方體。 (大聲笑)

所以在那兒,我似乎無法解決問題。 我會再旋轉一下,看看我可以改進什么。 任何幫助將非常感激。

編輯:

因此,我嘗試對其進行重做。 image變量已更改為Float Buffer,現在接受帶有stbi_loadf_from_memory的圖像。 仍然是一個但很困惑的人,並不認為HDR映射會如此混亂。

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;

您應該使用stbi_loadf_from_memory()而不是stbi_load_from_memory()來讀取HDR文件。 STB還包含諸如stbi_is_hdr_from_memory()函數,可讓您確保緩沖區包含HDR圖像。

請注意, stbi_load_from_memory()返回包含紋理的FloatBuffer

另外,您應該修改對glTexImage2D()的調用:

  • GL_UNSIGNED_BYTE替換為GL_FLOAT ,因為緩沖區現在包含每個組件的float ,並且
  • 選擇一個適當的浮點內部格式,例如GL_RGB16F來替換GL_RGB8

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM