Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I want to render output on a device to an arbitary quadirlateral, i.e. project texture on to a quad. What are the possible ways I could implement it?

Till now, I have investigated:

  • Drawing textured quadrilateral - Quads look odd as they are composed of triangles, and the distortion looks odd. The issue I'm facing has been discussed here and here as well.
  • Setting transformation on device - Need help in getting this implemented.
  • Pixel shaders - Not able to implement the desired effect.

Any help would be much appreciated.

share|improve this question
1  
Try searching for Render to texture. I got enough results.. e.g. two-kings.de/tutorials/dxgraphics/dxgraphics16.html Once you get your texture, just map it to a quad.. I don't see why this wouldn't work, since it's how many engines do it (e.g. Ogre3D has this technique out of the box and it is working for a plethora of effects..) –  teodron Apr 22 '12 at 8:50
    
Well, I did try setting the texture and drawing a quad, but the overall distortion looked like the quad is composed of two triangles and each triangle distorted independently. –  Trainee4Life Apr 22 '12 at 14:25
1  
You may want to review a basic "texture a quad" tutorial before continuing, pay attention to the camera/projection matrix setup and how the quad itself is built. –  Patrick Hughes Apr 22 '12 at 16:28

2 Answers 2

up vote 1 down vote accepted

Don't if it will help you or not but if you want to implement it with pixel shader see if the shader below can help you.

/// <summary>Explain the purpose of this variable.</summary>
/// <minValue>0,0/minValue>
/// <maxValue>1,1</maxValue>
/// <defaultValue>0,0</defaultValue>
float2 LeftTop :register(C0);
/// <summary>Explain the purpose of this variable.</summary>
/// <minValue>0,0/minValue>
/// <maxValue>1,1</maxValue>
/// <defaultValue>0,1</defaultValue>
float2 LeftBottom :register(C1);
/// <summary>Explain the purpose of this variable.</summary>
/// <minValue>0,0/minValue>
/// <maxValue>1,1</maxValue>
/// <defaultValue>1,0</defaultValue>
float2 RightTop :register(C2);
/// <summary>Explain the purpose of this variable.</summary>
/// <minValue>0,0/minValue>
/// <maxValue>1,1</maxValue>
/// <defaultValue>1,1</defaultValue>
float2 RightBottom    :register(C3);

sampler input : register(s0);

float3x3 Adjoint(float3x3 m)
{
    float3x3 adj;

    // Calculate the adjoint matrix
    adj._11 = m._22*m._33 - m._23*m._32;
    adj._12 = m._13*m._32 - m._12*m._33;
    adj._13 = m._12*m._23 - m._13*m._22;

    adj._21 = m._23*m._31 - m._21*m._33;
    adj._22 = m._11*m._33 - m._13*m._31;
    adj._23 = m._13*m._21 - m._11*m._23;

    adj._31 = m._21*m._32 - m._22*m._31;
    adj._32 = m._12*m._31 - m._11*m._32;
    adj._33 = m._11*m._22 - m._12*m._21;

    return adj;
}





float4 Projection(float2 uv)
{
    float a,b,c,d,e,f,g,h;

    //setting variable names as variable names in algorithem
   float x0,x1,x2,x3,y0,y1,y2,y3;
   x0=LeftTop.x;
   y0=LeftTop.y;
   x1=RightTop.x;
   y1=RightTop.y;
   x2=RightBottom.x;
   y2=RightBottom.y;
   x3=LeftBottom.x;
   y3=LeftBottom.y;

   //If the polygon is Parallegoram
    a=x1-x0;
    b=x2-x1;
    c=x0;
    d=y1-y0;
    e=y2-y1;
    f=y0;
    g=0;
    h=0;


    float x3minusx0 = x3-x0;
    float SigmaX=(b - x3minusx0);
    float y3minusy0 = y3- y0;
    float SigmaY=( e - y3minusy0);

    //If the polygon is not a Parallegoram the following changes need to be done to the variables
    //if( SigmaX!=0 || SigmaY!=0)
    {    
        float DeltaX1=-b;
        float DeltaX2=x3-x2;
        float DeltaY1=-e;
        float DeltaY2=y3-y2;
        float2x2 mat1 = {DeltaX1,DeltaX2,DeltaY1,DeltaY2};
        float denom = determinant(mat1);
        float2x2 mat2 = {SigmaX,DeltaX2,SigmaY,DeltaY2};
        g= determinant(mat2) / denom;
        float2x2 mat3= {DeltaX1,SigmaX,DeltaY1,SigmaY};
        h= determinant(mat3) /denom;
        a+=g*x1;
        b=(x3minusx0)+h*x3;
        d+=g*y1;
        e=y3minusy0+h*y3;
    }

    float3x3 ProjectionMatrix3x3= {a,d,g,b,e,h,c,f,1};
    float3x3 AdjoitOfProjectionMatrix3x3= Adjoint(ProjectionMatrix3x3);

    float3 inputVector=float3(uv.x,uv.y,1);
    float3 outputVector= mul(inputVector,AdjoitOfProjectionMatrix3x3);

   float2 FoundPoint;   

   //Converting homogenious point to noramal 2D cordinate
   FoundPoint.x=outputVector.x/outputVector.z;
   FoundPoint.y=outputVector.y/outputVector.z;

   //some point grater than 1   
   if(FoundPoint.x <0 || FoundPoint.y<0 || FoundPoint.x > 1 || FoundPoint.y > 1 ) 
   {
        return float4(0,0,0,0);
   }
   else
   {
        return tex2D(input, FoundPoint);
   }
}


float4 main(float2 uv: TEXCOORD) : COlOR
{
  return Projection(uv);
}


technique TransformTexture {
  pass P0     {        
    PixelShader  = compile ps_2_0 main(); 
  }
}
share|improve this answer

One way to map a square/rectangular texture to an arbitrary quad is projective interpolation. I've written an article showing how to do this.

The short version: you interpolate UVs across the quad in a way analogous to how GPUs do it for perspective-correct rendering (which, as you may have noticed, does not produce a visible seam between the two triangles). To do this, you need to calculate a false "depth" value for each vertex of the quad, and do the interpolation using homogeneous coordinates based on this "depth". Full details are in the article linked above.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.