c++ - 使球体上的球具有暗带

标签 c++ opengl texture-mapping

我正在使用此代码生成球体顶点和纹理,但是正如您在图像中看到的那样,当我旋转它时,我会看到一个暗带。

 for (int i = 0; i <= stacks; ++i)
    {
        float s = (float)i / (float) stacks;
        float theta = s * 2 * glm::pi<float>();

        for (int j = 0; j <= slices; ++j)
        {
            float sl = (float)j / (float) slices;
            float phi = sl * (glm::pi<float>());

            const float x = cos(theta) * sin(phi);
            const float y = sin(theta) * sin(phi);
            const float z = cos(phi);

            sphere_vertices.push_back(radius * glm::vec3(x, y, z));
            sphere_texcoords.push_back((glm::vec2((x + 1.0) / 2.0, (y + 1.0) / 2.0)));
        }
    }

    // get the indices

    for (int i = 0; i < stacks * slices + slices; ++i)
    {
        sphere_indices.push_back(i);
        sphere_indices.push_back(i + slices + 1);
        sphere_indices.push_back(i + slices);

        sphere_indices.push_back(i + slices + 1);
        sphere_indices.push_back(i);
        sphere_indices.push_back(i + 1);
    }

无论我使用什么纹理坐标,我都无法找到一种使之正确的方法。

ball

嗯..如果我使用其他图像,则映射是不同的(而且更糟!)

ball2

顶点着色器:
#version 330 core

layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aTexCoord;

out vec4 vertexColor;
out vec2 TexCoord;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    gl_Position = projection * view * model * vec4(aPos.x, aPos.y, aPos.z, 1.0);
    vertexColor = vec4(0.5, 0.2, 0.5, 1.0);
    TexCoord = vec2(aTexCoord.x, aTexCoord.y);
}

片段着色器:
#version 330 core
out vec4 FragColor;

in vec4 vertexColor;
in vec2 TexCoord;

uniform sampler2D sphere_texture;

void main()
{

    FragColor = texture(sphere_texture, TexCoord);
}

我没有使用任何照明条件。

如果我在片段着色器中使用FragColor = vec4(TexCoord.x, TexCoord.y, 0.0f, 1.0f);(出于调试目的),我将收到一个不错的球体。

ball3

我正在使用它作为纹理:

texture

最佳答案

您链接的网球图像揭示了问题所在。很高兴您最终提供了它。

enter image description here

您的图像是具有透明度的四通道PNG(Alpha通道)。球的黄色部分周围都有透明像素,它们的(R,G,B,A)=(0,0,0,0),所以如果您忽略A通道,则(R, G,B),将为(0,0,0)=黑色。

这只是红色,绿色和蓝色(RGB)通道:

enter image description here

这只是Alpha(A) channel 。

enter image description here

要注意的重要一点是,球的圆没有填充正方形。从球的范围到纹理的边缘,有53个黑色像素的显着空白。我们可以据此计算出球的半径。宽度的一半为1000像素,其中不使用53像素。球的半径是1000-53,即947个像素。从纹理的中心到边缘的距离大约为94.7%。剩余的5.3%距离为黑色。

Side note: I also notice that your ball doesn't quite reach 100% opacity. The yellow part of the ball has an alpha channel value of 254 (of 255) Meaning 99.6% opaque. The white lines and the shiny hot spot do actually reach 100% opacity, giving it sort of a Death Star look. ;)



要解决您的问题,有一种直观的方法(可能不起作用),然后需要做两件事才能起作用。您可以执行以下操作:

直观的解决方案:

这不会完全让您100%在那里。

1)调整球的大小以填充纹理。使用图像编辑软件放大球以填充纹理或修剪黑色像素。这样做只会更有效地利用像素,但是它将确保在边界处采样有用的像素。您可能需要将图像扩展为略大于100%。我将在下面解释原因。
2)重新映射纹理坐标,使其仅延伸到球半径的94.7%。 (类似于方法1,但不需要图像编辑)。这仅使用实际与您提供的图像相对应的坐标。您的xy坐标需要围绕图像的中心缩放,并减少到约94.7%。
x2 = 0.5 + (x - 0.5) * 0.947;
y2 = 0.5 + (y - 0.5) * 0.947;

建议的解决方案:

这将确保不再有黑色。

3)用较不令人讨厌的颜色填充您的球纹理的“黑色”部分-可能是网球周围的颜色。这样可以确保在球的精确边缘上采样的所有纹理像素都不会与黑色线性组合,以产生难看的深色但并不十分的黑色带,这几乎是您现在遇到的问题。您可以通过两种方式执行此操作。 A)图像编辑软件。去除图像的透明度并将其 mask 为深黄色。 B)使用着色器检测图像外部的像素,并将其替换为边框颜色(这很聪明,但是可能比它值得的麻烦更多。)

不同的纹理坐标

您可以做的最后一件事是完全避免此退化的纹理映射坐标问题。在赤道上,您不确定要采样哪些像素。球的黑色(透明)像素或彩色像素。正方形像素的离散性质正在与纹理贴图的极性性质作斗争。您将永远找不到在边缘附近产生连续,无缝 map 所需的确切颜色。相反,您可以使用其他坐标系。希望您对球的外观不感兴趣,因为让我向您介绍等角投影。您可以天真地使用它来将地球的地球映射到您可能熟悉的典型的矩形世界 map 上,北极和南极都会产生所有畸变,但赤道区域看起来还不错。

这是映射到等角坐标的图像:

enter image description here

请注意,底部的黑条...我们在做某事!该黑条实际上就是使用当前纹理贴图坐标系出现在球的赤道周围的东西。但是使用此坐标系,您可以轻松地看到,如果我们仅重新映射球以填充正方形,那么我们将完全消除所有透明像素。

在此坐标系中工作可能很不方便,但是您可以在Photoshop中使用“滤镜”>“扭曲”>“极坐标” ...>“极坐标到矩形”来变换图像。

Sigismondo's answer已经建议如何调整纹理映射坐标。

最后,这是一个纹理,它既被放大以填充纹理空间,又被重新映射为等矩形坐标。没有黑条,失真最小。但是您必须使用Sigismondo的纹理贴图坐标。同样,这可能不适合您,特别是如果您对纹理直接投影的想法很感兴趣(即:如果您不想操纵网球图像并且想要使用该投影。)但是如果您愿意重新映射数据,可以放心所有黑色像素都消失了!

enter image description here

祝好运!随时要求澄清。

关于c++ - 使球体上的球具有暗带,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57852295/

相关文章:

c++ - 在 C++ 中记录动态数据

c++ - 使用 boost 创建相对路径

C++ - 为此寻找合适的设计

c++ - 递归重载 "->"(成员访问)

c++ - opengl纹理贴图

c++ - Qt 4.6 和 OpenGL : how to capture keyboard presses with three different widgets at once?

java - 使用混合创建多个被黑色包围的透明区域

c - OpenGL翻译

c++ - OpenGL 绑定(bind)纹理到顶点缓冲对象(使用 CG 着色器)

c++ - Raytracer 纹理贴图留下伪影