2016-06-22 6 views
0

회전에 대한 모양이 변경되지 않고 OpenSceneGraph에서 확대/축소되지 않도록 사각형 개체를 표시하려고합니다. 나는 osg::AutoTransform이 나를 위해 일해야한다는 것을 발견했다.스크린에 자동 회전 된 오브젝트를 픽셀 그리드로 정렬하는 방법은 무엇입니까?

그러나 다음 코드를 사용하면 기본값이 LINEAR이 아닌 NEAREST으로 텍스처 필터를 설정해도 깨진 결과가 나타납니다. LINEAR을 사용하면 결과가 흐릿 해 지지만 NEAREST으로 텍셀 라인이 부족한 경우가 있습니다.

#include <osg/Node> 
#include <osgViewer/Viewer> 
#include <osg/Texture2D> 
#include <osg/Geode> 
#include <osg/AutoTransform> 

osg::ref_ptr<osg::Node> createFixedSizeTexture(osg::Image *image,int W,int H) 
{ 
    osg::Vec3Array& verts = *new osg::Vec3Array(4); 
    verts[0] = osg::Vec3(-W/2., -H/2., 0); 
    verts[1] = osg::Vec3(+W/2., -H/2., 0); 
    verts[2] = osg::Vec3(+W/2., +H/2., 0); 
    verts[3] = osg::Vec3(-W/2., +H/2., 0); 

    osg::Vec2Array& texcoords = *new osg::Vec2Array(4); 
    texcoords[0].set(0,0); 
    texcoords[1].set(1,0); 
    texcoords[2].set(1,1); 
    texcoords[3].set(0,1); 

    osg::Geometry*const geometry = new osg::Geometry; 
    geometry->setVertexArray(&verts); 
    geometry->setTexCoordArray(0, &texcoords); 
    geometry->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4)); 

    osg::Texture2D*const texture = new osg::Texture2D(image); 
    texture->setResizeNonPowerOfTwoHint(false); 

    geometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); 

    osg::Geode*const geode = new osg::Geode; 
    geode->addDrawable(geometry); 

    return geode; 
} 

int main() 
{ 
    static constexpr int W=21, H=15; 
    unsigned bits[W*H]; 
    for(int x=0;x<W;++x) 
     for(int y=0;y<H;++y) 
      bits[x+W*y] = (x&y&1)*0xffffffff; 

    osg::Image *formImage = new osg::Image; 
    formImage->setImage(W, H, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, 
         reinterpret_cast<unsigned char*>(bits), osg::Image::NO_DELETE); 

    osg::AutoTransform *at = new osg::AutoTransform; 
    at->setAutoScaleToScreen(true); 
    at->setAutoRotateMode(osg::AutoTransform::ROTATE_TO_SCREEN); 
    at->addChild(createFixedSizeTexture(formImage,W,H)); 

    osgViewer::Viewer viewer; 
    viewer.setUpViewInWindow(0, 0, 800, 600); 
    viewer.setSceneData(at); 

    return viewer.run(); 
} 

이것은 최종 개체의 비 정수 화면 좌표 때문입니다. 이 문제를 해결하려면 객체를 픽셀 격자에 정렬해야합니다. 이것을 어떻게 할 수 있습니까?

답변

0

정렬 오류 문제는 화면 좌표를 정수로 반올림하는 사용자 정점 쉐이더를 사용하여 해결할 수 있습니다.

다음 예는 영업 이익의 코드를 기반으로, 대신 osg::AutoTransform를 사용하는 것이 회전과 스케일링을 제거 + 화면을 반올림의 모든 것이 하나의 쉐이더 좌표 않습니다

#include <osg/Node> 
#include <osgViewer/Viewer> 
#include <osg/Texture2D> 
#include <osg/Geode> 

const char*const vertexShader=R"(
    #version 120 

    uniform vec2 screenSize; 

    vec4 roundCoords(vec4 clipPos) 
    { 
     vec2 halfScreenSize=screenSize/2.; 
     vec2 ndcPos=clipPos.xy/clipPos.w;   // transform to normalized device coordinates 
     vec2 screenPos=(ndcPos+1)*halfScreenSize; // transform from NDC space to screen space 
     vec2 screenPosRounded=floor(screenPos);  // round the screen coordinates 
     ndcPos=screenPosRounded.xy/halfScreenSize-1; // transform back to NDC space 
     clipPos.xy=ndcPos*clipPos.w;     // transform back to clip space 
     return clipPos; 
    } 

    void main() 
    { 
     gl_TexCoord[0]=gl_MultiTexCoord0; 
     gl_FrontColor=gl_Color; 

     vec4 translCol=gl_ModelViewProjectionMatrix[3]; 
     // Prevent rotation and unneeded scaling 
     mat4 mvp=mat4(vec4(2./screenSize.x, 0,  0,0), 
         vec4(  0, 2./screenSize.y,0,0), 
         vec4(  0,   0,  1,0), 
         vec4(translCol.xyz/translCol.w, 1)); 

     gl_Position=roundCoords(mvp*gl_Vertex); 
    } 
)"; 

static constexpr int windowWidth=800, windowHeight=600; 

osg::ref_ptr<osg::Node> createFixedSizeTexture(osg::Image *image,int W,int H) 
{ 
    osg::Vec3Array& verts = *new osg::Vec3Array(4); 
    verts[0] = osg::Vec3(-W/2., -H/2., 0); 
    verts[1] = osg::Vec3(+W/2., -H/2., 0); 
    verts[2] = osg::Vec3(+W/2., +H/2., 0); 
    verts[3] = osg::Vec3(-W/2., +H/2., 0); 

    osg::Vec2Array& texcoords = *new osg::Vec2Array(4); 
    texcoords[0].set(0,0); 
    texcoords[1].set(1,0); 
    texcoords[2].set(1,1); 
    texcoords[3].set(0,1); 

    osg::Geometry*const geometry = new osg::Geometry; 
    geometry->setVertexArray(&verts); 
    geometry->setTexCoordArray(0, &texcoords); 
    geometry->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4)); 

    osg::Texture2D*const texture = new osg::Texture2D(image); 
    texture->setResizeNonPowerOfTwoHint(false); 

    geometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); 

    osg::Geode*const geode = new osg::Geode; 
    geode->addDrawable(geometry); 

    osg::Program*const program = new osg::Program; 
    program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShader)); 

    osg::StateSet*const set = geode->getOrCreateStateSet(); 
    set->setAttributeAndModes(program, osg::StateAttribute::ON); 
    set->addUniform(new osg::Uniform("screenSize" , osg::Vec2(windowWidth,windowHeight))); 

    return geode; 
} 

int main() 
{ 
    static constexpr int W=21, H=15; 
    unsigned bits[W*H]; 
    for(int x=0;x<W;++x) 
     for(int y=0;y<H;++y) 
      bits[x+W*y] = (x&y&1)*0xffffffff; 

    osg::Image *formImage = new osg::Image; 
    formImage->setImage(W, H, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, 
         reinterpret_cast<unsigned char*>(bits), osg::Image::NO_DELETE); 

    osgViewer::Viewer viewer; 
    viewer.setUpViewInWindow(0, 0, windowWidth, windowHeight); 
    viewer.setSceneData(createFixedSizeTexture(formImage,W,H)); 

    return viewer.run(); 
}