Làm cách nào để đảm bảo rằng các ma trận chiếu phối cảnh và chính tả hiển thị các đối tượng có cùng kích thước trên màn hình?


7

Tôi đang làm việc trên một trình chỉnh sửa cảnh 3d và muốn hiển thị cảnh đó trong phép chiếu chính tả. Vấn đề hiện tại của tôi là tôi không chắc cách tính ma trận chiếu chính tả sao cho các đối tượng không xuất hiện ở một kích thước hoàn toàn khác trên màn hình.

Tôi hiện có 2 chức năng sau để tính ma trận chiếu của camera.

Matrix4.createPerspective = function(fov, aspect, near, far, result) {
    if (typeof result === 'undefined') {
        result = new Matrix4();
    }

    var ymax = near * Math.tan(fov * Math.PI / 360);
    var ymin = - ymax;
    var xmin = ymin * aspect;
    var xmax = ymax * aspect;

    Matrix4.createFrustum(xmin, xmax, ymin, ymax, near, far, /*out*/ result);

    return result;
};

Matrix4.createOrthographic = function(left, right, top, bottom, near, far, result) {
    if (typeof result === 'undefined') {
        result = new Matrix4();
    }

    var re = result.elements;
    var w = right - left;
    var h = top - bottom;
    var p = far - near;

    var x = ( right + left ) / w;
    var y = ( top + bottom ) / h;
    var z = ( far + near ) / p;

    re[0] =2/w;  re[4] = 0;   re[8]  = 0;   re[12] =-x;
    re[1] = 0;   re[5] =2/h;  re[9]  = 0;   re[13] =-y;
    re[2] = 0;   re[6] = 0;   re[10] =-2/p; re[14] =-z;
    re[3] = 0;   re[7] = 0;   re[11] = 0;   re[15] = 1;

    return result;
};

Và đây là cách chúng đang được sử dụng:

    updateProjectionMatrix: function(entity) {
        var camera = entity.getComponent('Camera');
        if (camera.isDirty()) {
            camera.aspect = camera.width / camera.height;
            if (camera.isOrthographic()){
                Matrix4.createOrthographic(
                    0, 
                    camera.width, 
                    0, 
                    camera.height, 
                    camera.near, 
                    camera.far, 
            /*out*/ camera._projectionMatrix);
            } else {
                Matrix4.createPerspective(
                    camera.fov,
                    camera.aspect,
                    camera.near,
                    camera.far,
            /*out*/ camera._projectionMatrix);
            }
        }
    },

Dưới đây là một ví dụ về những gì tôi đang cố gắng thực hiện bên trong Blender (F5 chuyển đổi giữa Ortho và Phối cảnh). Lưu ý rằng cả hai hình khối có cùng kích thước trên khung nhìn:

Ví dụ máy xay sinh tố


Khá chắc chắn rằng tất cả những gì bạn cần làm là đặt khoảng cách tiêu cự của bạn là không đổi. Đây sẽ là khoảng cách từ điểm biến mất đến mặt phẳng chiếu.
RandyGaul

@RandyGaul Tôi chắc chắn rằng bạn muốn nói điều này dù sao đi nữa, nhưng đồng bộ hóa cả hai khoảng cách thay vì sửa chúng là đủ.
danijar

Câu trả lời:


4

Trước hết, createPerspectivechức năng của bạn trông không hoàn toàn đúng - so sánh các công thức được sử dụng cho gluPerspective.

Nếu bạn muốn sử dụng cùng một ma trận xem cho cả hai máy ảnh, thì khi bạn thiết lập ma trận chỉnh hình, thay vì sử dụng 0, camera.width, 0, camera.heightbạn có thể muốn -0.5*camera.width, 0.5*camera.width, -0.5*camera.height, 0.5*camera.height. Điều này sẽ giữ chế độ xem tập trung xung quanh vị trí camera, thay vì đặt góc dưới bên trái của chế độ xem ở vị trí camera.

Bạn cũng có thể cần sử dụng các giá trị gần / xa khác nhau cho máy ảnh ortho, tùy thuộc vào việc bạn có muốn chế độ xem ortho hiển thị hình học phía sau máy ảnh hay không (sẽ yêu cầu giá trị âm gần mặt phẳng).

Sau đó, điều bạn cần làm tiếp theo là tính toán camera.widthcamera.heightdựa trên đối tượng hiện được chọn / tập trung khi bạn chuyển sang chế độ chỉnh hình. Bạn muốn các giá trị đó biểu thị chiều rộng và chiều cao của sự thất vọng ở độ sâu (khoảng cách dọc theo trục z của không gian camera) của đối tượng được chọn.

Nếu bạn sử dụng gluPerspectivema trận phối cảnh kiểu, thì các thành phần [0, 0] và [1, 1] của ma trận tương ứng là 2 / chiều rộng và 2 / chiều cao, ở độ sâu 1.0 đơn vị từ máy ảnh. Chiều rộng và chiều cao của thang đo độ lệch tuyến tính với độ sâu, vì vậy tất cả những gì bạn cần làm là nhân chúng với độ sâu của đối tượng tập trung:

objectDepth = dot(objectPos - cameraPos, cameraViewVector);
camera.width = (2.0 / perspectiveMatrix[0]) * objectDepth;
camera.height = (2.0 / perspectiveMatrix[5]) * objectDepth;

Tất nhiên, bạn cũng có thể tính toán lại các thành phần ma trận phối cảnh bằng cách sử dụng tỷ lệ khung hình và tỷ lệ khung hình nếu cần thiết.


Khi bạn có objectDepth, bạn có thể sử dụng cách sau để tính chiều rộng và chiều cao của ortho: var ymax = Math.tan(camera.fov * Math.PI / 360); var xmax = ymax * camera.aspect; var width = objectDepth * xmax; var height = objectDepth * ymax;
zfedoran
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.