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

如何在SharpDX.Direct3D9中按指定像素尺寸缩放纹理?

问题分析

你的核心问题出在坐标系误解和未考虑纹理实际尺寸两个方面:

  1. Sprite默认使用归一化设备坐标系(范围-1到1),直接用「目标像素/屏幕分辨率」的比例计算缩放,没有完成像素坐标到该坐标系的正确映射,导致尺寸偏差。
  2. 加载纹理时使用D3DX.DefaultNonPowerOf2,Direct3D会自动将非2的幂次尺寸的纹理调整为最近的2的幂次(比如120x120会被转为128x128),你没有基于纹理实际尺寸计算缩放比例,进一步放大了误差。
解决方案

推荐两种简单可靠的实现方式,优先选第一种:

方案1:直接用Sprite.Draw重载指定目标矩形(最省心)

不需要手动构建缩放矩阵,利用Sprite的内置重载直接传入像素坐标的目标矩形,自动处理缩放和旋转:

public static bool DrawTexture(IntPtr device, IntPtr txt, RectangleF rect, float rotation, Color tint)
{
    try {
        Texture texture = (Texture)txt;
        // 获取纹理实际尺寸(取第0级mipmap的原生尺寸)
        SurfaceDescription desc = texture.GetLevelDescription(0);
        int texWidth = desc.Width;
        int texHeight = desc.Height;

        using (Sprite s = new Sprite((Device)device)) {
            s.Begin(SpriteFlags.None);
            
            // 旋转中心设为纹理自身的中心,对应目标矩形的中心
            Vector3 center = new Vector3(texWidth / 2f, texHeight / 2f, 0);
            // 绘制位置设为目标矩形的中心坐标
            Vector3 position = new Vector3(rect.X + rect.Width / 2f, rect.Y + rect.Height / 2f, 0);
            
            // 传入源矩形(整个纹理)和目标参数,自动完成缩放
            s.Draw(texture, 
                new Rectangle(0, 0, texWidth, texHeight),
                center,
                position,
                tint.ToRawColorBGRA());
            
            s.End();
        }
        return true;
    }
    catch (Exception ex) {
        Main.managerInstance.console.PrintError(string.Format("[Direct3D9] An error occured while trying to draw texture. Details: {0}", ex.ToString()));
    }
    return false;
}

方案2:修正矩阵变换逻辑(适合需要自定义矩阵的场景)

手动构建矩阵时,先切换到像素坐标系,再基于纹理实际尺寸计算缩放比例:

public static bool DrawTexture(IntPtr device, IntPtr txt, RectangleF rect, float rotation, Color tint)
{
    try {
        Texture texture = (Texture)txt;
        SurfaceDescription desc = texture.GetLevelDescription(0);
        float texWidth = desc.Width;
        float texHeight = desc.Height;
        Size res = CGame.Resolution;
        
        // 计算缩放比例:目标像素尺寸 / 纹理原始尺寸
        float scaleX = rect.Width / texWidth;
        float scaleY = rect.Height / texHeight;

        using (Sprite s = new Sprite((Device)device)) {
            // 设置正交投影矩阵,将坐标系转为像素空间:左上角(0,0),右下角(屏幕宽,屏幕高)
            Matrix orthoMatrix = Matrix.OrthoOffCenterLH(0, res.Width, res.Height, 0, 0, 1);
            s.SetTransform(SpriteTransformType.Projection, orthoMatrix);
            
            s.Begin(SpriteFlags.None);
            
            // 矩阵变换顺序:先平移到纹理中心作为旋转原点→缩放→旋转→平移到目标矩形中心
            Matrix m = Matrix.Identity 
                * Matrix.Translation(-texWidth/2f, -texHeight/2f, 0)
                * Matrix.Scaling(scaleX, scaleY, 1)
                * Matrix.RotationZ(rotation)
                * Matrix.Translation(rect.X + rect.Width/2f, rect.Y + rect.Height/2f, 0);
            
            s.Transform = m;
            s.Draw(texture, tint.ToRawColorBGRA());
            
            s.End();
        }
        return true;
    }
    catch (Exception ex) {
        Main.managerInstance.console.PrintError(string.Format("[Direct3D9] An error occured while trying to draw texture. Details: {0}", ex.ToString()));
    }
    return false;
}
额外注意事项
  • 永远通过texture.GetLevelDescription(0)获取纹理实际尺寸,不要依赖原图尺寸,因为D3DX.DefaultNonPowerOf2会自动调整非2的幂次纹理的尺寸。
  • 如果不需要纹理自动调整尺寸,可以在加载时直接指定具体宽高(比如原图是128x128就传128),但需要确保设备支持非2的幂次纹理(Direct3D9大部分设备都支持)。

内容的提问来源于stack exchange,提问作者E. S.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 03:27:39