您的位置:

3D转换2D

一、基础知识

在介绍3D转换2D之前,我们需要先了解一些基础知识。在计算机图形学中,3D图形指的是三维空间中的图形,而2D图形指的是二维平面中的图形。而3D转换2D就是将3D图形转换成2D图形,也就是将三维空间中的图形投影到二维平面上。

在计算机图形学中,3D图形通常使用三维坐标系表示,也就是(x, y, z),其中x表示垂直于屏幕的方向,y表示水平方向,z表示垂直于屏幕的深度方向。而2D图形则通常使用二维坐标系表示,也就是(x, y)。

二、3D坐标转2D坐标

将3D图形转换成2D图形的过程通常分为两个阶段:投影和映射。在投影阶段,我们需要根据观察视角,将3D坐标系中的点投影到二维平面上,得到一个二维坐标系中的点。在映射阶段,我们将二维坐标系中的点映射到屏幕上,得到最终的图像。

在投影阶段,通常使用的方法是透视投影和正交投影。透视投影是指利用视角,将三维图形投影到一个透视平面上,得到二维图形。正交投影是指将三维图形的每个点沿视角垂直于投影面的方向进行投影,得到二维图形。

float3 ProjectTo2D(float3 pt, float4x4 view, float4x4 projection, float viewportWidth, float viewportHeight)
{
    // 投影变换
    float4 projPt = mul(projection, mul(view, float4(pt, 1.0)));

    // 归一化坐标系
    float2 normPt = projPt.xy / projPt.w;

    // 视口变换
    float2 screenPt = (normPt + 1.0) * 0.5 * float2(viewportWidth, viewportHeight);

    return float3(screenPt, projPt.z);
}

三、矩阵变换

由于在计算机图形学中,我们通常使用矩阵变换来进行坐标的转换。因此,在3D转换2D中,我们也需要运用矩阵变换来对图形进行变换。具体包括平移、旋转、缩放等操作。

float4x4 CreateTranslationMatrix(float3 translation)
{
    return float4x4(
        float4(1.0, 0.0, 0.0, 0.0),
        float4(0.0, 1.0, 0.0, 0.0),
        float4(0.0, 0.0, 1.0, 0.0),
        float4(translation, 1.0)
    );
}

float4x4 CreateRotationMatrix(float3 axis, float angle)
{
    axis = normalize(axis);
    float s = sin(angle);
    float c = cos(angle);
    float4 r0 = float4(c + axis.x * axis.x * (1.0 - c), axis.x * axis.y * (1.0 - c) - axis.z * s, axis.x * axis.z * (1.0 - c) + axis.y * s, 0.0);
    float4 r1 = float4(axis.y * axis.x * (1.0 - c) + axis.z * s, c + axis.y * axis.y * (1.0 - c), axis.y * axis.z * (1.0 - c) - axis.x * s, 0.0);
    float4 r2 = float4(axis.z * axis.x * (1.0 - c) - axis.y * s, axis.z * axis.y * (1.0 - c) + axis.x * s, c + axis.z * axis.z * (1.0 - c), 0.0);
    float4 r3 = float4(0.0, 0.0, 0.0, 1.0);
    return float4x4(r0, r1, r2, r3);
}

float4x4 CreateScaleMatrix(float3 scale)
{
    return float4x4(
        float4(scale.x, 0.0, 0.0, 0.0),
        float4(0.0, scale.y, 0.0, 0.0),
        float4(0.0, 0.0, scale.z, 0.0),
        float4(0.0, 0.0, 0.0, 1.0)
    );
}

四、实例

下面是一个简单的实例,展示了如何使用矩阵变换实现一个旋转立方体的过程。

float3x3 RotationMatrix(float yaw, float pitch, float roll)
{
    float3x3 mPitch = float3x3(
        float3(1.0, 0.0, 0.0),
        float3(0.0, cos(pitch), -sin(pitch)),
        float3(0.0, sin(pitch), cos(pitch))
    );
    float3x3 mYaw = float3x3(
        float3(cos(yaw), 0.0, sin(yaw)),
        float3(0.0, 1.0, 0.0),
        float3(-sin(yaw), 0.0, cos(yaw))
    );
    float3x3 mRoll = float3x3(
        float3(cos(roll), -sin(roll), 0.0),
        float3(sin(roll), cos(roll), 0.0),
        float3(0.0, 0.0, 1.0)
    );
    return mul(mul(mPitch, mYaw), mRoll);
}

void RenderCube(float time)
{
    float3 cameraPos = float3(0.0, 0.0, -10.0);
    float3 targetPos = float3(0.0, 0.0, 0.0);
    float3 up = float3(0.0, 1.0, 0.0);
    float4x4 view = CreateLookAtMatrix(cameraPos, targetPos, up);

    float aspectRatio = GetAspectRatio();
    float4x4 projection = CreatePerspectiveMatrix(PI / 3.0f, aspectRatio, 0.1f, 100.0f);
    float4x4 world = CreateRotationMatrix(float3(1.0, 1.0, 1.0), time);

    float4x4 worldViewProj = mul(projection, mul(view, world));

    float3 cubeVertices[8] = {
        float3(-1.0, 1.0, -1.0),
        float3(1.0, 1.0, -1.0),
        float3(1.0, -1.0, -1.0),
        float3(-1.0, -1.0, -1.0),
        float3(-1.0, 1.0, 1.0),
        float3(1.0, 1.0, 1.0),
        float3(1.0, -1.0, 1.0),
        float3(-1.0, -1.0, 1.0)
    };

    float4 cubeColors[8] = {
        float4(1.0, 0.0, 0.0, 1.0),
        float4(0.0, 1.0, 0.0, 1.0),
        float4(0.0, 0.0, 1.0, 1.0),
        float4(1.0, 1.0, 0.0, 1.0),
        float4(1.0, 0.0, 1.0, 1.0),
        float4(0.0, 1.0, 1.0, 1.0),
        float4(1.0, 1.0, 1.0, 1.0),
        float4(0.0, 0.0, 0.0, 1.0)
    };

    int cubeIndices[36] = {
        0, 1, 2, 2, 3, 0,
        1, 5, 6, 6, 2, 1,
        5, 4, 7, 7, 6, 5,
        4, 0, 3, 3, 7, 4,
        3, 2, 6, 6, 7, 3,
        4, 5, 1, 1, 0, 4
    };

    for (int i = 0; i < 36; i += 3)
    {
        float3 v0 = cubeVertices[cubeIndices[i]];
        float3 v1 = cubeVertices[cubeIndices[i + 1]];
        float3 v2 = cubeVertices[cubeIndices[i + 2]];

        float4 c0 = cubeColors[cubeIndices[i]];
        float4 c1 = cubeColors[cubeIndices[i + 1]];
        float4 c2 = cubeColors[cubeIndices[i + 2]];

        DrawTriangle(
            TransformTo2D(v0, worldViewProj, GetViewportWidth(), GetViewportHeight()),
            TransformTo2D(v1, worldViewProj, GetViewportWidth(), GetViewportHeight()),
            TransformTo2D(v2, worldViewProj, GetViewportWidth(), GetViewportHeight()),
            c0, c1, c2);
    }
}