GL.BindTexture 表现得很奇怪

GL.BindTexture is acting strange

我已经 运行 撞了我的头将近 3 天了,现在我变得很奇怪。

我基本上是在尝试创建一个地图应用程序,该应用程序本质上首先将地图纹理绘制到 OpenTK.GLControl,然后在该地图上创建多个 "dots" 表示实体,最后打印每个点旁边的实体名称。

我终于做到了,看到这个 image here

这是实现此目的的绘画方法:

    private void glControl_Paint(object sender, PaintEventArgs e)
    {
        if (!glControlLoaded)
            return;

        GL.Clear(ClearBufferMask.ColorBufferBit);

        if (currentMapImage != null)
        {
            GL.BindTexture(TextureTarget.Texture2D, mapTextureId);

            GL.Enable(EnableCap.Texture2D);
            GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int)TextureEnvMode.Decal);
            GL.Begin(PrimitiveType.Quads);
            GL.TexCoord2(currentZoomRectangle.Left, currentZoomRectangle.Top); GL.Vertex3(0, 0, 0.0f);
            GL.TexCoord2(currentZoomRectangle.Right, currentZoomRectangle.Top); GL.Vertex3(glControl.Width, 0, 0.0f);
            GL.TexCoord2(currentZoomRectangle.Right, currentZoomRectangle.Bottom); GL.Vertex3(glControl.Width, glControl.Height, 0.0f);
            GL.TexCoord2(currentZoomRectangle.Left, currentZoomRectangle.Bottom); GL.Vertex3(0, glControl.Height, 0.0f);
            GL.End();
            GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int)TextureEnvMode.Modulate);
            GL.Disable(EnableCap.Texture2D);
        }

        GL.Begin(PrimitiveType.Points);
        foreach (Entity entity in entityList)
        {
            if (filtersForm.getShowEntity(entity.Name))
            {
                if (filtersForm.getShowDot(entity.TypeConverted))
                {
                    Color dotColor = settingsForm.getDotColor(entity.TypeConverted);
                    GL.Color3(dotColor);

                    PointF? dotGlControlPos = getGlControlPos(entity.ZeroToOnePosition);
                    if (dotGlControlPos != null)
                    {
                        GL.Vertex3(dotGlControlPos.Value.X, dotGlControlPos.Value.Y, 0.0);
                    }
                }
            }
        }
        GL.End();

        using (Graphics gfx = Graphics.FromImage(textBitmap))
        {
            gfx.Clear(Color.Transparent);
            gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;

            foreach (Entity entity in entityList)
            {
                if (filtersForm.getShowEntity(entity.Name))
                {
                    if (filtersForm.getShowDot(entity.TypeConverted))
                    {
                        if (filtersForm.getShowName(entity.TypeConverted))
                        {
                            PointF? nameGlControlPos = getGlControlPos(entity.ZeroToOnePosition);
                            if (nameGlControlPos != null)
                            {
                                Color nameColor = nameColor = settingsForm.getNameColor(entity.TypeConverted);
                                nameGlControlPos = new PointF(nameGlControlPos.Value.X + 5, nameGlControlPos.Value.Y - settingsForm.EntityFontHeightInPixels - 5);
                                gfx.DrawString(entity.Name, settingsForm.EntityFont, new SolidBrush(nameColor), nameGlControlPos.Value);
                            }
                        }
                    }
                }
            }
        }

        GL.BindTexture(TextureTarget.Texture2D, textTextureId);

        System.Drawing.Imaging.BitmapData data = textBitmap.LockBits(new Rectangle(0, 0, textBitmap.Width, textBitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
        GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, glControl.Width, glControl.Height, PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);
        textBitmap.UnlockBits(data);

        GL.Enable(EnableCap.Texture2D);
        GL.Enable(EnableCap.Blend);
        GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.OneMinusSrcAlpha);

        GL.Begin(PrimitiveType.Quads);
        GL.TexCoord2(0.0f, 0.0f); GL.Vertex3(0, 0, -0.1f);
        GL.TexCoord2(1.0f, 0.0f); GL.Vertex3(glControl.Width, 0, -0.1f);
        GL.TexCoord2(1.0f, 1.0f); GL.Vertex3(glControl.Width, glControl.Height, -0.1f);
        GL.TexCoord2(0.0f, 1.0f); GL.Vertex3(0, glControl.Height, -0.1f);
        GL.End();

        GL.BindTexture(TextureTarget.Texture2D, mapTextureId);

        glControl.SwapBuffers();
    }

现在有趣的是,如果我删除上述方法中的最后一个 GL.BindTexture()-调用(即 glControl.SwapBuffers()-调用之前的调用),如下所示:

private void glControl_Paint(object sender, PaintEventArgs e)
{
    ...
    ...
    ...

    //GL.BindTexture(TextureTarget.Texture2D, mapTextureId);

    glControl.SwapBuffers();
}

我得到 this as a result

我不知道我最初是如何想出添加该调用的想法的。这对我来说没有任何意义......我以为我实际上只需要调用它一次(在我实际绘制地图纹理的开始时)。

所以我想我的问题是,谁能告诉我这是怎么回事?

这是因为您在尝试渲染地图之前没有绑定 mapTextureId

看,当您执行 GL.BindTexture(TextureTarget.Texture2D, textTextureId); 时,这意味着 所有进一步的渲染 将使用该纹理。好吧,直到下一个绑定命令。您刚刚注释掉了。

您唯一一次绑定 mapTextureId 是在您第一次创建纹理时;你再也没有绑定它,除了你注释掉的行。

OpenGL 中的状态不会因为您忘记它而改变。您的代码之所以起作用,是因为您注释掉了那一行。通过绑定纹理,您是说任何未来的渲染命令都将使用该纹理。即使那些未来的渲染命令发生在下一帧

基本上,您的代码是偶然运行的。

你应该做的是绑定纹理,用那个纹理渲染你想渲染的东西,然后解除绑定纹理(通过绑定 0)。