Tất cả về các đối tượng OpenGL
Mô hình chuẩn cho các đối tượng OpenGL như sau.
Đối tượng có nhà nước. Hãy nghĩ về họ như một struct
. Vì vậy, bạn có thể có một đối tượng được xác định như thế này:
struct Object
{
int count;
float opacity;
char *name;
};
Đối tượng có các giá trị nhất định được lưu trữ trong nó và nó có trạng thái . Các đối tượng OpenGL cũng có trạng thái.
Thay đổi trạng thái
Trong C / C ++, nếu bạn có một thể hiện của loại Object
, bạn sẽ thay đổi trạng thái của nó như sau: obj.count = 5;
Bạn sẽ trực tiếp tham chiếu một thể hiện của đối tượng, lấy phần trạng thái cụ thể mà bạn muốn thay đổi và chuyển một giá trị vào nó.
Trong OpenGL, bạn không làm điều này.
Vì lý do di sản tốt hơn không giải thích được, để thay đổi trạng thái của một đối tượng OpenGL, trước tiên bạn phải liên kết nó với bối cảnh. Điều này được thực hiện với một số từ glBind*
cuộc gọi.
C / C ++ tương đương với điều này như sau:
Object *g_objs[MAX_LOCATIONS] = {NULL};
void BindObject(int loc, Object *obj)
{
g_objs[loc] = obj;
}
Hoạ tiết rất thú vị; họ đại diện cho một trường hợp đặc biệt của ràng buộc. Nhiều glBind*
cuộc gọi có tham số "đích". Điều này thể hiện các vị trí khác nhau trong bối cảnh OpenGL nơi các đối tượng thuộc loại đó có thể bị ràng buộc. Ví dụ: bạn có thể liên kết một đối tượng bộ đệm khung để đọc ( GL_READ_FRAMEBUFFER
) hoặc để viết ( GL_DRAW_FRAMEBUFFER
). Điều này ảnh hưởng đến cách OpenGL sử dụng bộ đệm. Đây là những gì các loc
tham số ở trên đại diện.
Hoạ tiết rất đặc biệt vì khi bạn lần đầu tiên liên kết chúng với mục tiêu, chúng sẽ nhận được thông tin đặc biệt. Khi bạn lần đầu tiên liên kết một kết cấu như một GL_TEXTURE_2D
, bạn thực sự đang thiết lập trạng thái đặc biệt trong kết cấu. Bạn đang nói rằng kết cấu này là một kết cấu 2D. Và nó sẽ luôn là một kết cấu 2D; trạng thái này không thể thay đổi bao giờ . Nếu bạn có một kết cấu được ràng buộc đầu tiên là a GL_TEXTURE_2D
, bạn phải luôn liên kết nó như một GL_TEXTURE_2D
; cố gắng ràng buộc nó GL_TEXTURE_1D
sẽ làm phát sinh lỗi (trong thời gian chạy).
Một khi đối tượng bị ràng buộc, trạng thái của nó có thể được thay đổi. Điều này được thực hiện thông qua các chức năng chung cụ thể cho đối tượng đó. Họ cũng có một vị trí đại diện cho đối tượng để sửa đổi.
Trong C / C ++, điều này trông giống như:
void ObjectParameteri(int loc, ObjectParameters eParam, int value)
{
if(g_objs[loc] == NULL)
return;
switch(eParam)
{
case OBJECT_COUNT:
g_objs[loc]->count = value;
break;
case OBJECT_OPACITY:
g_objs[loc]->opacity = (float)value;
break;
default:
//INVALID_ENUM error
break;
}
}
Lưu ý cách hàm này đặt bất cứ điều gì xảy ra trong loc
giá trị hiện tại bị ràng buộc .
Đối với các đối tượng kết cấu, các chức năng thay đổi trạng thái kết cấu chính là glTexParameter
. Các chức năng khác chỉ thay đổi trạng thái kết cấu là các glTexImage
chức năng và các biến thể của chúng ( glCompressedTexImage
,, glCopyTexImage
gần đây glTexStorage
). Các SubImage
phiên bản khác nhau thay đổi nội dung của kết cấu, nhưng về mặt kỹ thuật chúng không thay đổi trạng thái của nó . Các Image
chức năng phân bổ lưu trữ kết cấu và đặt định dạng của kết cấu; các SubImage
chức năng chỉ sao chép các pixel xung quanh. Đó không được coi là trạng thái của kết cấu.
Cho phép tôi lặp lại: đây là các chức năng duy nhất sửa đổi trạng thái kết cấu. glTexEnv
Sửa đổi trạng thái môi trường; nó không ảnh hưởng đến bất cứ thứ gì được lưu trữ trong các đối tượng kết cấu.
Kết cấu hoạt động
Tình hình cho kết cấu phức tạp hơn, một lần nữa vì lý do di sản tốt nhất không được tiết lộ. Đây là nơi glActiveTexture
đến.
Đối với kết cấu, không có chỉ tiêu ( GL_TEXTURE_1D
, GL_TEXTURE_CUBE_MAP
, vv). Ngoài ra còn có các đơn vị kết cấu . Xét về ví dụ C / C ++ của chúng tôi, những gì chúng tôi có là:
Object *g_objs[MAX_OBJECTS][MAX_LOCATIONS] = {NULL};
int g_currObject = 0;
void BindObject(int loc, Object *obj)
{
g_objs[g_currObject][loc] = obj;
}
void ActiveObject(int currObject)
{
g_currObject = currObject;
}
Bây giờ, chúng ta không chỉ có một danh sách 2D Object
, mà chúng ta còn có khái niệm về một đối tượng hiện tại. Chúng ta có một chức năng để thiết lập đối tượng hiện tại, chúng ta có khái niệm về số lượng đối tượng hiện tại tối đa và tất cả các chức năng thao tác đối tượng của chúng ta được điều chỉnh để chọn từ đối tượng hiện tại.
Khi bạn thay đổi đối tượng hiện đang hoạt động, bạn thay đổi toàn bộ nhóm vị trí đích. Vì vậy, bạn có thể liên kết một cái gì đó đi vào đối tượng hiện tại 0, chuyển sang đối tượng hiện tại 4 và sẽ sửa đổi một đối tượng hoàn toàn khác.
Sự tương đồng với các đối tượng kết cấu là hoàn hảo ... gần như.
Xem, glActiveTexture
không lấy một số nguyên; phải mất một điều tra viên . Mà trong lý thuyết có nghĩa là nó có thể lấy bất cứ thứ gì từ GL_TEXTURE0
đến GL_TEXTURE31
. Nhưng có một điều bạn phải hiểu:
ĐIỀU NÀY LÀ SAI!
Phạm vi thực tế glActiveTexture
có thể mất được chi phối bởi GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
. Đó là số lượng đa điểm đồng thời tối đa mà việc triển khai cho phép. Chúng được chia thành các nhóm khác nhau cho các giai đoạn đổ bóng khác nhau. Ví dụ, trên phần cứng lớp GL 3.x, bạn nhận được 16 kết cấu đổ bóng đỉnh, 16 kết cấu đổ bóng mảnh và 16 kết cấu đổ bóng hình học. Do đó, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
sẽ là 48.
Nhưng không có 48 điều tra viên. Đó là lý do tại sao glActiveTexture
không thực sự mất các điều tra viên. Các đúng cách để gọi glActiveTexture
là như sau:
glActiveTexture(GL_TEXTURE0 + i);
trong đó i
một số từ 0 đến GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
.
Kết xuất
Vì vậy, tất cả những điều này có liên quan gì đến kết xuất?
Khi sử dụng các shader, bạn đặt đồng phục lấy mẫu của mình thành một đơn vị hình ảnh kết cấu ( glUniform1i(samplerLoc, i)
, đơn vị hình ảnh ở đâu i
). Điều đó thể hiện số lượng bạn đã sử dụng với glActiveTexture
. Người lấy mẫu sẽ chọn mục tiêu dựa trên loại người lấy mẫu. Vì vậy, một sampler2D
sẽ chọn từ GL_TEXTURE_2D
mục tiêu. Đây là một lý do tại sao các mẫu lấy mẫu có các loại khác nhau.
Bây giờ điều này nghe có vẻ đáng ngờ giống như bạn có thể có hai bộ lấy mẫu GLSL, với các loại khác nhau sử dụng cùng một đơn vị hình ảnh kết cấu. Nhưng bạn không thể; OpenGL cấm điều này và sẽ gây ra lỗi khi bạn cố kết xuất.
GL_TEXTURE0 + i
- tôi có ý kiểm tra các giá trị enum để xem liệu điều đó có hợp lệ hay không. Và đoạn cuối - không biết điều đó có hợp pháp hay không. Thông minh! Tôi đánh dấu tất cả các câu trả lời của bạn để tôi có thể tham khảo lại.