TECHARTNOMAD | TECHARTFLOWIO.COM

GRAPHICS PROGRAMMING

브랜치 프리 셰이더: 원-핫 마스크로 버텍스 컬러 채널 추출하기

jplee 2025. 8. 15. 19:18

분기 코드는 런타임 분기(동적 분기)로 인해 파이프라인에 따라 비용이 커질 수 있습니다.
프러퍼티.

[Enum(R,0,G,1,B,2,A,3)]_OutlineVertexColorChannel("Outline Vertex Color Channel", Float) = 0
float outlinceVertexColorMask = 0.0;
if (_OutlineVertexColorChannel == 0)
    outlinceVertexColorMask = vertexColor.r;
else if (_OutlineVertexColorChannel == 1)
    outlinceVertexColorMask = vertexColor.g;
else if (_OutlineVertexColorChannel == 2)
    outlinceVertexColorMask = vertexColor.b;
else if (_OutlineVertexColorChannel == 3)
    outlinceVertexColorMask = vertexColor.a;

이런 분기 코드를 최적화 한다면...분기 없이 인덱스에서 원-핫(one-hot) 마스크를 만들고 dot을 사용.

// _OutlineVertexColorChannel: float 또는 int (0,1,2,3)
float c = (float)_OutlineVertexColorChannel;

// 0,1,2,3과의 거리를 이용해 원-핫 마스크 생성 (분기 없음)
float4 mask = saturate(1.0 - abs(float4(0.0, 1.0, 2.0, 3.0) - c));

// vertexColor: float4/half4 (r,g,b,a)
float outlineVertexColorMask = dot(vertexColor, mask);

이 코드는 조건문(분기) 없이 버텍스 컬러에서 특정 채널을 선택하는 셰이더 기법
_OutlineVertexColorChannel 값에 따라 vertexColor에서 특정 채널(R, G, B, A 중 하나)을 선택.

  1. 채널 인덱스 
    • c는 선택할 채널을 나타냅니다:
      • 0 = 빨강(Red) 채널
      • 1 = 초록(Green) 채널
      • 2 = 파랑(Blue) 채널
      • 3 = 알파(Alpha) 채널
  2. 원-핫 마스크 생성
     
    hlsl
    float4 mask = saturate(1.0 - abs(float4(0.0, 1.0, 2.0, 3.0) - c));
    이 코드는 하나의 성분만 1.0이고 나머지는 0.0인 마스크를 생성:
    • c = 0이면: mask는 (1, 0, 0, 0)
    • c = 1이면: mask는 (0, 1, 0, 0)
    • c = 2이면: mask는 (0, 0, 1, 0)
    • c = 3이면: mask는 (0, 0, 0, 1)
  3. 채널 선택
     
    hlsl
    float outlineVertexColorMask = dot(vertexColor, mask);
    내적(dot product)을 통해 각 성분을 곱하고 더하는데, 마스크에서 하나의 성분만 1.0이므로 결과적으로 해당 채널의 값만 추출하면 됨.


추가.
abs 함수는 채널 인덱스(0,1,2,3)와 선택하려는 채널 값 c 사이의 절댓값 거리를 계산.
선택된 채널에서는 0이 되고, 다른 채널에서는 양수가 되도록 하여, saturate(1.0 - abs(...)) 연산을 통해 정확히 하나의 채널만 1이고 나머지는 0인 마스크를 만든다.

  • c = 1일 때: abs(float4(0,1,2,3) - 1) = float4(1,0,1,2)
  • 이것이 saturate(1.0 - ...) 연산을 거치면 (0,1,0,0) 마스크가 됨.


장점

  • GPU 친화적: 분기문(if/else)이 없어서 GPU 성능 저하를 방지
  • 벡터화: SIMD 연산을 효율적으로 활용
  • 유연성: 런타임에 쉽게 채널 변경 가능

이 기법은 버텍스 컬러의 특정 채널에 아웃라인 두께나 다른 속성을 저장하고 동적으로 선택할 때 활용.

One-hot - Wikipedia

From Wikipedia, the free encyclopedia Bit-vector representation where only one bit can be set at a time Decimal Binary Unary One-hot 0 000 00000000 00000001 1 001 00000001 00000010 2 010 00000011 00000100 3 011 00000111 00001000 4 100 00001111 00010000 5 1

en.wikipedia.org

 

GPU-friendly one-hot encoding

Given a vector of indices I want to get a matrix where only one element with corresponding index is one and others are zeros. On CPU it’s pretty easy, e.g.: function onehot(s::AbstractVector, n_dims::Int=maximum(s)) x = zeros(Int, n_dims, length(s)) for

discourse.julialang.org