You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在C#(GLFW)中如何将byte[]转为nint调用glTexImage2D?

在C# OpenGL(GLFW)项目中将字节数组转换为nint传入glTexImage2D的解决方案

问题描述

在基于GLFW的C# OpenGL项目中搭建纹理渲染功能时,调用glTexImage2D函数遇到类型不匹配问题:该函数最后一个参数要求传入nint类型,但实际需要传递的是RGBA格式的字节数组,编译时提示buffer是byte[]类型而非nint。

用户当前代码片段:

byte[] buffer = File.ReadAllBytes("Grass_Block_29_JE2_BE2.rgba");
for (int i = 0; i < buffer.Length; i++) {
    Console.WriteLine(buffer[i]);
}

while (!Glfw.WindowShouldClose(window)) {
    // Load texture
    uint texture = glGenTexture();
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);

    // Texture setup
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 160, 160, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); // 编译报错:buffer是byte[]而非nint
}

解决方案

要将托管的byte[]转换为nint(非托管指针),可以通过以下两种常用方式实现:

方法1:使用fixed关键字(需开启unsafe代码)

fixed关键字可以固定托管数组在内存中的位置,防止GC移动它,然后直接获取数组的首指针并转换为nint。

修改后的代码:

using System.Runtime.InteropServices;

// ... 其他代码

byte[] buffer = File.ReadAllBytes("Grass_Block_29_JE2_BE2.rgba");

// 纹理加载逻辑移到主循环外,避免重复创建纹理导致内存泄漏
uint texture = glGenTexture();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);

// 纹理参数设置
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

while (!Glfw.WindowShouldClose(window)) {
    // 使用fixed获取数组指针
    fixed (byte* ptr = buffer)
    {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 160, 160, 0, GL_RGBA, GL_UNSIGNED_BYTE, (nint)ptr);
    }

    // ... 其他渲染逻辑(清屏、绘制、交换缓冲区等)
}

注意:需要在项目属性中开启“允许不安全代码”(右键项目 -> 属性 -> 生成 -> 勾选“允许不安全代码”)。

方法2:使用GCHandle(无需unsafe代码)

通过GCHandle固定数组,获取其内存地址,用完后释放固定。

修改后的代码:

using System.Runtime.InteropServices;

// ... 其他代码

byte[] buffer = File.ReadAllBytes("Grass_Block_29_JE2_BE2.rgba");

uint texture = glGenTexture();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

// 固定数组并获取地址
GCHandle bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
try
{
    nint dataPtr = bufferHandle.AddrOfPinnedObject();
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 160, 160, 0, GL_RGBA, GL_UNSIGNED_BYTE, dataPtr);
}
finally
{
    // 必须释放固定,否则会导致内存泄漏
    bufferHandle.Free();
}

while (!Glfw.WindowShouldClose(window)) {
    // ... 其他渲染逻辑
}

额外注意事项

  • 避免重复加载纹理:原代码中将纹理生成逻辑放在主循环内,会导致每次循环都创建新的纹理对象,造成严重内存泄漏,建议将纹理加载逻辑移到主循环外部。
  • 验证数组长度:确保buffer的长度等于纹理宽度 * 纹理高度 * 通道数(即1601604=102400字节),否则纹理渲染会出现异常。

内容的提问来源于stack exchange,提问作者CptSDX23

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 04:02:10