2010-02-13 11 views
23

Tôi có một số hình học 2D. Tôi muốn có một số giới hạn rect quanh hình học của tôi, và sau đó làm cho một phiên bản nhỏ hơn của nó ở một nơi khác trên máy bay. Dưới đây là nhiều hay ít mã tôi phải làm rộng và dịch:OpenGL: tỷ lệ sau đó dịch? và làm thế nào?

// source and dest are arbitrary rectangles. 
float scaleX = dest.width/source.width; 
float scaleY = dest.height/source.height; 
float translateX = dest.x - source.x; 
float translateY = dest.y - source.y; 

glScalef(scaleX, scaleY, 0.0); 
glTranslatef(translateX, translateY, 0.0); 
// Draw geometry in question with its normal verts. 

này hoạt động chính xác như mong đợi cho một chiều hướng đưa ra khi nguồn gốc đích là 0. Nhưng nếu nguồn gốc cho, nói, x, là nonzero, kết quả vẫn được chia tỷ lệ chính xác nhưng trông giống như (?) nó được dịch sang một cái gì đó gần bằng không trên trục đó anyways-- hóa ra nó không chính xác giống như nếu dest.x là số không.

Ai đó có thể chỉ ra điều gì đó hiển nhiên tôi đang thiếu?

Cảm ơn!

BÁO CÁO CUỐI CÙNG Mỗi câu trả lời của Bahbar và Marcus bên dưới, tôi đã thực hiện thêm một số thử nghiệm và giải quyết vấn đề này. Lời bình luận của Adam Bowen là một mẹo nhỏ. Tôi đã thiếu hai sự kiện quan trọng:

  1. Tôi cần phải mở rộng xung quanh trung tâm của hình tôi quan tâm.
  2. Tôi cần áp dụng các biến đổi theo thứ tự ngược lại trực giác (đối với tôi).

Đầu tiên là loại hiển nhiên khi nhìn lại. Nhưng đối với các lập trình viên tốt/nhà toán học tồi như tôi: Hóa ra trực giác của tôi hoạt động trong những gì mà Red Book gọi là "Grand, Fixed Coordinate System", trong đó có một mặt phẳng tuyệt đối, và hình của bạn di chuyển xung quanh mặt phẳng bằng cách sử dụng biến đổi. Điều này là tốt, nhưng với bản chất của toán học đằng sau xếp chồng nhiều biến đổi thành một ma trận, nó trái ngược với cách mọi thứ thực sự hiệu quả (xem câu trả lời bên dưới hoặc Sổ đỏ để biết thêm). Về cơ bản, các biến đổi được "áp dụng" trong "thứ tự ngược lại" để chúng xuất hiện trong mã. Đây là giải pháp làm việc cuối cùng:

// source and dest are arbitrary rectangles. 
float scaleX = dest.width/source.width; 
float scaleY = dest.height/source.height; 
Point sourceCenter = centerPointOfRect(source); 
Point destCenter = centerPointOfRect(dest); 

glTranslatef(destCenter.x, destCenter.y, 0.0); 
glScalef(scaleX, scaleY, 0.0); 
glTranslatef(sourceCenter.x * -1.0, sourceCenter.y * -1.0, 0.0); 
// Draw geometry in question with its normal verts. 

Trả lời

16

Trong OpenGL, ma trận bạn chỉ định được nhân với bên phải của ma trận hiện có và đỉnh nằm ở bên phải của biểu thức.

Do đó, thao tác cuối cùng bạn chỉ định nằm trong hệ tọa độ của chính hình học. (Lần đầu tiên thường là biến đổi chế độ xem, nghĩa là nghịch đảo của biến đổi thế giới của máy ảnh của bạn.)

Bahbar làm cho điểm tốt là bạn cần xem xét điểm trung tâm để mở rộng quy mô. (hoặc điểm xoay cho phép quay.) Thông thường bạn dịch ở đó, xoay/chia tỷ lệ, sau đó dịch ngược lại. (hoặc nói chung, áp dụng biến đổi cơ sở, hoạt động, sau đó nghịch đảo).Điều này được gọi là Change of Basis, mà bạn có thể muốn đọc.

Dù sao, để có được trực giác về cách hoạt động, hãy thử với một số giá trị đơn giản (không, vv) sau đó thay đổi chúng một chút (có thể là hoạt ảnh) và xem điều gì xảy ra với đầu ra. Sau đó, nó dễ dàng hơn nhiều để xem những gì biến đổi của bạn đang thực sự làm cho hình học của bạn.

Cập nhật

Đó là trật tự là "đảo ngược" w.r.t. trực giác là khá phổ biến trong số các lập trình viên OpenGL mới bắt đầu. Tôi đã dạy kèm một khóa học đồ họa máy tính và nhiều phản ứng theo cách tương tự. Nó trở nên dễ dàng hơn để suy nghĩ về cách OpenGL làm điều đó nếu bạn xem xét việc sử dụng pushmatrix/popmatrix trong khi vẽ một cây (đồ thị cảnh) của biến đổi và hình học. Sau đó, trật tự hiện tại của sự vật trở nên khá tự nhiên, và ngược lại sẽ làm cho nó khá khó khăn để có được bất cứ điều gì hữu ích thực hiện.

+1

Tóm lại, thay đổi thứ tự thành glTranslate (dest); glScale (quy mô); glTranslate (nguồn); –

+0

Adam: Điều này dường như không hoạt động như bạn gợi ý, mặc dù tôi tò mò-- bạn có thể giải thích lý do tại sao thứ tự sẽ như thế và có thể cung cấp một ý tưởng rõ ràng hơn về cách nó sẽ liên quan đến mã hiện tại ? Có lẽ tôi chỉ hiểu sai mã giả của bạn. Cảm ơn! –

+0

Nevermind: "không hoạt động" là giá trị béo phì trong trường hợp này. Sau khi sửa chữa, chúng tôi đang kinh doanh. Xem câu hỏi được cập nhật để biết thêm. Cảm ơn! –

6

Quy mô, giống như Xoay, hoạt động từ nguồn gốc. vì vậy nếu bạn mở rộng một nửa đối tượng trải rộng đoạn [10:20] (trên trục X, ví dụ), bạn sẽ nhận được [5:10]. Do đó, đối tượng được thu nhỏ và di chuyển đến gần nguồn gốc hơn. Chính xác những gì bạn quan sát.

Đây là lý do tại sao bạn áp dụng Quy mô đầu tiên nói chung (vì các đối tượng có xu hướng được xác định khoảng 0).

Vì vậy, nếu bạn muốn chia tỷ lệ đối tượng quanh điểm Trung tâm, bạn có thể dịch đối tượng từ Trung tâm sang gốc, chia tỷ lệ và dịch ngược lại.

Lưu ý phụ, nếu bạn dịch trước, sau đó mở tỷ lệ, thì tỷ lệ của bạn được áp dụng cho bản dịch trước đó, đó là lý do bạn có thể gặp sự cố với phương pháp này.

+0

Cảm ơn bạn đã trả lời. Bạn có thể đánh vần cho một ma trận-math dimwit những hoạt động tôi sẽ làm gì, để làm thích hợp dịch-to-origin, sau đó quy mô, sau đó dịch-trở lại? Tôi đã cố gắng xếp chồng ba thứ này liên tiếp (dịch theo tiêu cực nguồn gốc, sau đó chia tỷ lệ theo các yếu tố tỷ lệ, sau đó dịch theo nguồn gốc) trong ba cuộc gọi trước khi vẽ hình nhưng không có kết quả rõ ràng. –

+0

Ah, có lẽ tôi cần phải làm các bản dịch liên quan đến trung tâm của rect hơn là nguồn gốc. Sẽ cố gắng này. –

+0

Không. Không có súc sắc với: dịch-by-âm-trung tâm-của-nguồn, sau đó quy mô, sau đó dịch-by-tích cực-trung tâm-of-dest. –

1

Tôi chưa chơi với OpenGL ES, chỉ một chút với OpenGL.

Có vẻ như bạn muốn chuyển đổi từ một vị trí khác trái ngược với nguồn gốc, không chắc chắn, nhưng bạn có thể thử thực hiện các phép biến đổi và vẽ bit đó trong glPushMatrix() and glPopMatrix() không?

e.g. 

// source and dest are arbitrary rectangles. 
float scaleX = dest.width/source.width; 
float scaleY = dest.height/source.height; 
float translateX = dest.x - source.x; 
float translateY = dest.y - source.y; 

glPushMatrix(); 
    glScalef(scaleX, scaleY, 0.0); 
    glTranslatef(translateX, translateY, 0.0); 
    // Draw geometry in question with its normal verts. 
    //as if it were drawn from 0,0 
glPopMatrix(); 

Dưới đây là một phác thảo chế biến đơn giản, tôi đã viết để minh họa cho điểm:

import processing.opengl.*; 
import javax.media.opengl.*; 


void setup() { 
    size(500, 400, OPENGL); 
} 

void draw() { 
    background(255); 
    PGraphicsOpenGL pgl = (PGraphicsOpenGL) g; 
    GL gl = pgl.beginGL(); 


    gl.glPushMatrix(); 
    //transform the 'pivot' 
    gl.glTranslatef(100,100,0); 
    gl.glScalef(10,10,10); 
    //draw something from the 'pivot' 
    gl.glColor3f(0, 0.77, 0); 
    drawTriangle(gl); 
    gl.glPopMatrix(); 
    //matrix poped, we're back to orginin(0,0,0), continue as normal 
    gl.glColor3f(0.77, 0, 0); 
    drawTriangle(gl); 
    pgl.endGL(); 
} 

void drawTriangle(GL gl){ 
    gl.glBegin(GL.GL_TRIANGLES); 
    gl.glVertex2i(10, 0); 
    gl.glVertex2i(0, 20); 
    gl.glVertex2i(20, 20); 
    gl.glEnd(); 
} 

Dưới đây là một hình ảnh của chạy phác thảo, cùng tam giác màu xanh lá cây được rút ra, với bản dịch và quy mô áp dụng, thì một màu đỏ, outsie push/pop 'khối', vì vậy nó không bị ảnh hưởng bởi biến đổi:

alt text

HTH, Ge orge

+0

Cảm ơn George, nhưng push/pop không thực sự là vấn đề; Tôi đã làm một push/pop bên ngoài mã mà tôi đã thực hiện các đoạn. Cảm ơn bạn đã minh họa bằng hình ảnh! Một hình dung tốt. –