답변:
광각 렌즈는 다른 일반 렌즈 모델과 다르게 작동해서는 안됩니다. 그것들은 더 큰 FOV ( D3DXMatrixPerspectiveFovLH
DirectX를 사용한다고 가정합니다) 또는 더 큰 왼쪽 / 오른쪽 및 아래쪽 / 상단 값 (OpenGL glFrustum
의미)을 가지고 있습니다.
정말 흥미로운 부분은 어안 렌즈 모델링에 있다고 생각합니다. 거기에 어안이 지진 이 소스와 함께 제공, 당신이 공부할 수있다.
그러나 어안 렌즈의 투영은 매우 비선형 적입니다. 보다 일반적인 (감시 카메라로 제한된 내 지식) 종류의 렌즈 M
에서 공간 반점이 단위 반구의 표면에 투영 된 다음 해당 표면이 단위 디스크에 평행 투영됩니다.
M
x M: world position
\ M': projection of M on the unit hemisphere
\ ______ M": projection of M' on the unit disc (= the screen)
M'_x' `-.
,' |\ `.
/ | \ \
/ | \ \
| | \ |
__________|_____|____\_________|_________
M" O 1
더 재미있는 효과를 줄 수 있는 다른 어안 매핑 이 있습니다. 그것은 당신에게 달려 있습니다.
HLSL에서 어안 효과를 구현하는 두 가지 방법을 볼 수 있습니다.
장점 : 코드에서 거의 변경할 필요가 없습니다. 프래그먼트 셰이더는 매우 간단합니다. 오히려 :
...
float4 screenPoint = mul(worldPoint, worldViewProjMatrix);
...
다음과 같이하십시오 (아마도 단순화 될 수 있습니다).
...
// This is optional, but it computes the z coordinate we will
// need later for Z sorting.
float4 out_Point = mul(in_Point, worldViewProjMatrix);
// This retrieves the world position so that we can project on
// the hemisphere. Normalise this vector and you get M'
float4 tmpPoint = mul(in_Point, worldViewMatrix);
// This computes the xy coordinates of M", which happen to
// be the same as M'.
out_Point.xy = tmpPoint.xy / length(tmpPoint.xyz);
...
단점 : 전체 렌더링 파이프 라인은 선형 변환에 대해 고려되었으므로 결과 투영은 정점에 대해 정확하지만 텍스처 좌표뿐만 아니라 모든 변화가 잘못되고 삼각형은 왜곡 된 것처럼 보이더라도 삼각형으로 표시됩니다.
해결 방법 : 더 많은 삼각형 세분으로 GPU에 세련된 지오메트리를 보내면 더 나은 근사치를 얻을 수 있습니다. 이 작업은 지오메트리 셰이더에서도 수행 될 수 있지만이 단계는 정점 셰이더 이후에 수행되므로 지오메트리 셰이더는 자체 추가 투영을 수행해야하기 때문에 상당히 복잡합니다.
또 다른 방법은 광각 투영을 사용하여 장면을 렌더링 한 다음 전체 화면 조각 셰이더를 사용하여 어안 효과를 얻기 위해 이미지를 왜곡하는 것입니다.
어안 화면에 점 M
에 좌표가 있으면 반구 표면에 (x,y)
좌표가 있음을 의미합니다 . 어떤이 좌표 한 의미 의 FOV로 렌더링 우리의 장면에서 그러한가 . (여기서 나의 수학에 대해 100 % 확신하지 못합니다. 오늘 밤 다시 확인하겠습니다).(x,y,z)
z = sqrt(1-x*x-y*y)
(ax,ay)
theta
a = 1/(z*tan(theta/2))
따라서 프래그먼트 셰이더는 다음과 같습니다.
void main(in float4 in_Point : POSITION,
uniform float u_Theta,
uniform sampler2D u_RenderBuffer,
out float4 out_FragColor : COLOR)
{
z = sqrt(1.0 - in_Point.x * in_Point.x - in_Point.y * in_Point.y);
float a = 1.0 / (z * tan(u_Theta * 0.5));
out_FragColor = tex2D(u_RenderBuffer, (in_Point.xy - 0.5) * 2.0 * a);
}
장점 : 픽셀 정확도로 인한 왜곡없이 완벽한 투사를 얻을 수 있습니다.
단점 : FOV가 180도에 도달 할 수 없으므로 전체 장면을 물리적으로 볼 수 없습니다. 또한 FOV가 클수록 이미지 중앙의 정밀도가 떨어집니다. 정확하게 최대 정밀도를 원하는 위치입니다.
해결 방법 : 예를 들어 5와 같은 여러 렌더링 패스를 수행하여 큐브 손실 방식으로 투영을 수행하면 정밀도 손실을 개선 할 수 있습니다. 또 다른 매우 간단한 해결 방법은 최종 이미지를 원하는 FOV로 간단히 자르는 것입니다. 렌즈 자체에 180도 FOV가 있어도 일부만 렌더링 할 수 있습니다. 이것을 "풀 프레임"어안이라고합니다 (이것은 실제로 이미지를 자르면서 "풀"무언가를 얻는 느낌을주기 때문에 다소 아이러니합니다).
(참고 :이 유용하지만 명확하지 않은 경우 알려주세요. 이에 대한 자세한 기사를 작성하고 싶습니다.)
맞아야 z = sqrt(1.0 - in_Point.x * in_Point.x - in_Point.y * in_Point.y)
합니까?
내 GLSL 구현은 다음과 같습니다
#ifdef GL_ES
precision mediump float;
#endif
varying vec2 v_texCoord;
uniform sampler2D u_texture;
uniform float fovTheta; // FOV's theta
// fisheye
void main (void)
{
vec2 uv = v_texCoord - 0.5;
float z = sqrt(1.0 - uv.x * uv.x - uv.y * uv.y);
float a = 1.0 / (z * tan(fovTheta * 0.5));
// float a = (z * tan(fovTheta * 0.5)) / 1.0; // reverse lens
gl_FragColor = texture2D(u_texture, (uv* a) + 0.5);
}