SDL2中如何在从Surface创建的纹理上叠加渲染纹理?
解决SDL中在PNG纹理上叠加文字的问题
嘿,我来帮你搞定这个问题!你遇到的核心痛点其实很明确:从Surface创建的纹理默认是SDL_TEXTUREACCESS_STATIC访问模式,根本没法被设置为渲染目标——所以你之前调用SDL_SetRenderTarget(renderer, bg)其实是无效的,文字实际还是被渲染到了默认的窗口帧缓冲上,最终出现文字在背景下方(或被背景覆盖)的问题。
既然你的需求是仅在应用启动时执行一次,性能要求不高,这里有两个简单且靠谱的解决方案:
方案1:创建支持渲染目标的纹理,分步绘制
这个思路是先创建一个专门支持作为渲染目标的纹理,先把背景图渲染进去,再叠加文字,最终得到合并好的纹理。
// 1. 加载背景图片到Surface SDL_Surface *bgImg = IMG_Load(PNG_PATH); if (!bgImg) { // 这里加错误处理,比如打印SDL_GetError() return; } // 2. 关键步骤:创建支持渲染目标的纹理 SDL_Texture *mergedTexture = SDL_CreateTexture( renderer, bgImg->format->format, // 和背景图保持相同像素格式 SDL_TEXTUREACCESS_TARGET, // 必须是这个模式才能当渲染目标 bgImg->w, bgImg->h ); if (!mergedTexture) { SDL_FreeSurface(bgImg); // 错误处理 return; } // 3. 将渲染目标切换到mergedTexture,先绘制背景 SDL_SetRenderTarget(renderer, mergedTexture); // 可选:先清空纹理(如果背景图是透明的,建议清成透明色) SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); SDL_RenderClear(renderer); // 把背景图转成临时纹理,渲染到目标纹理上 SDL_Texture *bgTemp = SDL_CreateTextureFromSurface(renderer, bgImg); SDL_RenderCopy(renderer, bgTemp, NULL, NULL); // 用完临时纹理立刻销毁,避免内存泄漏 SDL_DestroyTexture(bgTemp); SDL_FreeSurface(bgImg); // 4. 渲染文字到mergedTexture上 SDL_Surface *textSurface = TTF_RenderText_Blended(font, text, red); if (textSurface) { SDL_Texture *txtTexture = SDL_CreateTextureFromSurface(renderer, textSurface); if (txtTexture) { SDL_RenderCopy(renderer, txtTexture, NULL, &textDstRect); SDL_DestroyTexture(txtTexture); } SDL_FreeSurface(textSurface); } // 5. 恢复默认渲染目标(回到窗口帧缓冲) SDL_SetRenderTarget(renderer, NULL); // 后续直接使用mergedTexture进行渲染即可 SDL_RenderCopy(renderer, mergedTexture, NULL, NULL); SDL_RenderPresent(renderer); // 程序退出时记得销毁mergedTexture // SDL_DestroyTexture(mergedTexture);
方案2:直接在Surface层面合并,再转成纹理
因为只需要执行一次,完全可以跳过纹理渲染目标的复杂操作,直接在Surface层面把文字叠加到背景图上,再转成最终纹理。这个方法更简单,代码量更少。
// 1. 加载背景Surface SDL_Surface *bgImg = IMG_Load(PNG_PATH); if (!bgImg) { // 错误处理 return; } // 2. 生成文字Surface SDL_Surface *textSurface = TTF_RenderText_Blended(font, text, red); if (textSurface) { // 重要:将文字Surface转换为和背景图相同的像素格式,避免blit出错 SDL_Surface *textSurfaceConverted = SDL_ConvertSurface(textSurface, bgImg->format, 0); if (textSurfaceConverted) { // 3. 把文字blit到背景Surface上 SDL_BlitSurface(textSurfaceConverted, NULL, bgImg, &textDstRect); SDL_FreeSurface(textSurfaceConverted); } SDL_FreeSurface(textSurface); } // 4. 将合并后的Surface转成纹理 SDL_Texture *finalTexture = SDL_CreateTextureFromSurface(renderer, bgImg); SDL_FreeSurface(bgImg); // 后续渲染这个最终纹理 SDL_RenderCopy(renderer, finalTexture, NULL, NULL); SDL_RenderPresent(renderer); // 程序退出时销毁finalTexture // SDL_DestroyTexture(finalTexture);
为什么原来的方法无效?
再补充解释下:SDL_CreateTextureFromSurface生成的纹理默认是SDL_TEXTUREACCESS_STATIC,这种纹理是只读的,只能用来被渲染,不能作为渲染目标接收绘制操作。你调用SDL_SetRenderTarget时,SDL会默默地忽略这个无效的目标,所以文字实际被渲染到了窗口的帧缓冲上,而背景纹理如果之后被渲染到窗口,就会覆盖文字(或者反之,取决于你的渲染顺序)。
内容的提问来源于stack exchange,提问作者devil0150
相关产品推荐
相关产品推荐

