Как правильно рисовать мои 3D-объекты с помощью шейдеров? - PullRequest
1 голос
/ 10 января 2011

У меня есть файл OBJ & MTL, экспортированный из 3DS Max, который является полным набором шахмат. В своем конечном результате я хотел бы иметь возможность выбрать игровой фрагмент, а затем выбрать квадрат, чтобы переместить его тоже. Элементы, с которыми у меня возникают проблемы при соединении:

  • Выбор объекта
  • шейдеры

У меня импортер объектов работает двумя способами.

1) Сгруппируйте все вместе с подобными материалами в структуру, называемую Mesh, и переберите все model.meshes, отрисовывая каждый кадр.

2) Определите игровое поле, каждый квадрат и каждый игровой элемент и поместите соответствующие вершины, материал и т. Д. В структуру под названием GroupObject. Они помещены в model.objects, который я перебираю, рисуя каждый кадр.

Вот скриншот того, как выглядит каждая опция, описанная в # 1 и # 2. В верхней половине SS я просто вытягиваю сетки, и все штриховки выглядят правильно, но ничего нельзя выбрать. В нижней половине я могу просто выбрать игровую фигуру или квадрат, но модель выглядит как дерьмо.

http://img815.imageshack.us/img815/2158/chesst.png

Кроме того, если я использую шейдер с кодом из # 2, панорамирование и масштабирование замедляются до сканирования. Это почти полностью не отвечает.

Вот метод, который вызывается для рисования объектов в каждом кадре. Первые 2 прокомментированные строки - это то, где я пробую вариант 1 и просто нарисую свою структуру Mesh, и это выглядит хорошо Поворот и масштабирование также плавные, но я не могу выбрать объект, потому что я не могу сделать glPushName для Mesh. В данный момент код настраивается циклически по каждому model.objects, поэтому я могу запустить glPushName( (int)object );, который необходим для выбора / выбора игрового элемента или квадрата. В закомментированном разделе я пытаюсь применить шейдер, который работает очень медленно при цикле по model.objects (без замедления при цикле model.mesh)

 glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

//for (int i = 0; i < model.getNumberOfMeshes(); ++i)
//{
for ( int i = 0; i < (int)model.objects.size(); i++ )
{
    ModelOBJ::GroupObject *object = model.objects[i];

    glPushName( (int)object );

    int faceSize = (int)object->faces.size();

    for ( int j = 0; j < faceSize; j++ )
    {

        ModelOBJ::Face *face = object->faces[j];
        pMaterial = &model.getMaterial( face->materialId );


        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (GLfloat *)pMaterial->ambient);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (GLfloat *)pMaterial->diffuse);
        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (GLfloat *)pMaterial->specular);
        glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, pMaterial->shininess * 128.0f);

        glDisable(GL_TEXTURE_2D);
        drawFace( *face );

        //if (pMaterial->bumpMapFilename.empty())
        //{
            // Per fragment Blinn-Phong code path.

        //  glUseProgram(blinnPhongShader);

        //  // Bind the color map texture.

        //  texture = nullTexture;

        //  if (enableTextures)
        //  {
        //      iter = modelTextures.find(pMaterial->colorMapFilename);

        //      if (iter != modelTextures.end())
        //          texture = iter->second;
        //  }

        //  glActiveTexture(GL_TEXTURE0);
        //  glEnable(GL_TEXTURE_2D);
        //  glBindTexture(GL_TEXTURE_2D, texture);

        //  // Update shader parameters.

        //  glUniform1i(glGetUniformLocation(
        //      blinnPhongShader, "colorMap"), 0);
        //  glUniform1f(glGetUniformLocation(
        //      blinnPhongShader, "materialAlpha"), pMaterial->alpha);
        //}        
    }
    glPopName();
}

glBindTexture(GL_TEXTURE_2D, 0);
glUseProgram(0);
glDisable(GL_BLEND);

Вот метод drawFace, если он уместен

void GLEngine::drawFace(ModelOBJ::Face &face)
{
if ( (int)face.numVertices <= 3 )
    glBegin(GL_TRIANGLES);
else 
    glBegin(GL_POLYGON);

for ( int v = 0; v < (int)face.numVertices; v++ )
{
    if ( (int)face.numUVWs > v && face.UVWs != NULL )
        glTexCoord2f(face.UVWs[v]->x, face.UVWs[v]->y);

    if ( (int)face.numNormals > v && face.normals != NULL )
        glTexCoord3d(face.normals[v]->x, face.normals[v]->y, face.normals[v]->z);

    if ( (int)face.numVertices > v && face.vertices != NULL )
        glVertex3f(face.vertices[v]->x, face.vertices[v]->y, face.vertices[v]->z);
}
glEnd();
}

А вот шейдер, который я использую

Per-fragment Blinn-Phong shader for a single directional light source.

[vert]


varying vec3 normal;

void main()
{
    normal = normalize(gl_NormalMatrix * gl_Normal);

    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    gl_TexCoord[0] = gl_MultiTexCoord0;    
}

[frag]


uniform sampler2D colorMap;
uniform float materialAlpha;

varying vec3 normal;

void main()
{   
    vec3 n = normalize(normal);

    float nDotL = max(0.0, dot(n, gl_LightSource[0].position.xyz));
    float nDotH = max(0.0, dot(normal, vec3(gl_LightSource[0].halfVector)));
    float power = (nDotL == 0.0) ? 0.0 : pow(nDotH, gl_FrontMaterial.shininess);

    vec4 ambient = gl_FrontLightProduct[0].ambient;
    vec4 diffuse = gl_FrontLightProduct[0].diffuse * nDotL;
    vec4 specular = gl_FrontLightProduct[0].specular * power;
    vec4 color = gl_FrontLightModelProduct.sceneColor + ambient + diffuse + specular;

    gl_FragColor = color * texture2D(colorMap, gl_TexCoord[0].st);
    gl_FragColor.a = materialAlpha;
}

Как бы вы объединили все эти функции вместе? Моя первая мысль - нарисовать все model.objects без информации о материале и сделать их прозрачными. Затем пропустите второй цикл и нарисуйте все model.meshes в комплекте с материалом и используя шейдер. Но потом я подумал, когда я начну перемещать игровые фигуры на новую клетку, как я буду следить за тем, чтобы к новой позиции фигуры применялась правильная заливка. Когда я выберу прозрачный GroupObject и переведу его на новый квадрат, будет ли фигура иметь правильную штриховку?

Как лучше всего решить мою проблему?

1 Ответ

1 голос
/ 12 января 2011

Почему вы отправляете нормаль в качестве координаты текстуры в GLEngine::drawFace:

glTexCoord3d(face.normals[v]->x, face.normals[v]->y, face.normals[v]->z);

Вы ожидаете, что шейдер будет glNormal3d, как вы можете видеть здесь:

normal = normalize(gl_NormalMatrix * gl_Normal);
...