如何在 OpenTK 中的四边形内拟合图像(纹理)?

时间:2021-05-14 12:14:34

标签: c# shader textures opentk

我一直在尝试研究 OpenTK 中纹理的不同示例,但是,几乎没有代码示例使用我想要的相同方法,或者需要许多不符合我需求的无意义解决方法。我只是想在 OpenTK 中绘制图像而不会扭曲或变形它们的 UV。或者更确切地说,我如何使它们变形以适应原始(在这种情况下为四边形/正方形)在 2D 世界中的任何位置?

考虑这个图像(这是我的纹理,我试图放入一个四边形基元中): enter image description here

这是不需要的结果。如您所见,它被裁剪了。我不关心包装,因为我计划将整个图像放入正方形内(不需要纵横比)。不同的包装设置没有任何作用。图像的中心仍然在正方形之外。 enter image description here

透明度和调色板是我要担心的,我只需要帮助将整个图像拟合到正方形内即可!

这是我加载纹理的代码:

    public Texture(Bitmap image)
    {
        ID = GL.GenTexture();

        GL.ActiveTexture(TextureUnit.Texture0);
        GL.BindTexture(TextureTarget.Texture2D, ID);

        BitmapData data = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

        GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, image.Width, image.Height, 0, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);

        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);

        GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);
    }

然后这是我将顶点数据加载到着色器并绘制图元的代码:

        List<float> vertex_data = { 

            -.25f, -.25f,
            -.25f, .25f, 
            .25f, .25f,
            .25f, -.25f
        };

        // Load the 2D object
        GL.UseProgram(program);

        GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
        GL.BufferData(BufferTarget.ArrayBuffer, vertex_data.Count * sizeof(float), vertex_data.ToArray(), BufferUsageHint.DynamicDraw);
        
        GL.EnableVertexAttribArray(attr_pos);
        GL.VertexAttribPointer(attr_pos, 2, VertexAttribPointerType.Float, false, 2 * sizeof(float), 0);
        GL.EnableVertexAttribArray(attr_uv);
        GL.VertexAttribPointer(attr_uv, 2, VertexAttribPointerType.Float, false, 2 * sizeof(float), 0);
        
        // ^^ Using the same position data for the UV as well.
        
        // ...
        
        // Drawing the 2D object
        GL.UseProgram(program);

        GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);

        GL.ActiveTexture(TextureUnit.Texture0);
        GL.BindTexture(TextureTarget.Texture2D, ID);

        GL.DrawArrays(PrimitiveType.Quads, 0, 4);

以及顶点和片段着色器:

垂直:

#version 330 core

layout(location = 1) in vec3 vertex_pos;
layout(location = 2) in vec2 vertex_uv;

out vec2 uv;

uniform mat4 mvp;

void main() {

    gl_Position = mvp * vec4(vertex_pos, 1);
    uv = vertex_uv;
}

碎片:

#version 330 core

in vec2 uv;

out vec4 color;

uniform sampler2D texture0;

void main() {
    
    color = texture(texture0, uv);
}

1 个答案:

答案 0 :(得分:0)

您需要做的就是指定范围 [0.0, 1.0] 内的纹理坐标:

List<float> vertex_data = { 

//   x      y     u     v 
    -.25f, -.25f, 0.0f, 0.0f,
    -.25f,  .25f, 0.0f, 1.0f,
     .25f,  .25f, 1.0f, 1.0f,
     .25f, -.25f, 1.0f, 0.0f,
};

// Load the 2D object
GL.UseProgram(program);

GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
GL.BufferData(BufferTarget.ArrayBuffer, vertex_data.Count * sizeof(float),
    vertex_data.ToArray(), BufferUsageHint.DynamicDraw);

GL.EnableVertexAttribArray(attr_pos);
GL.VertexAttribPointer(attr_pos, 2, VertexAttribPointerType.Float, false,
    4 * sizeof(float), 0);
GL.EnableVertexAttribArray(attr_uv);
GL.VertexAttribPointer(attr_uv, 2, VertexAttribPointerType.Float, false,
    4 * sizeof(float), 2 * sizeof(float));

纹理坐标 (0, 0) 指向纹理的左下边缘,纹理坐标 (1, 1) 指向纹理的右上边缘。
您必须将纹理坐标 (0, 0) 关联到四边形的左下角,将纹理坐标 (1, 1) 关联到四边形的右上角。

GL.VertexAttribPointe (strid) 的第四个参数指定了连续通用顶点属性之间的字节偏移量。由于每个属性由 4 个 flaot (x, y, u, v) 类型的元素组成,所以这是 4*sizeof(float)。最后一个参数是属性的字节偏移量。顶点坐标的偏移量为0,纹理坐标的偏移量为2*sizeof(float)


当然可以使用2个单独的属性数组。在这种情况下,对于顶点坐标和纹理坐标,stride2*sizeof(float)。顶点坐标的偏移量为0,纹理坐标的偏移量为所有顶点坐标的大小(8*sizeof(float)):

使用GL.BufferSubData初始化缓冲区数据:

List<float> vertex_data = { 
    
//   x      y  
    -.25f, -.25f, 
    -.25f,  .25f,
     .25f,  .25f,
     .25f, -.25f,
}

List<float> texture_data = { 
//   u      v  
     0.0f, 0.0f,
     0.0f, 1.0f,
     1.0f, 1.0f,
     1.0f, 0.0f,
};

// Load the 2D object
GL.UseProgram(program);

GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
GL.BufferData(BufferTarget.ArrayBuffer, 
    vertex_data.Count * sizeof(float) + texture_data.Count * sizeof(float), 
    IntPtr.Zero, BufferUsageHint.DynamicDraw);
GL.BufferSubData(BufferTarget.ArrayBuffer, 0, 
    vertex_data.Count * sizeof(float), vertex_data.ToArray())
GL.BufferSubData(BufferTarget.ArrayBuffer, vertex_data.Count * sizeof(float), 
    texture_data.Count * sizeof(float), texture_data.ToArray())

GL.EnableVertexAttribArray(attr_pos);
GL.VertexAttribPointer(attr_pos, 2, VertexAttribPointerType.Float, false, 
    2 * sizeof(float), 0);
GL.EnableVertexAttribArray(attr_uv);
GL.VertexAttribPointer(attr_uv, 2, VertexAttribPointerType.Float, false, 
    2 * sizeof(float), vertex_data.Count * sizeof(float));
相关问题