2012-01-06 43 views
9

Tôi đã học OpenGL vài ngày nay bằng cách làm theo một số hướng dẫn và viết mã một số thử nghiệm của riêng tôi. Nhưng có một điều tôi thực sự không hiểu điều này ngăn cản tôi tiếp tục. Tôi đã googling trong một vài giờ và không tìm thấy câu trả lời nào cho câu hỏi của tôi.Bộ đệm riêng biệt OpenGLES 2.0 cho các đỉnh, màu sắc và tọa độ kết cấu

Tôi nên chỉ định từng giá trị màu riêng biệt và tọa độ kết cấu cho từng đỉnh riêng lẻ ở đâu? Nếu những thuộc tính đó luôn luôn được liệt kê trong cùng một mảng (struct) làm vị trí đỉnh? Giống như vậy:

const Vertex Vertices[] = { 
    // Front 
    {{1, -1, 0}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}}, 
    {{1, 1, 0}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}}, 
    {{-1, 1, 0}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}}, 
    {{-1, -1, 0}, {0, 0, 0, 1}, {0, 0}}, 

    ... 

Hoặc có cách nào để đặt giá trị màu và tọa độ kết cấu trong mảng riêng biệt không? Nhưng sau đó câu hỏi đặt ra: làm thế nào để tôi gọi glDrawElements với các mảng riêng biệt?

Trong trường hợp bạn tự hỏi tại sao tôi muốn tách các giá trị này: Tôi hiện đang tạo trình phân tích cú pháp .obj của mình trong obj-c và tôi đã tự hỏi: điều gì sẽ xảy ra nếu bạn tải mô hình mà không có kết cấu và chỉ muốn hiển thị một màu sắc trên đối tượng? Hoặc: nếu bạn muốn tải một mô hình chỉ với một kết cấu được ánh xạ tới nó nhưng không có màu riêng biệt trên mỗi đỉnh? Và: Không đặt các giá trị màu và phối cảnh kết cấu làm cho Vertex có cấu trúc với quá nhiều dữ liệu.

Trả lời

21

Thực ra đó là cách thông thường để tách dữ liệu đỉnh thành vị trí, màu sắc, vv bằng cách sử dụng một số mảng/bộ đệm.

Lần cuối tôi tiếp xúc với ES 2.0 là trong ngữ cảnh của WebGL (có thông số kỹ thuật hơi khác nhưng cuối cùng dựa trên ES 2.0).

gì được về cơ bản thực hiện được ghi dữ liệu vào bộ đệm riêng biệt sử dụng

glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); 
glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(float), positions, GL_STATIC_DRAW); 
glBindBuffer(GL_ARRAY_BUFFER, 0); 

glBindBuffer(GL_ARRAY_BUFFER, colorBuffer); 
glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), colors, GL_STATIC_DRAW); 
glBindBuffer(GL_ARRAY_BUFFER, 0); 

... 

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); 
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(ushort), indices, GL_STATIC_DRAW); 
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 

với vị trí và màu sắc là mảng float chứa dữ liệu đỉnh và các chỉ số có chứa các chỉ số như quần short unsigned trong trường hợp này.

Để làm cho dữ liệu này, bạn sẽ sử dụng bộ đệm và thuộc tính con trỏ để tạo bóng của bạn:

glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); 
glVertexAttribPointer(vertexPositionAttribute, 3, GL_FLOAT, false, 0, 0); 

glBindBuffer(GL_ARRAY_BUFFER, colorBuffer); 
glVertexAttribPointer(vertexColorAttribute, 4, GL_FLOAT, false, 0, 0); 

Cuối cùng gắn bộ đệm chỉ mục:

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); 

và render:

glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, 0); 

Để nhận các thuộc tính:

glUseProgram(shaderProgram); 

vertexPositionAttribute= glGetAttribLocation(shaderProgram, "vertexPosition"); 
glEnableVertexAttribArray(vertexPositionAttribute); 

vertexColorAttribute = glGetAttribLocation(shaderProgram, "vertexColor"); 
glEnableVertexAttribArray(vertexColorAttribute); 

... 

Nếu bạn không có shaders tùy chỉnh (sử dụng chức năng cố định), bạn có thể có thể sử dụng

glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); 
glVertexPointer(3, GL_FLOAT, false, 0, 0); 

glBindBuffer(GL_ARRAY_BUFFER, colorBuffer); 
glColorPointer(4, GL_FLOAT, false, 0, 0); 

để thay thế. Tôi khuyên bạn nên chống lại nó, mặc dù, vì nó là lỗi thời (nếu có sẵn trong ES 2.0). Nếu bạn vẫn muốn sử dụng nó, bạn có thể bỏ công việc kinh doanh toàn bộ đệm hoàn toàn và sử dụng

glVertexPointer(3, GL_FLOAT, false, 0, positions); 
glColorPointer(4, GL_FLOAT, false, 0, colors); 

với

glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, indices); 

Tôi hy vọng đó không phải là quá khó hiểu và giúp một chút. Để đọc thêm, mặc dù nhắm mục tiêu tại OpenGL, tôi muốn đề xuất Nehe tutorials.

+0

Tinh thể rõ ràng! ;) – polyclick

0

Bạn có thể tách chúng thành bộ đệm phụ nhưng nếu bạn sử dụng chúng thì bạn phải có chúng cho tất cả các đỉnh và nếu bạn sử dụng bộ đệm chỉ mục thì bạn phải sử dụng một bộ đệm chỉ mục cho tất cả (vị trí, màu sắc, texcoord, v.v.) Dưới đây là một số trích đoạn từ mã của tôi:

phân bổ với

glBindBuffer(GL_ARRAY_BUFFER, mId); 
glBufferData(GL_ARRAY_BUFFER, 
       mMaxNumberOfVertices * (mVertexBlockSize + mNormalBlockSize + mColorBlockSize + mTexCoordBlockSize), 
       0, 
       mDrawMode); 

đầy

glBufferSubData(GL_ARRAY_BUFFER, mVertexOffset, numberOfVertsToStore * mVertexBlockSize, vertices); 
glBufferSubData(GL_ARRAY_BUFFER, mNormalOffset, numberOfVertsToStore * mNormalBlockSize, normals); 
glBufferSubData(GL_ARRAY_BUFFER, mColorOffset, numberOfVertsToStore * mColorBlockSize, colors); 
glBufferSubData(GL_ARRAY_BUFFER, mTexCoordOffset, numberOfVertsToStore * mTexCoordBlockSize, texCoords); 

và sử dụng với điều này (tôi không nghĩ rằng clientStates liên tục chuyển đổi là thực hành tốt nhất mặc dù)

void Vbo::draw(GLenum primMode) 
{ 
    glEnableClientState(GL_VERTEX_ARRAY); 
    glVertexPointer(mVertexComponents, GL_FLOAT, 0, (void*)mVertexOffset); 

    if(mNormalBlockSize){ 
    glEnableClientState(GL_NORMAL_ARRAY); 
    glNormalPointer(GL_FLOAT, 0, (void*)mNormalOffset); 
    } 
    if(mColorBlockSize){ 
    glEnableClientState(GL_COLOR_ARRAY); 
    glColorPointer(mColorComponents, GL_FLOAT, 0, (void*)mColorOffset); 
    } 
    if(mTexCoordBlockSize){ 
    glEnableClientState(GL_TEXTURE_COORD_ARRAY); 
    glTexCoordPointer(mTexCoordComponents, GL_FLOAT, 0, (void*)mTexCoordOffset); 
    } 

    if (mAttachedIndexBuffer) 
    { 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mAttachedIndexBuffer); 
    glDrawElements(primMode, 
        mAttachedIndexBuffer->getNumberOfStoredIndices(), 
        mAttachedIndexBuffer->getDataType(), 
        0); 
    } 
    else 
    { 
    glDrawArrays(primMode, 0, mNumberOfStoredVertices); 
    } 

    if(mTexCoordBlockSize) 
    { 
    glDisableClientState(GL_TEXTURE_COORD_ARRAY); 
    } 
    if(mColorBlockSize) 
    { 
    glDisableClientState(GL_COLOR_ARRAY); 
    } 
    if(mNormalBlockSize) 
    { 
    glDisableClientState(GL_NORMAL_ARRAY); 
    } 
    glDisableClientState(GL_VERTEX_ARRAY); 
}  
+1

Không thực sự trả lời câu hỏi nếu bạn có thể lưu trữ các thuộc tính khác nhau trong bộ đệm hoàn toàn khác nhau, mà bạn chắc chắn có thể. –

+0

Tệ của tôi. Tôi không nghĩ rằng có sự khác biệt đáng kể giữa việc sử dụng bộ đệm con và bộ đệm riêng biệt cho mục đích của mình, vì chúng sẽ được phân bổ cùng nhau, được phân phối lại với nhau và luôn sử dụng cùng nhau nếu chúng chứa dữ liệu khác nhau cho cùng một đối tượng. – PeterT

+0

Thật vậy, nhưng anh vẫn hỏi một câu hỏi để được trả lời. –

2

Bạn có thể có dữ liệu của mình trong các bộ đệm khác nhau. Hãy nhớ rằng đó là cuộc gọi glVertexAttribPointer xác định nguồn của thuộc tính. Vì vậy, để sử dụng một bộ đệm khác nhau cho một thuộc tính, chỉ cần liên kết một khác nhau GL_ARRAY_BUFFER trước khi gọi glVertexAttribPointer. glDrawElements không có bất cứ điều gì để làm với nó:

glBindBuffer(GL_ARRAY_BUFFER, positionBuffer); 
glVertexAttribPointer(0, ...); 
glEnableVertexAttribArray(0); 
glBindBuffer(GL_ARRAY_BUFFER, colorBuffer); 
glVertexAttribPointer(1, ...); 
glEnableVertexAttribArray(1); 
glBindBuffer(GL_ARRAY_BUFFER, 0); 

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); 
glDrawElements(...); 

glDisableVertexAttribArray(0); 
glDisableVertexAttribArray(1); 

Khi không sử dụng VBOs (mà tôi không chắc là có thể trong ES 2.0), chỉ cần gọi glVertexAttribPointer với một mảng khác nhau cho mỗi thuộc tính:

glVertexAttribPointer(0, ..., positionArray); 
glEnableVertexAttribArray(0); 
glVertexAttribPointer(1, ..., colorArray); 
glEnableVertexAttribArray(1); 

glDrawElements(..., indexArray); 

glDisableVertexAttribArray(0); 
glDisableVertexAttribArray(1); 

Nhưng thông thường, nó sẽ hoạt động tốt hơn để giữ cho các thuộc tính của một đỉnh cùng nhau giống như trong ví dụ của bạn vì điều này thân thiện với bộ nhớ cache hơn. Nếu gần như tất cả các đối tượng của bạn sử dụng tất cả các mảng, sau đó giữ chúng lại với nhau và không kích hoạt thuộc tính cho một số đối tượng không sử dụng nó, có thể là một ý tưởng tốt hơn. Nhưng nếu các thuộc tính được sử dụng thực sự khác với đối tượng đối tượng thì giải pháp đệm riêng biệt có thể là một ý tưởng tốt hơn. Bạn cũng có thể lưu trữ tất cả các thuộc tính riêng biệt mảng một sau khi khác trong một VBO duy nhất và sử dụng bù đắp bộ đệm tương ứng trong các cuộc gọi glVertexAttribPointer, vì vậy bạn vẫn chỉ cần một VBO cho mỗi đối tượng.

Nhưng tất nhiên bạn chỉ có thể sử dụng một mảng chỉ mục cho mỗi đối tượng chứ không sử dụng các mảng chỉ mục khác nhau cho các vị trí và màu sắc. Điều này có thể yêu cầu bạn phải xử lý dữ liệu đọc từ một tệp OBJ một chút, vì các tệp OBJ thực sự có thể sử dụng các chỉ mục khác nhau cho các vị trí, tiêu chuẩn và texCoords.

Các vấn đề liên quan