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

SDL 1.2中Blit透明Surface时RGB通道异常问题求助

SDL 1.2中Alpha通道Blit失效,RGB意外绘制的问题解决

问题重现

使用SDL 1.2-master版本开发字体系统(每个字形对应一个Surface)时,将Surface的alpha通道设为0(完全透明)后执行Blit操作,原本预期RGB通道内容不会被绘制到屏幕,但实际RGB颜色仍被显示,导致透明效果失效。相关代码如下:

#include <SDL/SDL.h>
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
int main(int argc, char** argv) {
    if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) == -1) {
        fprintf(stderr, "Couldn't initialize SDL: %s.\n", SDL_GetError());
        exit(-1);
    }

    SDL_Rect** modes = SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_HWSURFACE);
    if(!modes) {
        printf(":(\n");
        return 1;
    }
    
    SDL_Surface* screen = SDL_SetVideoMode(modes[0]->w, modes[0]->h, 0, SDL_FULLSCREEN | SDL_HWSURFACE | SDL_DOUBLEBUF);
    if(!screen) {
        printf(":(\n");
        return 1;
    }

    SDL_Surface* surface = SDL_CreateRGBSurface(SDL_HWSURFACE|SDL_SRCALPHA, 32, 32, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
    if(!surface) {
        printf(":((\n");
        return 1;
    }

    for(int i=0; i!=32; i++) {
        for(int j=0; j!=32; j++) {
            // 0 blue
            // 1 green
            // 2 red
            // 3 alpha?
            ((char*)(surface->pixels))[0+i*4*32+j*4] = 0xff;
            ((char*)(surface->pixels))[1+i*4*32+j*4] = 0xff;
            ((char*)(surface->pixels))[2+i*4*32+j*4] = 0xff;
            ((char*)(surface->pixels))[3+i*4*32+j*4] = 0xff; // SDL_OPAQUE_ALPHA is 0xFF

            // not an alpha channel
        }
    }
    int ret = SDL_BlitSurface(surface, NULL, screen, NULL);

    SDL_Flip(screen);
    sleep(2);

    for(int i=0; i!=32; i++) {
        for(int j=0; j!=32; j++) {
            // 0 blue
            // 1 green
            // 2 red
            // 3 alpha?
            ((char*)(surface->pixels))[0+i*4*32+j*4] = 0x30;
            ((char*)(surface->pixels))[1+i*4*32+j*4] = 0x40;
            ((char*)(surface->pixels))[2+i*4*32+j*4] = 0x50;
            ((char*)(surface->pixels))[3+i*4*32+j*4] = 0x00;// This surface should be transparent, SDL_TRANSPARENT_ALPHA is 0

            // not an alpha channel
        }
    }
    ret = SDL_BlitSurface(surface, NULL, screen, NULL);
    
    while(1) {
        SDL_Flip(screen);
        //if the color is anything but pure white, alpha channel modification failed.
    }
}

问题原因

  1. Alpha混合未启用:SDL 1.2中仅在创建Surface时指定SDL_SRCALPHA并不足以开启alpha混合,需要显式设置alpha模式,确保Blit时系统会根据alpha通道值进行像素混合。
  2. 像素索引计算错误:直接使用i*4*32计算行偏移是错误的,SDL Surface的行字节数由pitch字段决定(考虑内存字节对齐),硬编码宽度*像素字节数会导致像素地址偏移错误,可能未正确修改到alpha通道。
  3. 硬件Surface直接访问风险:使用SDL_HWSURFACE创建的Surface,其像素内存可能位于显存中,直接访问前未调用SDL_LockSurface锁定,会导致内存访问异常或修改不生效。

修复方案

1. 启用Alpha混合模式

在Blit前调用SDL_SetAlpha,确保源Surface的alpha通道生效:

SDL_SetAlpha(surface, SDL_SRCALPHA, 0);

该函数会启用源Surface的alpha混合,Blit时系统会根据每个像素的alpha值计算最终颜色。

2. 使用Surface Pitch计算像素偏移

用surface->pitch代替硬编码的4*32,确保行偏移正确:

// 计算像素起始地址
Uint8* pixel = (Uint8*)surface->pixels + i * surface->pitch + j * 4;
pixel[0] = 0x30; // 蓝
pixel[1] = 0x40; // 绿
pixel[2] = 0x50; // 红
pixel[3] = 0x00; // Alpha

3. 安全访问硬件Surface像素

访问硬件Surface的像素前,必须调用SDL_LockSurface锁定内存,操作完成后调用SDL_UnlockSurface解锁:

if (SDL_LockSurface(surface) < 0) {
    fprintf(stderr, "Lock surface failed: %s\n", SDL_GetError());
    return 1;
}
// 这里执行像素修改操作
SDL_UnlockSurface(surface);

修改后的完整代码

#include <SDL/SDL.h>
#include <stdio.h>
#include <unistd.h>

int main(int argc, char** argv) {
    if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) == -1) {
        fprintf(stderr, "Couldn't initialize SDL: %s.\n", SDL_GetError());
        exit(-1);
    }

    SDL_Rect** modes = SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_HWSURFACE);
    if(!modes) {
        printf(":(\n");
        return 1;
    }
    
    SDL_Surface* screen = SDL_SetVideoMode(modes[0]->w, modes[0]->h, 0, SDL_FULLSCREEN | SDL_HWSURFACE | SDL_DOUBLEBUF);
    if(!screen) {
        printf(":(\n");
        return 1;
    }

    SDL_Surface* surface = SDL_CreateRGBSurface(SDL_HWSURFACE|SDL_SRCALPHA, 32, 32, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
    if(!surface) {
        printf(":((\n");
        return 1;
    }

    // 锁定Surface后修改像素
    if (SDL_LockSurface(surface) < 0) {
        fprintf(stderr, "Lock surface failed: %s\n", SDL_GetError());
        return 1;
    }
    for(int i=0; i<32; i++) {
        for(int j=0; j<32; j++) {
            Uint8* pixel = (Uint8*)surface->pixels + i * surface->pitch + j * 4;
            pixel[0] = 0xff; // 蓝
            pixel[1] = 0xff; // 绿
            pixel[2] = 0xff; // 红
            pixel[3] = 0xff; // 完全不透明
        }
    }
    SDL_UnlockSurface(surface);

    // 启用Alpha混合
    SDL_SetAlpha(surface, SDL_SRCALPHA, 0);
    SDL_BlitSurface(surface, NULL, screen, NULL);
    SDL_Flip(screen);
    sleep(2);

    // 再次修改像素为完全透明
    if (SDL_LockSurface(surface) < 0) {
        fprintf(stderr, "Lock surface failed: %s\n", SDL_GetError());
        return 1;
    }
    for(int i=0; i<32; i++) {
        for(int j=0; j<32; j++) {
            Uint8* pixel = (Uint8*)surface->pixels + i * surface->pitch + j * 4;
            pixel[0] = 0x30; // 蓝
            pixel[1] = 0x40; // 绿
            pixel[2] = 0x50; // 红
            pixel[3] = 0x00; // 完全透明
        }
    }
    SDL_UnlockSurface(surface);

    SDL_BlitSurface(surface, NULL, screen, NULL);
    
    while(1) {
        SDL_Flip(screen);
    }

    // 清理资源(示例中未执行,实际开发需添加)
    SDL_FreeSurface(surface);
    SDL_Quit();
    return 0;
}

内容的提问来源于stack exchange,提问作者Nieważne Nieważne

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 14:50:19