【问题标题】:GPU skinning issue with GLSLGLSL 的 GPU 蒙皮问题
【发布时间】:2013-06-30 14:24:22
【问题描述】:

我已经使用 openGL 工作了几个月,现在只是自学。现在我已经开始渲染位置、纹理坐标模型了

我正在尝试使用动画模型,我将在显卡上执行动画蒙皮过程。

顺便说一句,如果有人想一对一地帮助我,请告诉我,我不介意更直接的方法。

这是我的顶点格式

struct VERTEX_ANIMATED
{
    float3 position;
    float3 normal;
    float2 texCoord;
    float weights[4];
    unsigned boneIndices[4];
};

这就是我将顶点添加到 gpu 缓冲区句柄的方式(这些函数中的任何未初始化变量都位于 ".h" 中)

bool CVertexBuffer::IncreaseVerts( const unsigned int uiNumVerts )
{
    //create our increase by value
    unsigned uiIncrement = (uiNumVerts / BUFFER_INCREASE_SIZE) * BUFFER_INCREASE_SIZE + BUFFER_INCREASE_SIZE;
    m_uiNumVerts += uiIncrement;

    //bind to our buffer
    void* buffer1; 
    if (GLEW_ARB_vertex_shader)
    {
        glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_uiVertBufferHandle );

        //make sure our buffer exists
        buffer1 = glMapBufferARB( GL_ARRAY_BUFFER_ARB, GL_READ_WRITE );
    }
    else
    {
        glBindBuffer( GL_ARRAY_BUFFER, m_uiVertBufferHandle );

        //make sure our buffer exists
        buffer1 = glMapBuffer( GL_ARRAY_BUFFER, GL_READ_WRITE );
    }

    if( buffer1 )
    {
        //collection of all our data
        void* buffer2 = new char[ (m_uiNumVerts)*sizeof(VertexFormat) ];
        memset( buffer2, 0, (m_uiNumVerts)*sizeof(VertexFormat) );
        memcpy( buffer2, buffer1, (m_uiNumVerts - uiIncrement)*sizeof(VertexFormat)     );

        //create a new buffer
        //unsigned uiNewHandle;

        if (GLEW_ARB_vertex_shader)
        {
            //allocate our new storage space, and store our data in there
            glBufferDataARB( GL_ARRAY_BUFFER_ARB, (m_uiNumVerts*sizeof(VertexFormat)), buffer2, GL_DYNAMIC_READ );

            //lock our buffer
            //void* buffer2 = glMapBuffer( GL_ARRAY_BUFFER_ARB, GL_READ_WRITE );    

            //unlock our buffer2
            //if( glUnmapBufferARB( GL_ARRAY_BUFFER_ARB ) == GL_FALSE )
            //  return false;
            //}

            //reset what we are bound to
            glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
        }
        else
        {
            //allocate our new storage space, and store our data in there
            glBufferDataARB( GL_ARRAY_BUFFER_ARB, (m_uiNumVerts*sizeof(VertexFormat)), buffer2, GL_DYNAMIC_READ );

            //reset what we are bound to
            glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
        }

        //delete our buffer
        free( buffer2 );

        //Unmap our currently mapped buffer
        glUnmapBuffer( GL_ARRAY_BUFFER );

    return true;
}

unsigned int CVertexBuffer::AddVerts(const VERTEX_ANIMATED* pVerts, unsigned int iNumVerts)
{
    //Save the location to copy to
    unsigned int uiVertLocation = m_uiVertsUsed;

    m_uiVertsUsed += iNumVerts;

    if(m_uiVertsUsed > m_uiNumVerts)
    {
        IncreaseVerts(m_uiVertsUsed - m_uiNumVerts);
    }

    if(GLEW_ARB_vertex_program)
    {
        //bind the buffer we're gonna mess with
        glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_uiVertBufferHandle );

        //get the pointer position where we can add verts
        void* pPositionBuffer = glMapBufferARB( GL_ARRAY_BUFFER_ARB, GL_READ_WRITE     );

        //now copy into our memory spot
        //which we need to move to the right position
        memcpy( ((char*)pPositionBuffer) + ( uiVertLocation*sizeof(VertexFormat) ), pVerts, iNumVerts*sizeof(VertexFormat));

        //now stop mapping
        glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
    }
    else
    {
        //bind the buffer we're gonna mess with
        glBindBuffer( GL_ARRAY_BUFFER, m_uiVertBufferHandle );

        //get the pointer position where we can add verts
        void* pPositionBuffer = glMapBuffer( GL_ARRAY_BUFFER, GL_READ_WRITE );

        //now copy into our memory spot
        //which we need to move to the right position
        memcpy( ((char*)pPositionBuffer) + ( uiVertLocation*sizeof(VertexFormat) ), pVerts, iNumVerts*sizeof(VertexFormat));

        //now stop mapping
        glUnmapBuffer(GL_ARRAY_BUFFER);
    }

    return uiVertLocation;
}

我假设我的错误来自我如何初始化我的数据或我如何将我的数据传递给着色器。

这是对我的着色器程序创建的简单调用,它接受顶点着色器文件名和片段着色器文件名,然后是希望指定的主要变量的变量,例如“位置、法线、texCoords”

CreateProgram( "animTriangle.vp",
               "animTriangle.fp",
               5,
               VERTEX_ATTRIB, "vVertexPos",
               NORMAL_ATTRIB, "vVertexNormal",
               TEXTURE_COORD_ATTRIB0, "vTexCoord",
               COLOR_ATTRIB, "vBlendWeights",
               COLOR2_ATTRIB, "vBoneIndices" );

在这个函数中,我在创建和编译着色器程序后进行参数解析

 //make sure to use our program to setup our handles
glUseProgram( m_uiProgramHandle );

//start from this parameter
va_start( parseList, szFragmentShaderName );

//read in number of variables if any
uiNum = va_arg( parseList, unsigned );

//for loop through our attribute pairs
int enumType = 0;
for( unsigned x = 0; x < uiNum; ++x )
{
    //specify our attribute locations
    enumType = va_arg( parseList, int );
    char* name = va_arg( parseList, char* );
    glBindAttribLocation( m_uiProgramHandle, enumType, name );
}

//end our list parsing
va_end( parseList );

这是我的顶点着色器开头的变量列表

in vec3 vVertexPos;     // position
in vec3 vVertexNormal;  // normal
in vec2 vTexCoord;      // texture coordinate....
in vec4 vBlendWeights;  // the weights pull of the related bone
in ivec4 vBoneIndices;  // the indicators of which bones we are influenced by

这是我的顶点步幅

 //set which vertices we will be using
 glBindBuffer( GL_ARRAY_BUFFER, m_uiVertBufferHandle );

 //enable these vertex attributes
 glEnableVertexAttribArray( VERTEX_ATTRIB );
 glEnableVertexAttribArray( NORMAL_ATTRIB );
 glEnableVertexAttribArray( TEXTURE_COORD_ATTRIB0 );
 glEnableVertexAttribArray( COLOR_ATTRIB );
 glEnableVertexAttribArray( COLOR2_ATTRIB );

 //specify our vertex attribute
 glVertexAttribPointer( VERTEX_ATTRIB, 3, GL_FLOAT, GL_FALSE, sizeof( VERTEX_ANIMATED ), BUFFER_OFFSET(0) );

 //specify our normal attribute
 glVertexAttribPointer( NORMAL_ATTRIB, 3, GL_FLOAT, GL_FALSE, sizeof( VERTEX_ANIMATED ), BUFFER_OFFSET(12) );

 //specify our texture attribute
 glVertexAttribPointer( TEXTURE_COORD_ATTRIB0, 2, GL_FLOAT, GL_FALSE, sizeof( VERTEX_ANIMATED ), BUFFER_OFFSET(24) );

 //specify our bone weight attribute location
 glVertexAttribPointer( COLOR_ATTRIB, 4, GL_FLOAT, GL_FALSE, sizeof( VERTEX_ANIMATED ), BUFFER_OFFSET(32) );

 //specify our bone indice attribute location
 glVertexAttribPointer( COLOR2_ATTRIB, 4, GL_INT, GL_FALSE, sizeof( VERTEX_ANIMATED ), BUFFER_OFFSET(48) );

现在我可以很好地加载静态模型了。当我加载我的动画模型时,我得到了一半的模型或一半的模型,那一半缺少一些块。我以前使用过 DirectX,只有当 gpu 正确读取我的缓冲区时才遇到过这个问题。

如果你们想了解更多信息,请告诉我。我在这个奇怪的问题上待了将近 2 周,真的很想了解我的问题。

【问题讨论】:

  • 如何将骨骼矩阵传递给着色器?
  • 在着色器中看起来像这样 / uniform mat4 mAnimPose[40]; / 在 .cpp 中这是我传递它的方式 / glUniformMatrix4fv( glGetUniformLocation( pCurShader->GetShaderProgramHandle(), "mAnimPose" ), pCurBones.size(), GL_FALSE, (float*)(&pCurBones[0]) ); / 但目前在着色器中,我不只是使用它们来测试模型的其余部分,所以我基本上将顶点设置为仅乘以矩阵工作的模型视图投影矩阵,因为它是我在静态模型着色器中使用的
  • 对不起,我不擅长这个堆栈溢出注释代码语法 X_X
  • 好吧,我想那不是问题所在。您是否记得增加顶点属性的步幅/大小以考虑权重/索引?
  • 它不会让我添加那么多哈哈我已将其添加到底部的正常问题中

标签: opengl glsl shader gpu


【解决方案1】:

您似乎忘记在代码中初始化NORMAL_ATTRIB。您对CreateProgram (...) 的调用不包括在您的顶点着色器中NORMAL_ATTRIBvVertexNormal 的关联。

如果您的顶点着色器需要顶点法线用于动画目的,并且您没有将此顶点指针正确连接到适当的属性槽,那么结果将是未定义的。

同样,问题也可能是由于NORMAL_ATTRIB 别名为您的另一个属性,因为它未初始化。例如,顶点属性 0 通常是位置,如果您在这段代码中未初始化 NORMAL_ATTRIB,您可能会使用普通指针重新定义您的顶点位置指针。

【讨论】:

  • 我做了这一步,但我认为我的问题是我的 boneIndices 不正确我认为这可能是我的顶点步幅。你介意一对一看@Andon M. Coleman吗?因为我的骨骼在动画中很好,但我似乎无法正确连接皮肤
【解决方案2】:

我的整体问题原来与我的抽奖电话有关。我指定了要绘制的原始三角形的数量,而不是我的“三角形计数 * 3”的索引数量。

这可以解释为什么有些模型会出现但会被分块。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-06-16
    • 2017-05-31
    • 2011-03-15
    • 2011-04-10
    • 1970-01-01
    • 2010-12-27
    • 2020-03-21
    • 1970-01-01
    相关资源
    最近更新 更多