سؤال

مرحبًا ، أنا أكتب تطبيق النمذجة ثلاثية الأبعاد وأريد تسريع تقديم في OpenGL. حاليا أنا أستخدم glbegin/glend وهو طريقة بطيئة حقًا ومهملة. أحتاج إلى رسم نماذج مظللة مسطحة للغاية. أقوم بإنشاء القواعد الطبيعية على وحدة المعالجة المركزية في كل إطار واحد. هذا بطيء جدا. حاولت استخدام gldrawelements مع هندسة مفهرسة ، ولكن هناك مشكلة في الجيل الطبيعي ، لأن القواعد الطبيعية محددة في Vertex وليس على مستوى المثلث.
كانت هناك فكرة أخرى هي استخدام GLSL لتوليد القواعد الطبيعية على GPU في Shader Geometry. لقد كتبت هذا الرمز للجيل العادي:

#version 120 
#extension GL_EXT_geometry_shader4 : enable

vec3 NormalFromTriangleVertices(vec3 triangleVertices[3])
{
    // now is same as RedBook (OpenGL Programming Guide)
    vec3 u = triangleVertices[0] - triangleVertices[1];
    vec3 v = triangleVertices[1] - triangleVertices[2];
    return cross(v, u);
}

void main()
{
    // no change of position
    // computes normal from input triangle and front color for that triangle

    vec3 triangleVertices[3];
    vec3 computedNormal;

    vec3 normal, lightDir;
    vec4 diffuse;
    float NdotL;

    vec4 finalColor;

    for(int i = 0; i < gl_VerticesIn; i += 3)
    {
        for (int j = 0; j < 3; j++)
        {
            triangleVertices[j] = gl_PositionIn[i + j].xyz;
        }
        computedNormal = NormalFromTriangleVertices(triangleVertices);
        normal = normalize(gl_NormalMatrix * computedNormal);

        // hardcoded light direction 
        vec4 light = gl_ModelViewMatrix * vec4(0.0, 0.0, 1.0, 0.0);
        lightDir = normalize(light.xyz);

        NdotL = max(dot(normal, lightDir), 0.0);

        // hardcoded
        diffuse = vec4(0.5, 0.5, 0.9, 1.0);

        finalColor = NdotL * diffuse; 
        finalColor.a = 1.0; // final color ignores everything, except lighting

        for (int j = 0; j < 3; j++)
        { 
            gl_FrontColor = finalColor;
            gl_Position = gl_PositionIn[i + j];
            EmitVertex();
        }
    }
    EndPrimitive();
}

عندما قمت بدمج التظليلات على طلبي ، لم يحدث أي تحسين للسرعة. كان أسوأ من ذي قبل. أنا مبتدئ في GLSL والتظليل بشكل عام ، لذا لا أعرف ما الذي ارتكبته خطأ. جربت هذا الرمز على MacBook مع Geforce 9400m.

لكي أكون أكثر وضوحًا ، هذا رمز أريد استبداله:

- (void)drawAsCommandsWithScale:(Vector3D)scale
{
    float frontDiffuse[4] = { 0.4, 0.4, 0.4, 1 };
    CGFloat components[4];
    [color getComponents:components];
    float backDiffuse[4];
    float selectedDiffuse[4] = { 1.0f, 0.0f, 0.0f, 1 };

    for (uint i = 0; i < 4; i++)
        backDiffuse[i] = components[i];

    glMaterialfv(GL_BACK, GL_DIFFUSE, backDiffuse);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, frontDiffuse);

    Vector3D triangleVertices[3];

    float *lastDiffuse = frontDiffuse; 

    BOOL flip = scale.x < 0.0f || scale.y < 0.0f || scale.z < 0.0f;

    glBegin(GL_TRIANGLES);

    for (uint i = 0; i < triangles->size(); i++)
    {
        if (selectionMode == MeshSelectionModeTriangles) 
        {
            if (selected->at(i))
            {
                if (lastDiffuse == frontDiffuse)
                {
                    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, selectedDiffuse);
                    lastDiffuse = selectedDiffuse;
                }
            }
            else if (lastDiffuse == selectedDiffuse)
            {
                glMaterialfv(GL_BACK, GL_DIFFUSE, backDiffuse);
                glMaterialfv(GL_FRONT, GL_DIFFUSE, frontDiffuse);
                lastDiffuse = frontDiffuse;
            }
        }    
        Triangle currentTriangle = [self triangleAtIndex:i];
        if (flip)
            currentTriangle = FlipTriangle(currentTriangle);

        [self getTriangleVertices:triangleVertices fromTriangle:currentTriangle];
        for (uint j = 0; j < 3; j++)
        {
            for (uint k = 0; k < 3; k++)
            {
                triangleVertices[j][k] *= scale[k];
            }
        }
        Vector3D n = NormalFromTriangleVertices(triangleVertices);
        n.Normalize();
        for (uint j = 0; j < 3; j++)
        {
            glNormal3f(n.x, n.y, n.z);
            glVertex3f(triangleVertices[j].x, triangleVertices[j].y, triangleVertices[j].z);            
        }
    }

    glEnd();    
}

كما ترون أنه غير فعال للغاية ، ولكن العمل.triangles مجموعة من الفهارس في vertices مجموعة مصفوفة.

حاولت استخدام هذا الرمز للرسم ، لكن لا يمكنني الحصول على صفيف فهرس واحد فقط ليسان (واحد للرؤوس والثانية للـ Normalts).

glEnableClientState(GL_VERTEX_ARRAY);

uint *trianglePtr = (uint *)(&(*triangles)[0]); 
float *vertexPtr = (float *)(&(*vertices)[0]);

glVertexPointer(3, GL_FLOAT, 0, vertexPtr);
glDrawElements(GL_TRIANGLES, triangles->size() * 3, GL_UNSIGNED_INT, trianglePtr);
glDisableClientState(GL_VERTEX_ARRAY);

الآن ، كيف يمكنني تحديد المؤشر إلى القواعد الطبيعية ، عندما تتم مشاركة بعض القمم بواسطة مثلثات مختلفة ، مثل هذه القواعد الطبيعية المختلفة بالنسبة لهم؟

هل كانت مفيدة؟

المحلول

لذلك تمكنت أخيرًا من زيادة سرعة العرض. أقوم بإعادة حساب القواعد الطبيعية على وحدة المعالجة المركزية ، فقط عندما تتغير القمم أو المثلثات ، والتي تحدث فقط عند العمل في شبكة واحدة وليس في المشهد بأكمله. إنه ليس حلًا أردت ولكن في العالم الحقيقي هو أفضل من الأساليب السابقة.
أقوم بتخزين الهندسة الكاملة في مجموعة منفصلة وطبيعية وقامة ، لا يمكن استخدام الرسم المفهرس لأنني أريد تظليلًا مسطحًا (مشكلة مماثلة لمجموعات التجانس في 3DS Max).
أنا استخدم بسيط glDrawArrays وبالنسبة لإضاءة تظليل قمة الإضاءة ، فذلك لأنني أريد في وضع Triangle لونًا مختلفًا للمثلث المحدد وأخرى لم يتم تحديدها ولا توجد مجموعة من المواد (لم أجد أيًا).

نصائح أخرى

لن تقوم عادة بحساب القواعد الطبيعية في كل إطار ، فقط عندما يتغير الهندسة. وللحصول على واحد عادي لكل مثلث فقط قم بتعيين نفس المعدل الطبيعي لكل قمة في المثلث. هذا يعني أنه لا يمكنك مشاركة القمم بين المثلثات المجاورة في شبكةك ، لكن هذا ليس غير عادي على الإطلاق في هذا النوع من الأشياء.

سؤالك يجعلني أتذكر هذا العواصم بدون طيبة مشاركة مدونة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top