ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Direct2D] ID2D1Effect : Color matrix
    C++/미분류 2024. 4. 12. 15:46

    지난 글에서 D2D Effect와, 해당 객체를 사용해서 이미지에 아핀 변환을 수행하는 방법을 알아보았습니다.

    [Direct2D] ID2D1Effect 사용하기
    [Direct2D] ID2D1Effect : Affine transformation

    이번 글에서는 이미지의 색을 바꾸는 색조 행렬 변환에 대해 알아보도록 하겠습니다.

     

    이번 글은 지난 글에서 코드가 이어집니다.

    [Direct2D] ID2D1Effect : Affine transformation
    Color matrix effect - Win32 apps | Microsoft Learn

    또한, 위 MSDN에 기반하여 작성되었습니다.

     


     

    1. Effect 생성 및 초기화

     

    더보기

    D2D Effect는 Device context에 의해 초기화되며, 이 때 적용활 효과에 대한 ID를 사용합니다.

    색조 행렬 변환은 다음과 같이 초기화 할 수 있습니다.

    ComPtr<ID2D1Effect> colorMatrixEffect;
    myDirect2dContext->CreateEffect(
        CLSID_D2D1ColorMatrix,
        &colorMatrixEffect
    );

     

    초기화 된 Effect객체에 효과를 적용할 이미지를 지정합니다.

    ComPtr<ID2D1Bitmap> tmp = myCharacterBitmap->GetBitmap();
    if (tmp) {
        colorMatrixEffect->SetInput(0, tmp.Get());
        ...
    }

    이번 글에서는 위 코드가 아닌, 이전 글에서 사용된 아핀 변환 효과에 색조 행렬 변환을 추가해보도록 하겠습니다.

    colorMatrixEffect->SetInputEffect(0, affineTransformEffect.Get());

    SetInputEffect함수는 이미지가 아닌 효과를 추가하는 함수입니다.

    해당 함수를 사용할 경우, 지정한 효과에 추가적인 효과가 적용됩니다.

     

    2. 변환 적용하기

     

    더보기

    D2D Effect의 색조 행렬 변환은 각 픽셀에 다음과 같은 행렬 연산을 수행합니다.

    각 픽셀의 RGBA값은 0-1사이의 Float값 입니다. 

    코드로는 다음과 같습니다.

    D2D1_MATRIX_5X4_F matrix = D2D1::Matrix5x4F(
        1, 0, 0, 0, 
        0, 1, 0, 0, 
        0, 0, 1, 0, 
        0, 0, 0, 1, 
        0, 0, 0, 0);
    colorMatrixEffect->SetValue(
        D2D1_COLORMATRIX_PROP_COLOR_MATRIX,
        matrix
    );

    위 matrix의 값에 따라 각 픽셀의 RGBA값이 변동됩니다.

    예제 코드의 matrix는 주대각행렬이 모두 1인 행렬로, 각 픽셀의 RGBA값이 보존됩니다.

     

    이번 예제에서는 다음 행렬을 적용시키도록 하겠습니다.

    D2D1_MATRIX_5X4_F matrix = D2D1::Matrix5x4F(
        0, 0, 0, 0, 
        0, 0, 0, 0, 
        0, 0, 0, 0, 
        0, 0, 0, 100, 
        0, 1, 0, 0);

    위 matrix는 이미지의 R, B값을 0으로, G와 A값을 1로 지정합니다.

    A값은 이미지의 반투명한 부분을 반영하기 위해 기존 값에 큰 수를 곱했습니다. 

     

    3. 주의점 및 다른 속성

     

    더보기

    Direct2D에서 그리는 픽셀의 RGBA값은 0에서 1사이의 실수값입니다.

    하지만, D2D Effect를 통해 조작되는 RGBA값은 해당 범위를 초과할 수 있습니다.

    예를 들어, 위 문단의 A값에 100을 곱한 결과는 그대로 1을 초과한 값이 됩니다.

    해당 문제는 Effect에 추가적인 조작을 했을 때 발생할 수 있습니다.

     

    다음과 코드를 보겠습니다.

    D2D1_MATRIX_5X4_F matrix2 = D2D1::Matrix5x4F(
        1, 0, 0, 0,
        0, 1, 0, 0,
        0, 0, 1, 0,
        0, 0, 0, 0.5,
        0, 0, 0, 0);
    colorMatrixEffect2->SetValue(
        D2D1_COLORMATRIX_PROP_COLOR_MATRIX,
        matrix2
    );

    위 코드는 위 문단의 Effect에 추가적인 색조 행렬 변환을 수행하는 코드입니다.

    위 Effect는 지정한 이미지의 A값을 절반으로 만들어, 이미지가 투명해보이는 효과를 연출합니다.

    하지만 A값에 0.5를 곱해도 1이 넘어가는 경우, 투명도가 조절되지 않습니다.

     

    위와 같은 문제는 다음 코드로 해결이 가능합니다.

    colorMatrixEffect->SetValue(
        D2D1_COLORMATRIX_PROP_CLAMP_OUTPUT,
        TRUE
    );

    해당 코드는 RGBA값을 0에서 1사이로 고정하는 코드입니다.

    0미만의 값은 0으로, 1이상의 값은 1이 됩니다.

    기본 값은 FALSE로 설정되어 있어, 범위를 넘어가는 값에 대한 보정이 적용되지 않습니다.

     

    색을 조작할 때, 결과값에 주의하고, 값이 범위를 벗어날 경우 위와 같이 보정하는 것이 좋습니다.

     

    4. 출력하기

     

    더보기

    D2D Effect의 출력은 이전 글과 동일하게, DrawImage함수로 수행할 수 있습니다.

    myDirect2dContext->DrawImage(
        affineTransformEffect.Get(), 
        D2D1::Point2F(ps.x - 175.f, ps.y - 150.f));
    // Add    
    myDirect2dContext->DrawImage(
        colorMatrixEffect.Get(), 
        D2D1::Point2F(ps.x - 175.f, ps.y - 50.f));
    myDirect2dContext->DrawImage(
        colorMatrixEffect2.Get(), 
        D2D1::Point2F(ps.x - 175.f, ps.y + 50.f));

    기존의 아핀 변환 출력물과 동시에 확인할 수 있도록, 기존 코드에 그려지는 Effect객체를 추가했습니다. 

     


     

    본문의 내용을 따라, 기존 코드에 색조 행렬 변환을 수행한 예제는 다음과 같이 출력됩니다.

    출력 이미지가 늘었기 때문에, 동시에 확인하기 용이하도록 아핀 변환의 스케일 수치를 작게 조정했습니다.

    해당 출력에 대한 코드 전문은 아래 Github에서 확인하실 수 있습니다.

     

    GitHub - ruru14/WinapiStudy: WinAPI및 DirectX를 공부하며, 간단한 운동 법칙을 적용해봅니다.

    WinAPI및 DirectX를 공부하며, 간단한 운동 법칙을 적용해봅니다. Contribute to ruru14/WinapiStudy development by creating an account on GitHub.

    github.com

     

    이번 글이 도움이 되셨기를 바랍니다.

    감사합니다.

    댓글

Designed by Tistory.