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

Unity中Sprite转Texture出现拉伸问题及脚本设置纹理渲染模式为Cutout的实现方法问询

解决Doom风格游戏中Sprite转Texture的拉伸问题与自动设置Cutout渲染模式

嘿,这俩问题我之前做复古风格FPS的时候也碰到过,咱们一步步来解决:

一、用脚本自动将材质切换为Cutout渲染模式

首先得纠正一个小误区:你说的“纹理渲染模式”其实是材质的Shader参数,纹理本身没有Opaque/Cutout的属性,是Standard Shader这类材质通过配置来控制渲染逻辑的。

要实现自动切换到Cutout,你需要修改材质的几个关键参数:开启Alpha测试、设置裁剪阈值、调整渲染队列和混合模式。我给你写个通用的工具方法,直接调用就行:

// 先定义一个枚举方便调用
public enum RenderMode
{
    Opaque,
    Cutout,
    Fade,
    Transparent
}

// 传入目标材质和要切换的渲染模式
public void SetMaterialRenderMode(Material targetMaterial, RenderMode mode)
{
    switch (mode)
    {
        case RenderMode.Cutout:
            // 切换到Cutout模式的核心参数
            targetMaterial.SetFloat("_Mode", 1); // Cutout对应的值是1
            targetMaterial.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
            targetMaterial.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
            targetMaterial.SetInt("_ZWrite", 1);
            
            // 启用Alpha测试的关键词
            targetMaterial.EnableKeyword("_ALPHATEST_ON");
            targetMaterial.DisableKeyword("_ALPHABLEND_ON");
            targetMaterial.DisableKeyword("_ALPHAPREMULTIPLY_ON");
            
            // 设置Cutout的裁剪阈值(可根据你的Sprite透明度调整,0.5是常用值)
            targetMaterial.SetFloat("_Cutoff", 0.5f);
            // 调整渲染队列,确保Cutout物体在正确的顺序渲染
            targetMaterial.renderQueue = 2450;
            break;
        // 如果需要其他模式,可以继续补充Opaque/Fade/Transparent的逻辑
    }
}

然后在你的Start方法里调用它就行,注意一定要用material而不是sharedMaterial,不然会修改原始材质文件,导致所有用这个材质的物体都被影响:

void Start()
{
    var targetSprite = spr[0];
    // 先处理Sprite转Texture的逻辑,后面会讲
    Texture2D fixedTexture = CreateTextureFromSprite(targetSprite);
    
    // 获取面板的Renderer组件
    Renderer panelRenderer = panel.GetComponent<Renderer>();
    // 实例化材质副本,避免修改原始材质
    Material materialInstance = new Material(panelRenderer.material);
    materialInstance.mainTexture = fixedTexture;
    
    // 调用方法切换到Cutout模式
    SetMaterialRenderMode(materialInstance, RenderMode.Cutout);
    
    // 将修改后的材质赋值给面板
    panelRenderer.material = materialInstance;
}

二、解决Sprite转Texture的拉伸问题

你的原始代码里texture = spr[0].texture;这一步踩了个坑:Sprite的texture属性其实是它所在的整个图集纹理,而Sprite只是这个大纹理里的一块区域。直接把整个图集纹理赋值给面板,肯定会因为尺寸不匹配导致拉伸。

正确的做法是从Sprite中提取它对应的像素区域,创建一个和Sprite尺寸完全一致的新Texture2D。我写了个工具方法来做这件事:

public Texture2D CreateTextureFromSprite(Sprite sprite)
{
    // 根据Sprite的实际尺寸创建Texture2D
    Texture2D newTexture = new Texture2D(
        (int)sprite.rect.width, 
        (int)sprite.rect.height, 
        TextureFormat.ARGB32, 
        false
    );
    
    // 从原始纹理中提取Sprite对应的像素区域
    Color[] spritePixels = sprite.texture.GetPixels(
        (int)sprite.rect.x, 
        (int)sprite.rect.y, 
        (int)sprite.rect.width, 
        (int)sprite.rect.height
    );
    
    // 将像素赋值给新纹理并应用
    newTexture.SetPixels(spritePixels);
    newTexture.Apply();
    
    // 可选:设置纹理的过滤模式,复古风格游戏可以用Point过滤避免模糊
    newTexture.filterMode = FilterMode.Point;
    
    return newTexture;
}

额外优化建议

如果你的面板是3D物体,创建完纹理后,最好调整面板的缩放比例,让它和Texture的宽高比一致,这样就完全不会拉伸了。比如:

// 调整面板缩放比例匹配纹理宽高比
float aspectRatio = (float)fixedTexture.width / fixedTexture.height;
panel.transform.localScale = new Vector3(aspectRatio, 1, 1);

如果是用UGUI的Panel,其实更简单:直接用Image组件,把Sprite赋值给Image.sprite,然后把Image的Image Type设为Single,材质用UI/Default Cutout就行,完全不用手动转Texture,Unity会自动处理所有细节。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 06:32:35