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)。
我已经 运行 撞了我的头将近 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)。