2012-06-07 5 views
3

Я хочу вычислить ширину пространства глаз проецируемой пирамиды пикселя в текущем месте вершины в вершинном шейдере glsl, но я не могу получить правильную математику. Вот, очевидно, неверный пример:ширина пикселя в пространстве в вершинном шейдере GLSL

// GLSL VERTEX SHADER 
#version 410 compatibility 

uniform vec4 viewport; // same as glViewport​ 
in vec4 gl_Vertex; 

void main() 
{ 
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 
    float pixelWidth = gl_Position.z/viewport.z; 
<snip> 

Но это не относится к FOV или плоскостям отсечения.

ответ

1

Я проработал математику и понял ее. :) Как я надеялся, что нет никаких дополнительных матричных преобразований требуется, только один разделяй:

// GLSL VERTEX SHADER 
#version 410 compatibility 

uniform vec4 viewport; // same as glViewport​ 
in vec4 gl_Vertex; 

float pixelWidthRatio = 2./(viewport.z * gl_ProjectionMatrix[0][0]); 

void main() 
{ 
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 
    float pixelWidth = gl_Position.w * pixelWidthRatio; 
    <snip> 

Или в качестве альтернативы:

<snip> 
float pixelHeightRatio = 2./(viewport.w * gl_ProjectionMatrix[1][1]); 

void main() 
{ 
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 
    float pixelHeight = gl_Position.w * pixelHeightRatio; 
<snip> 

Как и следовало ожидать, pixelWidth и pixelHeight одинаковы, если пиксели квадратные.

0

В vertex shader нет такой вещи, как ширина пространства в мире для пикселя. «Ширина» проецируется в пиксель только на данном расстоянии Z. В общем, у вас есть пирамида, проецируемая в пиксель.

Здесь вы идете:

  1. Преобразовать два экрана-точек в НДЦ пунктов:

    vec2 Screen = vec2(ScreenWidth, ScreenHeight); 
        vec3 Point1 = vec3(ScreenPt1/Screen * 2.0 - vec2(1.0), 1.0); 
        vec3 Point2 = vec3(ScreenPt2/Screen * 2.0 - vec2(1.0), 1.0); 
    
  2. Unproject НДЦ точек в мировой космической позиции:

    vec4 R1 = vec4(Point1, 1.0); 
        vec4 R2 = vec4(Point2, 1.0); 
    
        R1 = Projection.GetInversed() * R1; 
        R1 = ModelView.GetInversed() * R1; 
        R1 /= R1.W; 
    
        R2 = Projection.GetInversed() * R2; 
        R2 = ModelView.GetInversed() * R2; 
        R2 /= R2.W; 
    
  3. Найти расстояние между R1 и R2.

В пиксельного шейдера вы можете использовать локальные производные. Посмотрите здесь:

http://www.opengl.org/sdk/docs/manglsl/xhtml/dFdx.xml

и здесь:

http://www.opengl.org/sdk/docs/manglsl/xhtml/fwidth.xml

Доступно только в пиксельный шейдер, dFdx и dFdy вернуть частную производную от выражения р х и у, соответственно. Девианты рассчитываются с использованием локальных различий. Выражения, предполагающие производные более высокого порядка, такие как dFdx (dFdx (n)), имеют неопределенные результаты, как и производные смешанного порядка, такие как dFdx (dFdy (n)). Предполагается, что выражение p является непрерывным, и поэтому выражения, оцениваемые с помощью неравномерного потока управления, могут быть неопределенными.

+1

Эти функции доступны только в шейдере фрагментов, и я спрашиваю о вершинном шейдере, так что это не помогает мне. – atb

+1

См. Мой обновленный ответ. –

+0

OK, используя вашу семантику Мне нужна ширина пространства в мире «пиксельной пирамиды» на z-глубине текущей вершины в вершинном шейдере. Ваш ответ по-прежнему не помогает мне, но спасибо за информацию. – atb