[英]using HDR maps in LWJGL 3
我目前正在使用LWJGL 3並構建一個簡單的skybox。 我希望Skybox接收HDR文件,即等角圖。 我可以使用PNGDecoder讓Skybox與PNG一起運行,但不確定如何與HDR文件配合使用。 據我了解,STB(在c ++中)允許將HDR文件上傳到程序中,並且LWJGL 3具有STB支持。
我將如何制作支持STB和HDR文件的loadTexture函數?
編輯:我將要發布的進度,以便任何人都可以看到我正在從事的工作。
我的加載程序類包含我所有的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.