-1
$\begingroup$

I have been trying to implement a simple rasterizer in GLSL fragment shader. The goal is to render a quad with texture mapped on it, with correct 3d transforms (perspective and model matrices). I got to the point where it looks ok,except that the Z position of the plane is exactly 2 times closer to the screen than in normal OpenGL rendering pipeline. I double checked all the matrices,the data is correct.Here is my GLSL code:

 uniform mat4 modelMatrix; 
 uniform mat4 projMatrix; 
 uniform sampler2D tex; 
 uniform ivec2 res; 
 out vec4 oColor; 
 struct Tri{ 
 vec4 v0; 
 vec4 v1; 
 vec4 v2; 
 vec2 uv0; 
 vec2 uv1; 
 vec2 uv2; 
 }; 


  vec4 vertices[4]; 
 // 2d cross product, aka "wedge product", returns signed area 
 // of a parallellogram defined by the 2 vectors.
  float cross2d(in vec2 v1, in vec2 v2){   
    return (v1.x*v2.y) - (v1.y*v2.x);       
  } 
  bool drawTriangleBary(in Tri tri,in vec2 uv,inout vec4 color){  
     vec2 p1 = tri.v0.xy;                                          
     vec2 p2 = tri.v1.xy;                                           
     vec2 p3 = tri.v2.xy;                                           

    float triangleArea =  -(cross2d(p2 - p1, p3 - p1)) * 0.5;   
    float w1 = (cross2d(p2 - uv, p1 - uv) * 0.5) / triangleArea; 
    float w2 = (cross2d(p2 - uv, uv - p3) * 0.5) / triangleArea; 
    float w3 = (cross2d(p3 - uv, uv - p1) * 0.5) / triangleArea; 


   if(w1 < 0.0 || w2 < 0.0 || w3 < 0.0){                        
         return false;                                         
   }                                                            
   float z1 = 1.0 / tri.v0.w;                                   
   float z2 = 1.0 / tri.v1.w;                                   
   float z3 = 1.0 / tri.v2.w;                                   

  float depth = 1.0 / (w2 * z1 + w3 * z2 + w1 * z3) ;         
  // Perspective correction for UV coordinates 
  vec2 puv = w2 * (tri.uv0 * z1) + w3 * (tri.uv1 * z2) + w1 * (tri.uv2 * z3);    
   puv *= depth;                                                                    
    color = texture(tex, puv);                                                       
    return true;                                                                     
 } 

  void main(){ 
    vec2 uv = gl_FragCoord.xy / vec2(res);                    
    uv -= vec2(0.5); 
   //build default vertices:
   vertices[0] = vec4(-1.0,-1.0,   0.0,1.0);                       
   vertices[1] = vec4( 1.0,-1.0,   0.0,1.0);                         
   vertices[2] = vec4( 1.0,1.0,    0.0,1.0);                         
   vertices[3] = vec4(-1.0,1.0,    0.0,1.0);                          

   //transform vertices:
   for(int c = 0; c < 4; ++c){                                      
      vertices[c] = projMatrix  * modelMatrix * vertices[c];             
      vertices[c].xyz   /=  vertices[c].w; //to NDC
   } 
     //define triangle geometry:
   Tri tri1 = Tri(vertices[0],vertices[1],vertices[2]  
       ,vec2(0.0,0.0),vec2(1.0,0.0),vec2(1.0,1.0)); 

    bool rasterize = false;                                       
     vec4 colorRes = vec4(0.0);
    rasterize = drawTriangleBary(tri1, uv, colorRes);  
    if(rasterize){ 
          oColor = colorRes;
    }else{discard;}                                                  
   }                                                                 
} 

I omit the code of drawTriangleBary() which simply calculates barycentric coords,computes correct UVs and samples texture.The area of interest is the part where I transform the vertices. For example,if I multiple .w by 2 the Z position looks correct:

 for(int c = 0; c < 4; ++c){                                      
  vertices[c] = projMatrix  * modelMatrix * vertices[c];             
  vertices[c].xyz   /=  vertices[c].w * 2.0; //to NDC

}

Same effect is when I set .z position in modelMatrix which is 2 times larger than the desired position. Is it expected behavior due to transition from clip to NDC space? Or I am missing something here?

$\endgroup$
  • $\begingroup$ $ uv = 2.0(uv-1.0)$ As it is, it's in $[-0.5,0.5]^2$ rather than $[-1,1]^2$. $\endgroup$ – lightxbulb Mar 18 at 19:25
  • $\begingroup$ How uv is related here? I have no issues with texture mapping.I guess I need to remap NDC from [0,1] to [-1,1] $\endgroup$ – Michael IV Mar 18 at 19:38
  • $\begingroup$ You use it here: $drawTriangleBary(tri1, uv, colorRes);$. And yes $ndc$ should be in $[-1,1]^3$ (in some APIs the $z$ coord is in $[0,1]$). $\endgroup$ – lightxbulb Mar 18 at 19:46
  • $\begingroup$ Again,my texture mapping is fine.Yes,I use initial screen space UVs to get barycentric etc. But my question is related to wrong .z position which is 2 times closer to the view port than expected. So I don't understand what you're trying to say. $\endgroup$ – Michael IV Mar 18 at 19:52
  • 1
    $\begingroup$ Ah ok. Sure $uv+= uv - vec2(1)$ is the same as $uv = 2uv - vec2(1)$, guess I just missed that part (it's less obvious written like this too). $\endgroup$ – lightxbulb Mar 18 at 20:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.