使用帧缓冲区写入 3D 纹理并另存为图像
Writing to a 3D Texture Using Framebuffers and Saving as Image
我正在尝试为某些体积效果生成 3D worley 噪声纹理。我只是生成一组随机点,对于每个片段,我会找到最近的点并获得片段和像素之间的距离。然后将距离用作图像的最终颜色。结果在 2D 中看起来像这样:
这在我生成 2D 纹理时效果很好。在尝试生成 3D 纹理时,我开始 运行 遇到一些问题。
现在我将 3D 纹理的每个切片附加为颜色附件并使用着色器写入它。我的代码如下:
产生噪声的函数(注:这段代码假设宽高深都相等):
void WorleyGenerator::GenerateWorley3D(int numPoints, Texture3D* texture, PrimitiveShape* quad, unsigned int nativeWidth, unsigned int nativeHeight)
{
int resolution = texture->GetWidth();
glViewport(0, 0, resolution, resolution);
glDisable(GL_CULL_FACE);
frameBuffer->Bind();
shader3D->Bind();
shader3D->SetFloat("uResolution", resolution);
shader3D->SetInt("uNumWorleyPoints", numPoints); // Tell shader how many points we have
// Generate random points and pass them ot shader
for (int i = 0; i < numPoints; i++)
{
shader3D->SetFloat3("uPointData[" + std::to_string(i) + "]", glm::vec3(Utils::RandInt(0, resolution), Utils::RandInt(0, resolution), Utils::RandInt(0, resolution)));
}
// Render to each "slice" of the texture
for (int z = 0; z < resolution; z++)
{
shader3D->SetInt("uCurrentSlice", z);
glFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, texture->GetID(), 0, z);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
quad->Draw();
}
frameBuffer->Unbind();
glViewport(0, 0, nativeWidth, nativeHeight);
}
我的片段着色器:
#version 420
in vec2 mTextureCoordinates;
out vec4 oColor;
uniform int uCurrentSlice;
uniform float uResolution;
uniform int uNumWorleyPoints;
uniform vec3 uPointData[256];
void main()
{
vec3 fragPos = vec3(gl_FragCoord.xy, uCurrentSlice) / uResolution; // Convert frag pos to range 0 - 1
// Find closest point's distance
float closestDist = 100000.0f;
// Get closest point for red channel
for (int i = 0; i < uNumWorleyPoints; i++)
{
vec3 p = uPointData[i] / uResolution; // Convert point to range 0 - 1
float dist = distance(fragPos, p);
if (dist < closestDist)
{
closestDist = dist;
}
}
oColor = vec4(closestDist, closestDist, closestDist, 1.0f);
}
现在要测试我的代码,我会将 3D 纹理的每个切片保存到 BMP 文件中:
void Utils::SaveTexture3DAsBMP(const std::string& savePath, Texture3D* texture)
{
unsigned int size = texture->GetWidth() * texture->GetHeight() * 4;
float* data = new float[size];
for (int z = 0; z < texture->GetDepth(); z++)
{
glGetTextureSubImage(texture->GetID(), 0, 0, 0, z, texture->GetWidth(), texture->GetHeight(), z, GL_RGBA16F, GL_FLOAT, size, data);
stbi_write_bmp((savePath + std::to_string(z) + ".bmp").c_str(), texture->GetWidth(), texture->GetHeight(), 4, data);
}
delete[] data;
}
保存图像的结果如下所示:
此外,每个切片都完全相同,这是不应该发生的。
我怀疑我没有正确地写入切片,或者我保存图像的代码有误。
如有任何帮助,我们将不胜感激!
我的问题不在于纹理,而在于我如何保存图像。我改变了我的纹理保存功能:
void Utils::SaveTexture3DAsBMP(const std::string& savePath, Texture3D* texture)
{
unsigned int size = texture->GetWidth() * texture->GetHeight() * 4;
float* data = new float[size];
for (int z = 0; z < texture->GetDepth(); z++)
{
glGetTextureSubImage(texture->GetID(), 0, 0, 0, z, texture->GetWidth(), texture->GetHeight(), z, GL_RGBA16F, GL_FLOAT, size, data);
stbi_write_bmp((savePath + std::to_string(z) + ".bmp").c_str(), texture->GetWidth(), texture->GetHeight(), 4, data);
}
delete[] data;
}
为此:
void Utils::SaveTexture3DAsBMP(const std::string& savePath, Texture3D* texture)
{
unsigned int size = texture->GetWidth() * texture->GetHeight() * 4;
uint8_t* data = new uint8_t[size];
for (int z = 0; z < texture->GetDepth(); z++)
{
glGetTextureSubImage(texture->GetID(), 0, 0, 0, z, texture->GetWidth(), texture->GetHeight(), 1, GL_RGBA, GL_UNSIGNED_BYTE, size, data);
stbi_write_bmp((savePath + std::to_string(z) + ".bmp").c_str(), texture->GetWidth(), texture->GetHeight(), 4, data);
}
delete[] data;
}
我正在尝试为某些体积效果生成 3D worley 噪声纹理。我只是生成一组随机点,对于每个片段,我会找到最近的点并获得片段和像素之间的距离。然后将距离用作图像的最终颜色。结果在 2D 中看起来像这样:
这在我生成 2D 纹理时效果很好。在尝试生成 3D 纹理时,我开始 运行 遇到一些问题。
现在我将 3D 纹理的每个切片附加为颜色附件并使用着色器写入它。我的代码如下:
产生噪声的函数(注:这段代码假设宽高深都相等):
void WorleyGenerator::GenerateWorley3D(int numPoints, Texture3D* texture, PrimitiveShape* quad, unsigned int nativeWidth, unsigned int nativeHeight)
{
int resolution = texture->GetWidth();
glViewport(0, 0, resolution, resolution);
glDisable(GL_CULL_FACE);
frameBuffer->Bind();
shader3D->Bind();
shader3D->SetFloat("uResolution", resolution);
shader3D->SetInt("uNumWorleyPoints", numPoints); // Tell shader how many points we have
// Generate random points and pass them ot shader
for (int i = 0; i < numPoints; i++)
{
shader3D->SetFloat3("uPointData[" + std::to_string(i) + "]", glm::vec3(Utils::RandInt(0, resolution), Utils::RandInt(0, resolution), Utils::RandInt(0, resolution)));
}
// Render to each "slice" of the texture
for (int z = 0; z < resolution; z++)
{
shader3D->SetInt("uCurrentSlice", z);
glFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, texture->GetID(), 0, z);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
quad->Draw();
}
frameBuffer->Unbind();
glViewport(0, 0, nativeWidth, nativeHeight);
}
我的片段着色器:
#version 420
in vec2 mTextureCoordinates;
out vec4 oColor;
uniform int uCurrentSlice;
uniform float uResolution;
uniform int uNumWorleyPoints;
uniform vec3 uPointData[256];
void main()
{
vec3 fragPos = vec3(gl_FragCoord.xy, uCurrentSlice) / uResolution; // Convert frag pos to range 0 - 1
// Find closest point's distance
float closestDist = 100000.0f;
// Get closest point for red channel
for (int i = 0; i < uNumWorleyPoints; i++)
{
vec3 p = uPointData[i] / uResolution; // Convert point to range 0 - 1
float dist = distance(fragPos, p);
if (dist < closestDist)
{
closestDist = dist;
}
}
oColor = vec4(closestDist, closestDist, closestDist, 1.0f);
}
现在要测试我的代码,我会将 3D 纹理的每个切片保存到 BMP 文件中:
void Utils::SaveTexture3DAsBMP(const std::string& savePath, Texture3D* texture)
{
unsigned int size = texture->GetWidth() * texture->GetHeight() * 4;
float* data = new float[size];
for (int z = 0; z < texture->GetDepth(); z++)
{
glGetTextureSubImage(texture->GetID(), 0, 0, 0, z, texture->GetWidth(), texture->GetHeight(), z, GL_RGBA16F, GL_FLOAT, size, data);
stbi_write_bmp((savePath + std::to_string(z) + ".bmp").c_str(), texture->GetWidth(), texture->GetHeight(), 4, data);
}
delete[] data;
}
保存图像的结果如下所示:
此外,每个切片都完全相同,这是不应该发生的。
我怀疑我没有正确地写入切片,或者我保存图像的代码有误。
如有任何帮助,我们将不胜感激!
我的问题不在于纹理,而在于我如何保存图像。我改变了我的纹理保存功能:
void Utils::SaveTexture3DAsBMP(const std::string& savePath, Texture3D* texture)
{
unsigned int size = texture->GetWidth() * texture->GetHeight() * 4;
float* data = new float[size];
for (int z = 0; z < texture->GetDepth(); z++)
{
glGetTextureSubImage(texture->GetID(), 0, 0, 0, z, texture->GetWidth(), texture->GetHeight(), z, GL_RGBA16F, GL_FLOAT, size, data);
stbi_write_bmp((savePath + std::to_string(z) + ".bmp").c_str(), texture->GetWidth(), texture->GetHeight(), 4, data);
}
delete[] data;
}
为此:
void Utils::SaveTexture3DAsBMP(const std::string& savePath, Texture3D* texture)
{
unsigned int size = texture->GetWidth() * texture->GetHeight() * 4;
uint8_t* data = new uint8_t[size];
for (int z = 0; z < texture->GetDepth(); z++)
{
glGetTextureSubImage(texture->GetID(), 0, 0, 0, z, texture->GetWidth(), texture->GetHeight(), 1, GL_RGBA, GL_UNSIGNED_BYTE, size, data);
stbi_write_bmp((savePath + std::to_string(z) + ".bmp").c_str(), texture->GetWidth(), texture->GetHeight(), 4, data);
}
delete[] data;
}