生成一个立方体贴图(Cube Map)

cs 复制代码
private bool GenerateNormalisationCubeMap()
        {
            var gl = openGLControl1.OpenGL;

            //  First we create space to hold the data for a single face.
            //  Each face is 32x32, and we need to store the R, G and B components of the color at each point.
            byte[] data = new byte[32 * 32 * 3];

            //  Some useful variables.
            int size = 32;
            float offset = 0.5f;
            float halfSize = 16.0f;
            Vertex tempVector = new Vertex();
            uint byteCounter = 0;

            //  Positive x.
            for (int j = 0; j < size; j++)
            {
                for (int i = 0; i < size; i++)
                {
                    tempVector.X = (halfSize);
                    tempVector.Y = (-(j + offset - halfSize));
                    tempVector.Z = (-(i + offset - halfSize));
                    tempVector.UnitLength();
                    tempVector = tempVector.GetPackedTo01();
                    data[byteCounter++] = (byte)(tempVector.X * 255f);
                    data[byteCounter++] = (byte)(tempVector.Y * 255f);
                    data[byteCounter++] = (byte)(tempVector.Z * 255f);
                }
            }

            //  Set the texture image.
            gl.TexImage2D(OpenGL.GL_TEXTURE_CUBE_MAP_POSITIVE_X,
                0, OpenGL.GL_RGBA8, 32, 32, 0, OpenGL.GL_RGB, OpenGL.GL_UNSIGNED_BYTE, data);

            //negative x
            byteCounter = 0;

            for (int j = 0; j < size; j++)
            {
                for (int i = 0; i < size; i++)
                {
                    tempVector.X = (-halfSize);
                    tempVector.Y = (-(j + offset - halfSize));
                    tempVector.Z = ((i + offset - halfSize));

                    tempVector.UnitLength();
                    tempVector = tempVector.GetPackedTo01();

                    data[byteCounter++] = (byte)(tempVector.X * 255f);
                    data[byteCounter++] = (byte)(tempVector.Y * 255f);
                    data[byteCounter++] = (byte)(tempVector.Z * 255f);
                }
            }
            gl.TexImage2D(OpenGL.GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
                            0, OpenGL.GL_RGBA8, 32, 32, 0, OpenGL.GL_RGB, OpenGL.GL_UNSIGNED_BYTE, data);

            //positive y
            byteCounter = 0;

            for (int j = 0; j < size; j++)
            {
                for (int i = 0; i < size; i++)
                {
                    tempVector.X = (i + offset - halfSize);
                    tempVector.Y = (halfSize);
                    tempVector.Z = ((j + offset - halfSize));

                    tempVector.UnitLength();
                    tempVector = tempVector.GetPackedTo01();

                    data[byteCounter++] = (byte)(tempVector.X * 255f);
                    data[byteCounter++] = (byte)(tempVector.Y * 255f);
                    data[byteCounter++] = (byte)(tempVector.Z * 255f);
                }
            }
            gl.TexImage2D(OpenGL.GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
                            0, OpenGL.GL_RGBA8, 32, 32, 0, OpenGL.GL_RGB, OpenGL.GL_UNSIGNED_BYTE, data);

            //negative y
            byteCounter = 0;

            for (int j = 0; j < size; j++)
            {
                for (int i = 0; i < size; i++)
                {
                    tempVector.X = (i + offset - halfSize);
                    tempVector.Y = (-halfSize);
                    tempVector.Z = (-(j + offset - halfSize));

                    tempVector.UnitLength();
                    tempVector = tempVector.GetPackedTo01();

                    data[byteCounter++] = (byte)(tempVector.X * 255f);
                    data[byteCounter++] = (byte)(tempVector.Y * 255f);
                    data[byteCounter++] = (byte)(tempVector.Z * 255f);

                }
            }
            gl.TexImage2D(OpenGL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
                            0, OpenGL.GL_RGBA8, 32, 32, 0, OpenGL.GL_RGB, OpenGL.GL_UNSIGNED_BYTE, data);

            //positive z
            byteCounter = 0;

            for (int j = 0; j < size; j++)
            {
                for (int i = 0; i < size; i++)
                {
                    tempVector.X = (i + offset - halfSize);
                    tempVector.Y = (-(j + offset - halfSize));
                    tempVector.Z = (halfSize);

                    tempVector.UnitLength();
                    tempVector = tempVector.GetPackedTo01();

                    data[byteCounter++] = (byte)(tempVector.X * 255f);
                    data[byteCounter++] = (byte)(tempVector.Y * 255f);
                    data[byteCounter++] = (byte)(tempVector.Z * 255f);

                }
            }
            gl.TexImage2D(OpenGL.GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
                            0, OpenGL.GL_RGBA8, 32, 32, 0, OpenGL.GL_RGB, OpenGL.GL_UNSIGNED_BYTE, data);

            //negative z
            byteCounter = 0;

            for (int j = 0; j < size; j++)
            {
                for (int i = 0; i < size; i++)
                {
                    tempVector.X = (-(i + offset - halfSize));
                    tempVector.Y = (-(j + offset - halfSize));
                    tempVector.Z = (-halfSize);

                    tempVector.UnitLength();
                    tempVector = tempVector.GetPackedTo01();

                    data[byteCounter++] = (byte)(tempVector.X * 255f);
                    data[byteCounter++] = (byte)(tempVector.Y * 255f);
                    data[byteCounter++] = (byte)(tempVector.Z * 255f);
                }
            }
            gl.TexImage2D(OpenGL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
                            0, OpenGL.GL_RGBA8, 32, 32, 0, OpenGL.GL_RGB, OpenGL.GL_UNSIGNED_BYTE, data);

            return true;
        }

这段代码的主要目的是生成一个立方体贴图(Cube Map)。在 OpenGL 中,立方体贴图通常用于环境映射、天空盒(Skybox)等效果。每个面都会生成一个 32x32 的像素格子,并通过计算每个面上每个像素的位置来获得其颜色值。这里是通过计算每个像素对应的单位向量(normalization vector),然后将该向量转换为颜色数据(RGB),最终上传到 OpenGL 中生成立方体贴图。

代码解析:

变量定义和初始化:

cs 复制代码
byte[] data = new byte[32 * 32 * 3];
int size = 32;
float offset = 0.5f;
float halfSize = 16.0f;
Vertex tempVector = new Vertex();
uint byteCounter = 0;

data 是存储每个面数据的数组,大小为 32x32 的每个像素 3 个通道的 RGB 数据(即 32 * 32 * 3 字节)。

size 表示每个面是 32x32 的大小。

offset 和 halfSize 用于计算立方体的每个像素点的坐标。

tempVector 用于存储每个计算得到的顶点(向量)。

byteCounter 用来记录当前存储的位置。

正 X 面计算:

cs 复制代码
for (int j = 0; j < size; j++)
{
    for (int i = 0; i < size; i++)
    {
        tempVector.X = (halfSize);
        tempVector.Y = (-(j + offset - halfSize));
        tempVector.Z = (-(i + offset - halfSize));
        tempVector.UnitLength();
        tempVector = tempVector.GetPackedTo01();
        data[byteCounter++] = (byte)(tempVector.X * 255f);
        data[byteCounter++] = (byte)(tempVector.Y * 255f);
        data[byteCounter++] = (byte)(tempVector.Z * 255f);
    }
}
gl.TexImage2D(OpenGL.GL_TEXTURE_CUBE_MAP_POSITIVE_X,
                0, OpenGL.GL_RGBA8, 32, 32, 0, OpenGL.GL_RGB, OpenGL.GL_UNSIGNED_BYTE, data);

这部分代码是用来计算并生成正 X 面的纹理数据。每个像素的位置会根据当前的 i 和 j 值来计算对应的三维坐标(tempVector.X, tempVector.Y, tempVector.Z)。

然后调用 UnitLength() 方法对向量进行归一化,确保每个向量的长度为 1。

接着调用 GetPackedTo01() 方法将向量的各分量映射到 0 到 1 之间。

最后,将计算出的 RGB 值存入 data 数组中,并通过 gl.TexImage2D 函数上传数据到 OpenGL 的正 X 面。

负 X 面计算: 负 X 面的计算与正 X 面类似,只是方向相反。代码如下:

cs 复制代码
byteCounter = 0;
for (int j = 0; j < size; j++)
{
    for (int i = 0; i < size; i++)
    {
        tempVector.X = (-halfSize);
        tempVector.Y = (-(j + offset - halfSize));
        tempVector.Z = ((i + offset - halfSize));
        tempVector.UnitLength();
        tempVector = tempVector.GetPackedTo01();
        data[byteCounter++] = (byte)(tempVector.X * 255f);
        data[byteCounter++] = (byte)(tempVector.Y * 255f);
        data[byteCounter++] = (byte)(tempVector.Z * 255f);
    }
}
gl.TexImage2D(OpenGL.GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
                0, OpenGL.GL_RGBA8, 32, 32, 0, OpenGL.GL_RGB, OpenGL.GL_UNSIGNED_BYTE, data);

tempVector.X 设置为负值,其他计算过程与正 X 面相同。

正 Y 面计算:

cs 复制代码
byteCounter = 0;
for (int j = 0; j < size; j++)
{
    for (int i = 0; i < size; i++)
    {
        tempVector.X = (i + offset - halfSize);
        tempVector.Y = (halfSize);
        tempVector.Z = ((j + offset - halfSize));
        tempVector.UnitLength();
        tempVector = tempVector.GetPackedTo01();
        data[byteCounter++] = (byte)(tempVector.X * 255f);
        data[byteCounter++] = (byte)(tempVector.Y * 255f);
        data[byteCounter++] = (byte)(tempVector.Z * 255f);
    }
}
gl.TexImage2D(OpenGL.GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
                0, OpenGL.GL_RGBA8, 32, 32, 0, OpenGL.GL_RGB, OpenGL.GL_UNSIGNED_BYTE, data);

这部分代码计算的是正 Y 面的数据,与正 X 面类似,不同的是 tempVector.Y 设置为正值,表示 Y 轴上的正方向。

负 Y 面计算: 负 Y 面的计算与正 Y 面类似,只是 tempVector.Y 设置为负值。代码如下:

cs 复制代码
byteCounter = 0;
for (int j = 0; j < size; j++)
{
    for (int i = 0; i < size; i++)
    {
        tempVector.X = (i + offset - halfSize);
        tempVector.Y = (-halfSize);
        tempVector.Z = (-(j + offset - halfSize));
        tempVector.UnitLength();
        tempVector = tempVector.GetPackedTo01();
        data[byteCounter++] = (byte)(tempVector.X * 255f);
        data[byteCounter++] = (byte)(tempVector.Y * 255f);
        data[byteCounter++] = (byte)(tempVector.Z * 255f);
    }
}
gl.TexImage2D(OpenGL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
                0, OpenGL.GL_RGBA8, 32, 32, 0, OpenGL.GL_RGB, OpenGL.GL_UNSIGNED_BYTE, data);

正 Z 面和负 Z 面的计算: 正 Z 面和负 Z 面的计算方法与前面的类似,只是 tempVector.Z 设置为正值或负值。

正 Z 面:

cs 复制代码
byteCounter = 0;
for (int j = 0; j < size; j++)
{
    for (int i = 0; i < size; i++)
    {
        tempVector.X = (i + offset - halfSize);
        tempVector.Y = (-(j + offset - halfSize));
        tempVector.Z = (halfSize);
        tempVector.UnitLength();
        tempVector = tempVector.GetPackedTo01();
        data[byteCounter++] = (byte)(tempVector.X * 255f);
        data[byteCounter++] = (byte)(tempVector.Y * 255f);
        data[byteCounter++] = (byte)(tempVector.Z * 255f);
    }
}
gl.TexImage2D(OpenGL.GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
                0, OpenGL.GL_RGBA8, 32, 32, 0, OpenGL.GL_RGB, OpenGL.GL_UNSIGNED_BYTE, data);

负 Z 面:

cs 复制代码
byteCounter = 0;
for (int j = 0; j < size; j++)
{
    for (int i = 0; i < size; i++)
    {
        tempVector.X = (-(i + offset - halfSize));
        tempVector.Y = (-(j + offset - halfSize));
        tempVector.Z = (-halfSize);
        tempVector.UnitLength();
        tempVector = tempVector.GetPackedTo01();
        data[byteCounter++] = (byte)(tempVector.X * 255f);
        data[byteCounter++] = (byte)(tempVector.Y * 255f);
        data[byteCounter++] = (byte)(tempVector.Z * 255f);
    }
}
gl.TexImage2D(OpenGL.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
                0, OpenGL.GL_RGBA8, 32, 32, 0, OpenGL.GL_RGB, OpenGL.GL_UNSIGNED_BYTE, data);

总结:

这段代码通过计算每个面上每个像素对应的单位向量,将向量值转换为 RGB 颜色,并使用 OpenGL 的 TexImage2D 方法将数据上传到 GPU,从而生成立方体贴图。

代码结构中有很多重复的部分,可以考虑通过提取成函数来进行重构,从而减少冗余。

相关推荐
qq_416018723 分钟前
实时数据可视化库
开发语言·c++·算法
格林威3 分钟前
工业相机参数解析:曝光时间与运动模糊的“生死博弈”
c++·人工智能·数码相机·opencv·算法·计算机视觉·工业相机
2401_8732046517 分钟前
C++中的策略模式进阶
开发语言·c++·算法
xushichao198922 分钟前
C++中的职责链模式实战
开发语言·c++·算法
大鹏说大话29 分钟前
数据库查询优化全攻略:从索引设计到架构演进
算法
小O的算法实验室29 分钟前
2025年IEEE TETCI SCI2区,一种用于二次无约束二进制优化的协同神经动力学算法,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
2301_8184190135 分钟前
C++中的协程编程
开发语言·c++·算法
add45a37 分钟前
C++中的工厂方法模式
开发语言·c++·算法
無限進步D44 分钟前
二分算法 cpp
算法
xushichao19891 小时前
C++中的工厂模式高级应用
开发语言·c++·算法