Closed3

UnityでCompute Shaderを用いて画像の回転を行う

0y00y0

ImageRotation.hlslについて

テクスチャのサイズを取得

// Get the dimensions of the input texture
uint textureWidth, textureHeight;
inputTexture.GetDimensions(textureWidth, textureHeight);

ピクセルの位置を正規化

// Normalize pixel coordinates to [-0.5, 0.5] range
float2 uv =  float2(id.x, id.y) / float2(textureWidth, textureHeight) - 0.5;

ピクセルの位置をテクスチャの幅と高さで割る。その結果、ピクセルの位置は [0, 1] の範囲に正規化される。さらに、0.5を引くことで [-0.5, 0.5] の範囲になる。(ピクセルの中心を原点とする座標系に変換)

回転行列の計算

// Compute rotation matrix based on the rotation angle
float2x2 rotationMatrix = float2x2(cos(rotationAngle), -sin(rotationAngle), sin(rotationAngle), cos(rotationAngle));

回転行列はrotationAngleから計算され、2次元ベクトルを回転させるために使用する。

ピクセルの位置を回転

// Rotate the pixel position and shift back to [0, 1] range
float2 uvRotated = mul(rotationMatrix, uv) + 0.5;

回転行列を使ってピクセルの位置 uv を回転させ、0.5を足すことで [0, 1] の範囲に戻す。

範囲外チェック

// If rotated pixel is out of bounds, set pixel color to black
if (any(uvRotated < 0.0) || any(uvRotated > 1.0))
{
    resultColor = float4(0.0, 0.0, 0.0, 1.0);
}

回転後のピクセル位置 uvRotated が [0, 1] の範囲を超えているかどうかを確認する。範囲を超えている場合(つまり、回転によりテクスチャの範囲外になった場合)、そのピクセルの値を黒(0.0, 0.0, 0.0, 1.0)に設定する。

バイリニア補間

else
{
    // Scale up the rotated coordinates to original texture size
    uvRotated *= float2(textureWidth, textureHeight);

    // Compute the integer and fractional parts of the coordinates
    int2 uvInt = int2(uvRotated);
    float2 uvFrac = frac(uvRotated);

    // Get the color of four neighboring pixels
    float4 topLeftColor = inputTexture[uvInt]; // Top-left
    float4 topRightColor = inputTexture[uvInt + int2(1, 0)]; // Top-right
    float4 bottomLeftColor = inputTexture[uvInt + int2(0, 1)]; // Bottom-left
    float4 bottomRightColor = inputTexture[uvInt + int2(1, 1)]; // Bottom-right

    // Perform bilinear interpolation to compute final color of the rotated pixel
    float4 topInterpolation = lerp(topLeftColor, topRightColor, uvFrac.x); // Top interpolation
    float4 bottomInterpolation = lerp(bottomLeftColor, bottomRightColor, uvFrac.x); // Bottom interpolation
    resultColor = lerp(topInterpolation, bottomInterpolation, uvFrac.y); // Final interpolation
}

範囲内に留まったピクセルの値を計算する。まず、回転後のピクセル位置 uvRotated をテクスチャのサイズにスケールアップする。次に、ピクセルの整数部分と小数部分を取得する。整数部分はピクセルの位置を表し、小数部分はその位置からのオフセットを表す。この情報を使用して、バイリニア補間を行い、新しいピクセルの値を計算する。バイリニア補間は、4つの隣接ピクセルの値を使い、新しいピクセルの値を計算する。

0y00y0

成果物

インスペクターから回転角を指定可能。

lenna_rotation

このスクラップは2023/08/02にクローズされました