> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# LampArray 효과

> LampArray 효과

효과와 애니메이션을 만들려면 게임 루프 내에서 [ILampArray](/reference/lighting/lamparray/interfaces/ilamparray/ilamparray) 색상 함수를 호출합니다. 이 페이지에서는 몇 가지 예제를 보여줍니다.

간결한 설명을 위해 이 예제들은 가능한 경우 [ILampArray::SetColor](/reference/lighting/lamparray/interfaces/ilamparray/methods/ilamparray_setcolor)를 사용하여 장치의 모든 Lamp에 색상을 적용합니다. [ILampArray::SetColorsForIndices](/reference/lighting/lamparray/interfaces/ilamparray/methods/ilamparray_setcolorsforindices)를 사용하면 개별 Lamp 또는 Lamp 집합에 효과를 만들 수 있습니다.

## 페이드 및 깜박임

일정 시간 동안 색상의 RGB 값을 증가하거나 감소하는 백분율로 곱하여 Lamp를 페이드 인 또는 페이드 아웃할 수 있습니다. Lamp를 반복적으로 페이드 인 및 페이드 아웃하면 깜박이거나, 숨쉬는 듯하거나, 번쩍이는 효과를 만들 수 있습니다.

다음 예제는 LampArray의 모든 Lamp를 켜고 끄면서 깜박이게 합니다.

```cpp theme={null}
uint32_t currentFrame = 0;

// The total number of frames in one blink
const float blinkFrameCount = 90;

const float blinkFadeFrameCount = blinkFrameCount / 2;

// The color to fade in and out. In this example we'll use red.
const LampArrayColor mainColor = {0xFF /* r */, 0x0 /* g */, 0x0 /* b */, 0xFF /* a */};

Microsoft::WRL::ComPtr<ILampArray> lampArray;

void BlinkUpdateFrame(ILampArray* lampArrayToUpdate)
{
    LampArrayColor currentFrameColor = mainColor;

    float colorScale = 1.0;

    if (currentFrame < blinkFadeFrameCount)
    {
        // Fade out to black
        colorScale = (blinkFadeFrameCount - currentFrame) / blinkFadeFrameCount;
    }
    else
    {
        // Fade in to full color value
        colorScale = (currentFrame - blinkFadeFrameCount) / blinkFadeFrameCount;
    }

    currentFrameColor.r = static_cast<uint8_t>(mainColor.r * colorScale);
    currentFrameColor.g = static_cast<uint8_t>(mainColor.g * colorScale);
    currentFrameColor.b = static_cast<uint8_t>(mainColor.b * colorScale);

    // Apply the color
    lampArrayToUpdate->SetColor(currentFrameColor);

    // Increment our current frame, accounting for overflow
    if (++currentFrame > blinkFrameCount)
    {
        currentFrame = 0;
    }
}

void MainLoop(
    _In_ volatile bool& terminateLoop)
{
    color.a = 0xFF;

    while (!terminateLoop)
    {
        Sleep(50);

        BlinkUpdateFrame(lampArray.Get());
    }
} 
```

## 색상 사이클

색상의 빨간색, 녹색, 파란색 값을 점차적으로 늘리고 줄여서 색상 사이클을 만들 수 있습니다. 이렇게 하면 RGB 스펙트럼상의 넓은 범위 색상들 사이에서 블렌딩됩니다.

다음 예제는 LampArray에 RGB 색상 사이클을 수행합니다.

```cpp theme={null}
uint32_t currentFrame = 0;

// The total number of frames in one cycle
const float cycleFrameCount = 180;

// The size of each "ramp" of the cycle (blending from one color to the next)
const float rampIntervalFrameCount = cycleFrameCount / 6;

// The color to set in each frame
LampArrayColor color = {};

Microsoft::WRL::ComPtr<ILampArray> lampArray;

void CycleUpdateFrame(ILampArray* lampArrayToUpdate)
{
    // Calculate the color for the current frame.
    if (currentFrame < rampIntervalFrameCount)
    {
        // Red -> yellow: increase g
        color.r = 0xFF;
        color.g = static_cast<BYTE>(0xFF * (currentFrame / rampIntervalFrameCount));
    }
    else if (currentFrame < (2 * rampIntervalFrameCount))
    {
        // Yellow -> green: decrease r
        color.r = static_cast<BYTE>(0xFF * (((2 * rampIntervalFrameCount) - currentFrame) / rampIntervalFrameCount));
        color.g = 0xFF;
    }
    else if (currentFrame < (3 * rampIntervalFrameCount))
    {
        // Green -> cyan: increase b
        color.g = 0xFF;
        color.b = static_cast<BYTE>(0xFF * ((currentFrame - (2 * rampIntervalFrameCount)) / rampIntervalFrameCount));
    }
    else if (currentFrame < (4 * rampIntervalFrameCount))
    {
        // Cyan -> blue: decrease g
        color.g = static_cast<BYTE>(0xFF * (((4 * rampIntervalFrameCount) - currentFrame) / rampIntervalFrameCount));
        color.b = 0xFF;
    }
    else if (currentFrame < (5 * rampIntervalFrameCount))
    {
        // Blue -> magenta: increase r
        color.r = static_cast<BYTE>(0xFF * ((currentFrame - (4 * rampIntervalFrameCount)) / rampIntervalFrameCount));
        color.b = 0xFF;
    }
    else
    {
        // Magenta -> red: decrease b
        color.r = 0xFF;
        color.b = static_cast<BYTE>(0xFF * ((cycleFrameCount - currentFrame) / rampIntervalFrameCount));
    }

    // Apply the color
    lampArrayToUpdate->SetColor(color);

    // Increment our current frame, accounting for overflow
    if (++currentFrame > cycleFrameCount)
    {
        currentFrame = 0;
    }
}

void MainLoop(
    _In_ volatile bool& terminateLoop)
{
    color.a = 0xFF;

    while (!terminateLoop)
    {
        Sleep(50);

        CycleUpdateFrame(lampArray.Get());
    }
}
```

## 위치 기반 효과

파문이나 파도처럼 장치를 가로질러 이동하는 것처럼 보이는 효과를 만들 때는 [ILampInfo::GetPosition](/reference/lighting/lamparray/interfaces/ilampinfo/methods/ilampinfo_getposition)과 [ILampArray::GetBoundingBox](/reference/lighting/lamparray/interfaces/ilamparray/methods/ilamparray_getboundingbox)를 사용하세요.

다음 예제는 장치를 가로질러 왼쪽에서 오른쪽으로 이동하며 페이드 아웃되는 Lamp 파도를 생성합니다. "페이드 및 깜박임" 섹션의 스케일링 개념을 통합했지만, Lamp 단위로 적용한 점에 주목하세요.

```cpp theme={null}
Microsoft::WRL::ComPtr<ILampArray> lampArray;

uint32_t currentFrame = 0;

// The total number of frames in one wave
const uint32_t waveFrameCount = 30;

// The number of frames it takes for each Lamp to fade out
const uint32_t fadeDurationInFrames = 10;

// Helper class for per-Lamp effect state information
struct LampContext
{
    uint32_t lampIndex;

    // How far to the right this Lamp is located compared to the total length of the device.
    float xPercentage;

    // The number of frames left in this Lamp's fade-out
    uint32_t fadeFramesRemaining;
};

std::vector<LampContext> lampContexts;

// The Lamp indices for the device, in sorted order by position from left to right
std::vector<uint32_t> indices;

// The colors to set in each frame
std::vector<LampArrayColor> colors;

// The index in the sorted array representing the peak of the wave
uint32_t lastUpdatedIndex = 0;

// The base color to use in the wave effect
const LampArrayColor mainColor = {0xFF /* r */, 0x0 /* g */, 0x0 /* b */, 0xFF /* a */};

void WaveUpdateFrame(ILampArray* lampArrayToUpdate)
{
    float framePercentage = (float)currentFrame / (float)myFrameCount;

    const uint32_t lampCount = lampArrayToUpdate->GetLampCount();
    for (uint32_t i = 0; i < lampCount; i++)
    {
        auto& lampContext = lampContexts[i];

        // Mark any Lamps for which we should start a new fade-out.
        // Use lastUpdatedIndex to track which Lamps we've started in this wave.
        if (i >= lastUpdatedIndex && lampContext.xPercentage <= framePercentage)
        {
            lastUpdatedIndex = i;

            // This Lamp should start at full brightness on this frame.
            lampContext.fadeFramesRemaining = fadeDurationInFrames + 1;
        }

        // Process fade-outs for any Lamps that have fade-out frames remaining
        if (lampContext.fadeFramesRemaining > 0)
        {
            lampContext.fadeFramesRemaining--;

            // Optimization: use the full strength color for the first fade-out frame (without scaling)
            if (lampContext.fadeFramesRemaining == fadeDurationInFrames)
            {
                colors[i] = mainColor;
            }
            else
            {
                // Scale the main color down based on how many fade-out frames are remaining for this Lamp.
                float scaleFactor = (float)lampContext.fadeFramesRemaining / (float)fadeDurationInFrames;

                auto& lampColor = colors[i];
                lampColor.r = static_cast<BYTE>(scaleFactor * mainColor.r);
                lampColor.g = static_cast<BYTE>(scaleFactor * mainColor.g);
                lampColor.b = static_cast<BYTE>(scaleFactor * mainColor.b);
            }
        }
    }

    // Apply the color
    lampArrayToUpdate->SetColorsForIndices(lampCount, indices.data(), colors.data());

    // Increment our current frame, accounting for overflow
    if (++currentFrame > waveFrameCount)
    {
        currentFrame = 0;

        // The peak of the wave also needs to wrap around
        lastUpdatedIndex = 0;
    }
}

HRESULT MainLoop(
    _In_ volatile bool& terminateLoop)
{
    color.a = 0xFF;

    // Set up contexts
    const uint32_t lampCount = lampArray->GetLampCount();
    for (uint32_t i = 0; i < lampCount; i++)
    {
        LampContext context = {};
        context.lampIndex = i;

        Microsoft::WRL::ComPtr<ILampInfo> lampInfo;
        RETURN_IF_FAILED(lampArray->GetLampInfo(i, &lampInfo));

        LampArrayPosition lampPosition = {};
        lampInfo->GetPosition(&lampPosition);

        // Our position values will be relative to the total length of the device.
        context.xPercentage = (float)lampPosition.xInMeters / (float)boundingBox.xInMeters;

        lampContexts.push_back(context);
    }

    // Sort the contexts by position from left to right
    std::sort(lampContexts.begin(),
        lampContexts.end(),
        [](LampContext const& a, LampContext const& b)
        {
            return a.xPercentage < b.xPercentage;
        });

    // Set up our indices buffer in sorted order
    for (uint32_t i = 0; i < lampCount; i++)
    {
        indices[i] = lampContexts[i].lampIndex;
    }

    colors.resize(lampCount);

    // Animation loop for the sample
    while (!terminateLoop)
    {
        Sleep(33);
        WaveUpdateFrame(lampArray.Get());
    }

    return S_OK;
}
```

## 함께 보기

[Lighting API 개요](/build/core-features/common/lighting/gc-lighting-toc)
[ILampArray 참조](/reference/lighting/lamparray/interfaces/ilamparray/ilamparray)


## Related topics

- [XBOX 및 PC의 조명 API와 LampArray](/ko/build/core-features/common/lighting/index.md)
- [Lighting API 개요](/ko/build/core-features/common/lighting/gc-lighting-toc.md)
- [LampArray](/ko/reference/lighting/lamparray/lamparray_members.md)
- [LampArray의 색상 설정](/ko/build/core-features/common/lighting/lighting-colors.md)
- [ILampArray::SetColorsForScanCodes](/ko/reference/lighting/lamparray/interfaces/ilamparray/methods/ilamparray_setcolorsforscancodes.md)
