Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Problem with deforming  (Read 4435 times)

0 Members and 1 Guest are viewing this topic.

TurboLento

  • Newbie
  • *
  • Posts: 9
    • View Profile
    • http://pjmendes.blogspot.com/
Problem with deforming
« on: July 22, 2010, 04:27:57 am »
First of all, this is mostly an OpenGL question, but since my OpenGL knowledge isn't very extensive, my searches aren't being fruitful in solving the problem, and that my issue may be related to some specific code in SFML, I'm posing it here.

I'm trying to extend a Sprite to allow for Mode-7 (http://en.wikipedia.org/wiki/Mode_7) rendering.

I have decided to attempt to inherit from Sprite and overload Render().

Initially, I just want to deform the sprite in a way that the upper edge is smaller than the lower ("scaling" the sprite's upper edge). To do this, I'm simply changing the coordinates for the sprite's top vertices, in the followin manner:

(in Sprite::Render, replacing the OpenGL rendering part with:)
Code: [Select]

glBegin(GL_QUADS);
            glTexCoord2f(Rect.Left,  Rect.Top);    glVertex2f(Width * 0.25f,     0);
            glTexCoord2f(Rect.Left,  Rect.Bottom); glVertex2f(0,     Height);
            glTexCoord2f(Rect.Right, Rect.Bottom); glVertex2f(Width, Height);
            glTexCoord2f(Rect.Right, Rect.Top);    glVertex2f(Width - (Width * 0.25f), 0) ;


The resulting image has a weird deformation along the line where the polygons meet, not mapping the texture smoothly along the deformed quad.

Original image:


Result image:


What I intended image (mockup):


Can anyone point me towards some info? Sorry if it's offensive to be this off-topic
Game development blog: http://pjmendes.blogspot.com/

TurboLento

  • Newbie
  • *
  • Posts: 9
    • View Profile
    • http://pjmendes.blogspot.com/
Problem with deforming
« Reply #1 on: July 23, 2010, 09:05:18 pm »
Ok, I figured it out. It had to do with the texture mapping, it could not be done using glTexCoords2* but had to include the "q" coordinate (thus, the use of glTexCoords4* was necessary). It had to do with mapping the texture to a trapezoidal quad, which causes the undesired effect.

I've implemented a Sprite which allows the definition of a few parameters to emulate Mode-7 (simulated perspective), by shrinking the top or bottom edge of the sprite and mapping the texture accordingly.



Commented code is below, along with the pages which helped me figure out what the problem was, the solution, and how to calculate that damned q coord.

Code: [Select]

#ifndef SPRITEMODE7_H_INCLUDED
#define SPRITEMODE7_H_INCLUDED

#include <SFML/Graphics/Sprite.hpp>

using namespace sf;

class SpriteMode7 : public Sprite
{
    public:
        SpriteMode7():
        Sprite()
        {
            //this->displacementTop = 200.0f;
            this->displacementTop = 0.0f;
            this->displacementBottom = 0.0f;
            this->depthTop = 3.0f;
            this->depthBottom = 1.0f;
            this->scaleVerticalRatio = 1.0f;
        }

        void displacementTopSet(float newDisplacementTop)
        {
            this->displacementTop = newDisplacementTop;
        }

        float displacementTopGet()
        {
            return this->displacementTop;
        }

        void displacementBottomSet(float newDisplacementBottom)
        {
            this->displacementBottom = newDisplacementBottom;
        }

        float displacementBottomGet()
        {
            return this->displacementBottom;
        }

        void depthTopSet(float newDepthTop)
        {
            this->depthTop = newDepthTop;
        }

        float depthTopGet()
        {
            return this->depthTop;
        }

        void depthBottomSet(float newDepthBottom)
        {
            this->depthBottom = newDepthBottom;
        }

        float depthBottomGet()
        {
            return this->depthBottom;
        }

        void Render(RenderTarget& rt) const
        {
            //std::cout << "Sprite::Render()\n";
            IntRect _mySubRect = GetSubRect();

            // Get the sprite size
            float Width  = static_cast<float>(_mySubRect.GetWidth());
            float Height = static_cast<float>(_mySubRect.GetHeight());

            // Check if the image is valid
            const Image* _myImage = GetImage();
            if (_myImage && (_myImage->GetWidth() > 0) && (_myImage->GetHeight() > 0))
            {
                // Use the "offset trick" to get pixel-perfect rendering
                // see http://www.opengl.org/resources/faq/technical/transformations.htm#tran0030
                glTranslatef(0.375f, 0.375f, 0.f);

                // Bind the texture
                _myImage->Bind();

                // Calculate the texture coordinates
                FloatRect TexCoords = _myImage->GetTexCoords(_mySubRect);
                /*
                FloatRect Rect(myIsFlippedX ? TexCoords.Right  : TexCoords.Left,
                               myIsFlippedY ? TexCoords.Bottom : TexCoords.Top,
                               myIsFlippedX ? TexCoords.Left   : TexCoords.Right,
                               myIsFlippedY ? TexCoords.Top    : TexCoords.Bottom);
                */
                FloatRect Rect(TexCoords.Left,
                               TexCoords.Top,
                               TexCoords.Right,
                               TexCoords.Bottom);

                // Draw the sprite's triangles
                //glBegin(GL_QUADS);
                glBegin(GL_TRIANGLES);

                    // For the sprite to be displayed correctly (with correct texture mapping, no visible seam in the middle where
                    // the two triangles meet) and appearing with perspective (texture along the furthest edge is "smaller"),
                    // must emulate perspective projection of the texture, using the q coordinate and glTexCoord4f.
                    //
                    // http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Board=2&Number=229833
                    // http://glprogramming.com/red/chapter09.html
                    // http://www.xyzw.us/~cass/qcoord/
                    // http://www.idevgames.com/forums/thread-7430.html
                    // http://www.gamedev.net/community/forums/topic.asp?topic_id=419296
                    //
                    // Details:
                    // - it is best to define the vertices in an order where the "furthest" texture coordinates are in the same line
                    // - using GL_TRIANGLES, could not make it work with GL_QUADS
                    // - it is important that the invW calculation aligns precisely with the ratio we are shrinking an edge, or the texture
                    //      won't line up in the middle; e.g. if an edge is to have 0.5 it's original length, it's z depth should be 2, so that invW = 0.5

                    float invWTop = 1.0f / depthTop;
                    float invWBottom = 1.0f / depthBottom;
                    float edgeMiddle = Width * 0.5f;
                    float edgeScaleTop = edgeMiddle / depthTop; //(Width / (depthTop * 2.0f);
                    float edgeScaleBottom = edgeMiddle / depthBottom; //(Width / (depthBottom * 2.0f);

                    glTexCoord4f(invWTop, 0, 0, invWTop);
                    glVertex2f(edgeMiddle + edgeScaleTop + displacementTop, 0);

                    glTexCoord4f(0, 0, 0, invWTop);
                    glVertex2f(edgeMiddle - edgeScaleTop + displacementTop, 0);

                    glTexCoord4f(0,  invWBottom, 0, invWBottom);
                    glVertex2f(edgeMiddle - edgeScaleBottom + displacementBottom, Height * scaleVerticalRatio);

        //////
        ////// TRI 2
        //////
                    glTexCoord4f(invWTop, 0, 0, invWTop);
                    glVertex2f(edgeMiddle + edgeScaleTop + displacementTop, 0);

                    glTexCoord4f(0, invWBottom, 0, invWBottom);
                    glVertex2f(edgeMiddle - edgeScaleBottom + displacementBottom, Height * scaleVerticalRatio);

                    glTexCoord4f(invWBottom, invWBottom, 0, invWBottom);
                    glVertex2f(edgeMiddle + edgeScaleBottom + displacementBottom, Height * scaleVerticalRatio);

                glEnd();
            }
            else
            {
                // Disable texturing
                glDisable(GL_TEXTURE_2D);

                // Draw the sprite's triangles
                glBegin(GL_QUADS);
                    glVertex2f(0,     0);
                    glVertex2f(0,     Height);
                    glVertex2f(Width, Height);
                    glVertex2f(Width, 0);
                glEnd();
            }
        }

    private:
        float   depthTop, // z depth of sprite's top edge
                depthBottom,    // z depth of sprite's bottom edge
                displacementTop,    // number of pixels to horizontally displace this sprite's top edge
                displacementBottom, // number of pixels to horizontally displace this sprite's bottom edge
                scaleVerticalRatio;  // scale to vertically apply to sprite, to achieve a better perspective effect
};

#endif // SPRITEMODE7_H_INCLUDED
Game development blog: http://pjmendes.blogspot.com/