// precision highp float; uniform sampler2D u_Texture0; uniform sampler2D u_Texture1; uniform sampler2D u_Texture2; varying vec2 v_TexCoords0; varying vec2 v_TexCoords1; varying vec2 v_TexCoords2; #define v_TexCoords1 v_TexCoords0 #define v_TexCoords2 v_TexCoords0 #define v_TexCoords3 v_TexCoords0 uniform float u_opacity; uniform mat4 u_colorMatrix; uniform int u_mode; uniform float u_angle; uniform int u_flip; uniform float u_effectiveWidth; uniform float u_clipBound; uniform float u_screenWidth; uniform float u_screenHeight; uniform float u_realScreenWidth; void main(void) { vec2 fc = v_TexCoords0.st; float PI = 3.141592; float sw = u_screenWidth; float rsw = u_realScreenWidth; float sh = u_screenHeight; // 구분선 픽셀 크기 float pw = (2.0 / u_realScreenWidth);// * u_effectiveWidth; float ph = (2.0 / u_screenHeight); float tmin = 0.2; float tmax = 0.43; const vec4 lineColor = vec4(0.796875,0.59765625,0.19921875,1.0); // VR + PANORAMA if(u_mode == 2 || u_mode == 3) { float R = u_effectiveWidth / 2.0 * 0.96;//0.5; float Cfx = u_effectiveWidth / 2.0; float Cfy = 0.5; float He = 1.0; float We = u_effectiveWidth; float Xe = 1.0-fc.x; // flip h float Ye = 1.0-fc.y; // upside down if(u_mode == 3){ if(Ye > 0.62) { gl_FragColor = vec4(0.0,0.0,0.0,1.0); return; } Ye = (Ye / 0.62); } float r = Ye/He*R; float theta = Xe/We*2.0*PI;// - (u_angle * 3.0); // TOP_DOWN_2D_360 float Xf = Cfx+r*sin(theta); float Yf = Cfy+r*cos(theta); fc = vec2(Xf,Yf); } else if(u_mode == 1) // PANORAMA 4CH { // 4분할 모드 (가로 라인 위치는 u_effectiveWidth 반영) float hw = u_effectiveWidth / 2.0; if(abs(hw - fc.x) < pw || abs(0.5 - fc.y) < ph) { gl_FragColor = lineColor;// return; } fc.y = 1.0 - fc.y; float R = u_effectiveWidth / 2.0 * 0.99; float Cfx = u_effectiveWidth / 2.0; float Cfy = 0.5; float We = u_effectiveWidth; float Xe = 1.0-fc.x; // flip h float Ye = 1.0-fc.y; // upside down // 세로 분할 선 if(fc.y < 0.5) // bottom AREA { /* Ye = 1.0-Ye; float r = (((Ye * (tmax - tmin)) / 0.5) + tmin); // (fmax - fmin) = 0.5 float theta = Xe/We*PI+(PI/2.0); // 1/2 theta += PI; float Xf = Cfx+r*sin(theta); float Yf = Cfy+r*cos(theta); fc = vec2(Xf,Yf); */ // Ye가 0.0일 때 안쪽(tmin), 0.5일 때 바깥쪽(tmax)이 되도록 매핑 // 상하를 뒤집으려면 0.5 - fc.y를 사용하여 좌표 진행 방향을 반대로 바꿉니다. float Ye_flipped = 0.5 - fc.y; float r = (((Ye_flipped * (tmax - tmin)) / 0.5) + tmin); /* float theta = Xe/We*PI+(PI/2.0); theta += PI; float Xf = Cfx+r*sin(theta); float Yf = Cfy+r*cos(theta); fc = vec2(Xf,Yf); */ // 2. 좌우 반전 추가 // Xe가 (1.0 - fc.x)이므로, 이를 다시 반전시키려면 // We(효과 너비)에서 Xe를 뺀 값을 사용하거나 fc.x를 직접 활용합니다. float Xe_flipped = We - Xe; // 3. 반전된 Xe_flipped를 사용하여 theta 계산 float theta = Xe_flipped / We * PI + (PI / 2.0); theta += PI; float Xf = Cfx + r * sin(theta); float Yf = Cfy + r * cos(theta); fc = vec2(Xf, Yf); } else // top AREA 180 ~ 360 { Ye = 1.0-Ye-0.5; //float r = ((Ye*R) * 2.0) * clip_y + offset_y; // float r = (((Ye * (tmax - tmin)) / 0.5) + tmin); // (fmax - fmin) = 0.5 float theta = Xe/We*PI+(PI/2.0); // 1/2 float Xf = Cfx+r*sin(theta); float Yf = Cfy+r*cos(theta); fc = vec2(Xf,Yf); } } else if(u_mode == 4) // 5CH 모드 { float left_area_ratio = 0.5; float left_area_width = u_effectiveWidth * left_area_ratio;//min(sh / sw,0.5) * u_effectiveWidth; if(abs(left_area_width - fc.x) < pw) { gl_FragColor = lineColor; return; } // 5분할 모드 float rx = fc.x; float ry = fc.y; float R = u_effectiveWidth / 2.0 * 0.99; float Cfx = u_effectiveWidth / 2.0; float Cfy = 0.5; float We = u_effectiveWidth; // 우측 (5채널) if (rx < left_area_width) { // 1:1 영역 은 보장됨 float target_area = 0.4; float tx = rx * (1.0 / left_area_width) * target_area + ((1.0-target_area) * 0.5); float ty = ry * target_area + ((1.0-target_area) * 0.5); fc = vec2(tx,ty); } else { // 우측 4분할 (실제로는 2분할) // 나머지 영역 의 // 좌우(abs(fc.x - h_center) < pw) // 상하( abs(fc.y - 0.5) < ph) 라인 그리기 float h_center = (left_area_ratio + ((1.0 - left_area_ratio) * 0.5)) * u_effectiveWidth; if(abs(h_center - rx) < pw || abs(ry - 0.5) < ph) { gl_FragColor = lineColor; return; } // 4채널 모드와 동일 float R = u_effectiveWidth / 2.0 * 0.99; float Cfx = u_effectiveWidth / 2.0; float Cfy = 0.5; float We = u_effectiveWidth; // ry 는 1.0 - left_area_width rx = (1.0 - (rx - left_area_width) / (1.0 - left_area_width)); if(ry > 0.5) // bottom AREA { /* ry = 1.0 - ((ry - 0.5) * 2.0); // ry 는 0.5~1.0 이므로 0.0~1.0으로 변환 float r = ((((ry * R) * (tmax - tmin)) / 0.5) + tmin); float theta = rx/We*PI+(PI/2.0); // 1/2 theta += PI; float Xf = Cfx+r*sin(theta); float Yf = Cfy+r*cos(theta); fc = vec2(Xf,Yf); */ /* // --- 수정 부분 --- // 기존: ry = 1.0 - ((ry - 0.5) * 2.0); -> 중앙이 1.0, 하단끝이 0.0 // 변경: 아래 식은 중앙(0.5)일 때 0.0, 하단끝(1.0)일 때 1.0이 됩니다. ry = (ry - 0.5) * 2.0; float r = ((((ry * R) * (tmax - tmin)) / 0.5) + tmin); float theta = rx / We * PI + (PI / 2.0); theta += PI; float Xf = Cfx + r * sin(theta); float Yf = Cfy + r * cos(theta); fc = vec2(Xf, Yf); */ // 1. 상하 반전 처리 (기존 유지: 중앙 0.5일 때 r 최소, 바닥 1.0일 때 r 최대) ry = (ry - 0.5) * 2.0; float r = ((((ry * R) * (tmax - tmin)) / 0.5) + tmin); // 2. 좌우 반전 추가 // rx 값을 1.0에서 빼줌으로써 좌우를 뒤집습니다. float rx_flipped = 1.0 - rx; // 3. 반전된 rx_flipped를 사용하여 theta 계산 float theta = rx_flipped / We * PI + (PI / 2.0); theta += PI; float Xf = Cfx + r * sin(theta); float Yf = Cfy + r * cos(theta); fc = vec2(Xf, Yf); } else // top AREA 180 ~ 360 { ry = 1.0 - (ry * 2.0); // ry 는 0.0~0.5 이므로 0.0~1.0으로 변환 float r = ((((ry * R) * (tmax - tmin)) / 0.5) + tmin); float theta = rx/We*PI+(PI/2.0); // 1/2 = ANGLE float Xf = Cfx+r*sin(theta); float Yf = Cfy+r*cos(theta); fc = vec2(Xf,Yf); } } } else // FISH EYE { // ZOOM CLIP if (fc.x < 0.0 || fc.x > 1.0) { gl_FragColor = vec4(0.0,0.0,0.0,1.0); return; } fc.x *= u_effectiveWidth; // 1. 중앙 85%의 시작점 (버릴 영역의 크기: 15% / 2 = 7.5%) float START_UV = 0.075; // 2. 텍스처의 85% 영역 크기 float SCALE_RANGE = 1.0 - 2.0 * START_UV; // 0.85 // 3. 출력 UV (0.0~1.0)를 원본 텍스처의 중앙 85% 영역으로 매핑 // New_UV = TexCoords * (0.85) + 0.075 fc = fc * SCALE_RANGE + START_UV; } gl_FragColor = clamp(u_colorMatrix * vec4(texture2D(u_Texture0, fc).r, texture2D(u_Texture1, fc).r, texture2D(u_Texture2, fc).r, 1.0), 0.0, 1.0); }