Akashic Engine으로 조명

Akashic Advent Calendar 2019의 25일째 보도입니다.
Akashic Engine은 조각 착색기를 사용할 수 있습니다.게임 화면에 다양한 후기 효과를 적용할 수 있습니다.이 글에서 우리는 조각 착색기를 사용하여 조명을 실현하려고 시도할 것이다.

목표 확인


일단 완성형부터 확인해보자.

스포트라이트에 귀여운 고양이가 그려진 포스터가 떠올랐다.

작문 생각


조명에는 점광원(점에서 전체 방향으로의 광원)과 평행광원(무한히 먼 곳에 있는 광원)이 포함됩니다.이 글은 게임에서 사용할 수 있는 스포트라이트를 실현할 것이다.
게임 화면의 일부를 밝게 비추는 것을 고려할 때도 2차원 처리로 완성할 수 있다. 여기서 아래의 그림처럼 모형화를 시도해 보자.

UV 평면은 조각 음영처리기로 처리된 텍스쳐 평면입니다.W축을 추가합니다.높은 곳에서 손전등으로 비추는 것이 인상적이다.
스포트라이트가 어느 방향을 강하게 비추면 그 방향에서 멀어지면 쇠퇴한다.다음 그림에서 라이트에서 연장된 화살표는 스폿라이트의 방향입니다.멀어질수록 쇠퇴가 커서 허선의 바깥쪽을 밝게 비추지 않는다.

스폿라이트 매개변수는 다음과 같습니다.
  • 위치
  • 방향
  • 마감
  • 스폿라이트 범위의 각도를 결정합니다.
  • 밝기
  • 지수
  • 스포트라이트 방향에서 멀어지면서 빛이 약해지는 값.
  • 환경광
  • 스포트라이트 범위 밖의 밝기.
  • 구체적인 계산은 코드에서 확인하세요.

    완성


    음영처리기는 다음과 같습니다.
    #version 100
    
    precision mediump float;
    
    uniform sampler2D uSampler;
    varying vec2 vTexCoord;
    
    // テクスチャの解像度。
    uniform float image_width;
    uniform float image_height;
    
    // スポットライトのパラメータ。
    // スポットライトの位置。
    uniform float light_pos_x;
    uniform float light_pos_y;
    uniform float light_pos_z;
    // スポットライトの方向。
    uniform float light_dir_x;
    uniform float light_dir_y;
    uniform float light_dir_z;
    // スポットライトの明るさ。
    uniform float light_intensity;
    // スポットライトの範囲。
    uniform float light_cutoff;
    // スポットライトの指数(大きくなるほど速く減衰する)。
    uniform float light_exp;
    // 環境光。スポットライトの範囲外の明るさ。
    uniform float light_ambient;
    
    // スポットライトの計算
    //
    // uv: スポットライトで照らされる画像上の位置。
    // n: 画像の法線。
    // lightPos: スポットライトの位置。
    // cutoff: スポットライトの範囲。
    // itensity: スポットライトの明るさ。
    float spotLighting(vec2 uv, vec3 lightPos, vec3 spotDir, float cutoff, float exponent, float intensity) {
        // 画像上の一点からみた光源の方向。
        vec3 lightDir = normalize(lightPos - vec3(uv, 0.));
        // 画像上の一点に届く光線がスポットライトの方向からどの程度離れているか、を表す量(離れ具合の角度の余弦)。
        float spotCos = dot(spotDir, -lightDir);
        // スポットライトに照らされる範囲にあるか。
        if (spotCos >= cutoff) {
            return max(dot(vec3(0., 0., 1.), lightDir), 0.) // UV平面に対して光線が斜めに当たるほど弱くなるようにする。
                 * pow(spotCos, exponent) // スポットライトの向きから外れた光線ほど減衰するようにする。
                  * intensity; // スポットライト本来の明るさ。
        } else {
            // スポットライトの範囲外は照らされない。
            return 0.;
        }
    }
    
    void main() {
        vec2 uv = vTexCoord;
    
        vec3 lightPosition = vec3(light_pos_x, light_pos_y, light_pos_z);
        vec3 spotDir = normalize(vec3(light_dir_x, light_dir_y, light_dir_z));
        float intensity = spotLighting(uv, lightPosition, spotDir, light_cutoff, light_exp, light_intensity);
    
        vec3 ambient = vec3(light_ambient);
        vec3 lightColor = vec3(1., 1., 1.);
        vec4 color = texture2D(uSampler, uv);
    
        gl_FragColor = vec4(color.rgb * ambient + color.rgb * lightColor * intensity, 1.);
    }
    
    다음은 스폿라이트의 구현입니다.프레젠테이션 가능GitHub에서 가져오기.

    응용: 입체감 구현

    spotLighting()의 계산에는 상수vec3(0., 0., 1.)가 있다.이것은 UV 평면이 W축의 양방향으로 향하는 값입니다.
    이 값을 변경하면 이미지 표면에 요철이 있는 것처럼 조명을 사용할 수 있습니다.다음 예는 이미지의 밝기에서 요철을 구하는 것이다.벽돌담에 입체감이 있다.

    마지막


    이 글에서 우리는 조각 착색기에서 스포트라이트를 실현했다.공포계 소설 게임과 모험 게임의 추리 부분을 사용할 수 있다.

    좋은 웹페이지 즐겨찾기