渲染openGL纹理:类函数导致渲染失败

Posted

技术标签:

【中文标题】渲染openGL纹理:类函数导致渲染失败【英文标题】:Rendering openGL texture: Class function causes rendering to fail 【发布时间】:2013-06-22 23:28:38 【问题描述】:

我正在开发一个菜单系统,该系统允许我将“父级”应用于对象。我有一个呈现字体的CLabel 类。我有一个CEditBox 类,它有一个指向基础CControl 类的指针,它们都是其中的一部分。然后我声明一个指向CControl 对象的指针,并将它指向CEditBox 的构造函数中的CLabel

据我所知,这一切都设置正确。我为什么这么说?这个函数:

void CControl::RenderChildren() 
    for( int i = 0; i < Children.size(); i++ ) 


        //Children[i]->X(Children[i]->X()+_X); //offset child _X with parent's _X
        //Children[i]->Y(Children[i]->Y()+_Y); //offset child _Y with parent's _Y

        Children[i]->OnRender();
    

将渲染编辑框,它将渲染带有标签偏移量的标签(_X,_Y 它们是CControl 的成员)。由于它们位于 0,0,它会在左上角呈现文本。

现在,如果我取消注释这两行并使用以下函数,则文本不会呈现。

void CControl::RenderChildren() 
    for( int i = 0; i < Children.size(); i++ ) 


        Children[i]->X(Children[i]->X()+_X); //offset child _X with parent's _X
        Children[i]->Y(Children[i]->Y()+_Y); //offset child _Y with parent's _Y

        Children[i]->OnRender();
    

我使用exit(variable) 调用来专门测试这些值,并且可以告诉您几件事。 _X 和 _Y 正在为孩子正确设置。父级在所需位置呈现,因此不会影响父级的 _X,_Y 值。

接下来看看我调用的函数:

void CControl::X(int x)                                            
    //      Set Component's X coordinate
    _X = x;
    //if(Pappy != NULL)  
    //  _X = _X + Pappy->X(); 
    //


void CControl::Y(int y)                                            
    //      Set Component's Y coordinate
    _Y = y;
    //if(Pappy != NULL) 
    //  _Y = _Y + Pappy->Y();
    //

不要介意注释掉的行,那些是因为我要检查它是否是某物的子对象并修改 _X 和 _Y 函数中的偏移量,但意识到不用担心可能更有效关于它,并且只在渲染孩子时应用偏移量(因此我上面的原始函数)。简单地说,这些函数只是将传递的整数设置为当前偏移量。

然后是函数的读取版本:

int CControl::X()                                              
    //      Get Component's X coordinate
    //if(Pappy != NULL) return _X - Pappy->X();
    return _X;


int CControl::Y()                                              
    //      Get Component's Y coordinate
    //if(Pappy != NULL) return _Y - Pappy->Y();
    return _Y;

也只是返回值,我不知道这两行是怎么回事

    Children[i]->X(Children[i]->X()+_X); //offset child _X with parent's _X
    Children[i]->Y(Children[i]->Y()+_Y); //offset child _Y with parent's _Y

导致渲染失败。

查看我的CLabel::OnRender() 函数,我也无法检测到问题。

void CLabel::OnRender() 

    if(Visible) 
        SDL_Surface* Surf_Text; 
        Surf_Text = Font.BlendedUTF8Surface();
        Text_Font.OnLoad(Surf_Text);
        Text_Font.RenderQuad(_X,_Y);
        SDL_FreeSurface(Surf_Text);
    

我知道代码正在这里输入。我在if 语句中使用了exit(variable)。我已经测试了Surf_Text-&gt;wSurf_Text-&gt;h 并且知道文本正在呈现,因为在有或没有偏移线的情况下,SDL_Surface 值没有区别,它在一种情况下呈现,但在另一种情况下不呈现。此外,我在这个函数中测试了 _X 和 _Y 只是为了验证它们确实在正确的位置呈现。他们是。

这意味着渲染顺序可能有问题,但在此函数中,如果我将 Text_Font.RenderQuad(_X,_Y); 替换为 Text_Font.RenderQuad(_X+dX,_Y+dY); 其中 dX 和 dY 只是应用父偏移后应为的整数值,则文本渲染得很好。所以我能想到的一切,我都测试过了。我无法弄清楚为什么这两条偏移线会终止渲染。

    Children[i]->X(Children[i]->X()+_X); //offset child _X with parent's _X
    Children[i]->Y(Children[i]->Y()+_Y); //offset child _Y with parent's _Y

[已解决]

是的。去想了一分钟。

第 1 帧)

Children[i]->X(Children[i]->X()+_X) // will be 100 and exit correctly.

第 2 帧)

Children[i]->X(Children[i]->X()+_X) // will be 200 if I don't add the exit

等等……

做我的功能:

void CControl::RenderChildren() 
    for( int i = 0; i < Children.size(); i++ ) 


        Children[i]->X(Children[i]->X()+_X); //offset child _X with parent's _X
        Children[i]->Y(Children[i]->Y()+_Y); //offset child _Y with parent's _Y

        Children[i]->OnRender();

        Children[i]->X(Children[i]->X()-_X);
        Children[i]->Y(Children[i]->Y()-_Y);
    

完美呈现。希望我没有浪费任何人的时间。

[解决方案 2]

阅读所选答案后,我选择重写函数以在渲染期间应用偏移量。我只是在渲染孩子之前计算偏移量,如下所示:

void CControl::RenderChildren() 
    for( int i = 0; i < Children.size(); i++ ) 

        int xOff, yOff;
        xOff = yOff = 0;                                //Initialize offsets

        CControl * Kin = this;                          //Pointer to current parent
        while( Kin != NULL )                           //Until there is no more parent container repeat
            xOff = Kin->X() + xOff;                     //Add X of Parent to the current X offset total.
            yOff = Kin->Y() + yOff;                     //Add Y of Parent to the current Y offset total.
            Kin = Kin->GetParent();                     //Get next parent.  
        

        Children[i]->OnRender(xOff,yOff);               //Render based on parental induced offset location

    

【问题讨论】:

【参考方案1】:

我确实在一秒钟内看到了你的错误。所以你没有浪费任何人的时间(除了你自己的;))。无论如何都这样做:

void CControl::RenderChildren() 
    for( int i = 0; i < Children.size(); i++ ) 


        Children[i]->X(Children[i]->X()+_X); //offset child _X with parent's _X
        Children[i]->Y(Children[i]->Y()+_Y); //offset child _Y with parent's _Y

        Children[i]->OnRender();

        Children[i]->X(Children[i]->X()-_X);
        Children[i]->Y(Children[i]->Y()-_Y);
    

不是最优的。在您的情况下,您正在使用遇到任何问题的整数。 但是说有一次你决定使用浮点数

问题是,浮点数上发生的每个操作都会产生舍入误差。迭代地进行(如您的情况)可能会将数字收敛到一个稳定的点,或者它可能会稍微发散。作为一般规则,您应该最小化单个浮点数“流动”的操作。从数学上讲,您的序言和后序可能看起来像彼此的精确倒数。实际上在精度有限的计算机上它们不是。

长话短说:

您应该稍微更改CControl::OnRender 以将偏移量作为参数,以便在渲染时原位应用偏移量添加。不要介意额外的工作。如果这确实是一个问题,请使用分析器来确定真正的瓶颈。不要在设计界面时考虑到某些关于性能的“想法”。过早的优化就是这样,不好。


顺便说一句:在 *** 上,标记自我解决问题的规范方法是将您自己的解决方案写入您自己问题的答案中,然后将其标记为已接受。

【讨论】:

嗨,Datenwolf。感谢您的回复。很快,感谢您提供有关如何回答我自己的问题的说明。我在这里还是比较新的。你提出了一个很棒的观点。所以本质上,由于舍入,每个周期最终可能会导致 _X 或 _Y 发生净变化,因此组件最终会滑出屏幕(或者如果出现一些循环舍入问题,在屏幕上会稍微振荡。)典型地说,像素通常作为浮点数处理吗?似乎 int 将是像素坐标的更好选择(更少的内存),但我在图形方面的正式培训很少。 好吧,我猜就内存而言它们是相同的,但我一直认为整数的计算成本较低。 @Chemistpp:像素通常只是内存的线性寻址部分中的元素(之间偶尔会有对齐间隙,具体取决于窗口大小和像素格式)。所以像素地址总是整数。然而,像素本身可能是浮点值。至于浮动坐标的行为:是的,它们可能会摆动或慢慢滑出视口。 好的,修正了我的算法。我猜在大多数情况下应该会更好。

以上是关于渲染openGL纹理:类函数导致渲染失败的主要内容,如果未能解决你的问题,请参考以下文章

我的OpenGL学习进阶之旅关于OpenGL ES 绘制纹理,因为加载纹理坐标设置错误,导致纹理无法渲染的问题

openGL FBO 复制到纹理导致黑色/深色图像

OpenGL渲染到纹理透明度问题

opengl vbo 纹理

OpenGL - 纹理加载不正确

opengl vbo建议[关闭]