Cesium 通過primitive 添加垂直圖片資源

實際Cesium 項目中添加了部分貼地的資源。資源類型有圖片,gltf或者glb的模型。這裏簡單比較一下primitive 和entity。

primitive 基於比較底層的webgl技術,進行渲染資源,所以對於很多自定義的效果支持比較好,靈活度比較高,帶來的開銷就是API複雜,參數多,單獨相對大。

entity, 是對primitive的封裝,操作簡單,一般的效果都能滿足。

本次項目中是爲了通過座標系,變換實體模型對象。目前知道的就是通過primitive加進去的模型,支持座標變換。其他的應該也有,但是沒接觸到。

先看一下效果

其實有兩種思路處理這個問題,一種是做一個glb的模型,另一外一種是通過圖片作爲材質創建primitive對象。實際驗證的效果是通過glb模型創建添加的資源,可以實現座標系的編輯,通過圖片作爲材質創建的primitive對象,無法完成座標變換。調試發現是因爲圖片添加的primitive modelMatrix 爲空。可能也和我操作有關,我親自測試失敗了。

作爲glb模型添加

var targetPosition = Cesium.Cartesian3.fromDegrees(pos[0], pos[1], pos[2] + 0.5);
    var headingPitchRoll = new Cesium.HeadingPitchRoll(0, 0, 0);
    var modelMatrix = new Cesium.Matrix4();
    var modelEntity;
    Cesium.Transforms.headingPitchRollToFixedFrame(targetPosition, headingPitchRoll, Cesium.Ellipsoid.WGS84, Cesium.Transforms.eastNorthUpToFixedFrame, modelMatrix);
    window.setTimeout(function() {
        modelEntity = viewer.scene.primitives.add(Cesium.Model.fromGltf({
            id: src_manager._GenGuid("3d_geo_"),
            name: name,
            url: url,
            modelMatrix: modelMatrix,
            scale: 2,
            colorBlendMode: Cesium.ColorBlendMode.HIGHLIGHT
        }));
        modelEntity.readyPromise.then(function(modeltemp) {
        });
    }, 500);

作爲圖片添加的primitive對象,參考鏈接https://zhuanlan.zhihu.com/p/41862338

function addDevImg(pos, size, url) {
    var dimensions = new Cesium.Cartesian3(size, size, 1.0);
    var positionOnEllipsoid = Cesium.Cartesian3.fromDegrees(parseFloat(pos[0]), parseFloat(pos[1]));
    var translateMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(positionOnEllipsoid);
    var rotationYMatrix = Cesium.Matrix4.fromRotationTranslation(Cesium.Matrix3.fromRotationY(Cesium.Math.toRadians(120.0)));
    var scaleMatrix = Cesium.Matrix4.fromScale(dimensions);

    var planeYModelMatrix = new Cesium.Matrix4();
    Cesium.Matrix4.multiply(translateMatrix, rotationYMatrix, planeYModelMatrix);
    Cesium.Matrix4.multiply(planeYModelMatrix, scaleMatrix, planeYModelMatrix);

    createPlane(planeYModelMatrix, new Cesium.Color(0.0, 1.0, 0.0, 1.0));

    function createPlane(planeModelMatrix, color) {
        // 創建平面
        /*var planeGeometry = new Cesium.PlaneGeometry({
            vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
        });*/
        var planeGeometry = new Cesium.PlaneGeometry();

        var planeGeometryInstance = new Cesium.GeometryInstance({
            geometry: planeGeometry,
            modelMatrix: planeModelMatrix,
        });

        var material = new Cesium.Material({
            fabric: {
                type: "DiffuseMap",
                uniforms: {
                    image: url,
                },
            },
        });
        var model = viewer.scene.primitives.add(new Cesium.Primitive({
            geometryInstances: planeGeometryInstance,
            appearance: new Cesium.MaterialAppearance({
                closed: false,
                //translucent: false,
                material: material
            })
        }));
    }
}

 

通過座標系拾取模型對象進行座標變換。

function rotateTranslation(viewer) {
    //handler && handler.destroy();			
    var timeoutID = null;
    if (!window.roate_handler) {
        window.roate_handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
    }
    //var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
    var tooltip;
    window.roate_handler.setInputAction(function(movement) {
        tooltip = document.getElementById("toolTip");
        tooltip.innerHTML = '<p style="color:red;font-size:16px;">單擊選擇單體模型</p>';
        tooltip.style.display = "block";
        tooltip.style.left = movement.endPosition.x + 3 + "px";
        tooltip.style.top = movement.endPosition.y - 25 + "px";
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
    //鼠標左擊
    window.roate_handler.setInputAction(function(movement) {
        if (timeoutID != null) {
            clearTimeout(timeoutID);
        }
        var picked = viewer.scene.pick(movement.position);
        if (Cesium.defined(picked)) {
            if (picked.primitive) {
                var model = picked.primitive;
                var scale = model.boundingSphere.radius;
                timeoutID = window.setTimeout(function() {
                    if (window.axisModel) {
                        viewer.scene.primitives.remove(window.axisModel);
                    }
                    var axisModel = viewer.scene.primitives.add(Cesium.Model.fromGltf({
                        url: '../../Build/DECore/models/TransformGizmo_Tex12.gltf',
                        modelMatrix: model.modelMatrix,
                        scale: 2,
                        colorBlendMode: Cesium.ColorBlendMode.HIGHLIGHT
                    }));
                    if (axisModel) {
                        window.axisModel = axisModel;
                        tooltip.style.display = "none";
                        //旋轉平移
                        rotateAndTranslation(viewer, model, axisModel);
                    }
                }, 250);
            }
        }
        clearAxisHandler = function(e) {
            clearTimeout(timeoutID);
            window.roate_handler = window.roate_handler && window.roate_handler.destroy();
            // downHandler = downHandler && downHandler.destroy();
            if (window.axisModel) {
                viewer.scene.primitives.remove(window.axisModel);
            }
            window.axisModel = undefined;
            tooltip.style.display = "none";
        };
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
    window.roate_handler.setInputAction(function(movement) {
        clearTimeout(timeoutID);
        window.roate_handler = window.roate_handler && window.roate_handler.destroy();
        // downHandler = downHandler && downHandler.destroy();
        if (window.axisModel) {
            viewer.scene.primitives.remove(window.axisModel);
        }
        window.axisModel = undefined;
        tooltip.style.display = "none";

    }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
}

function rotateAndTranslation(viewer, model, axisModel) {
    // 事件監控
    if (!window.roate_handler) {
        window.roate_handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
    }
    // 判斷當前是否點擊在座標軸上進行拖動和旋轉
    var isAxis = false;

    var zhou = undefined; // 當前拖拽的是哪個軸

    window.roate_handler.setInputAction(function(movement) {

        var cartesian = viewer.scene.pickPosition(movement.position);
        var pickedObject = viewer.scene.pick(movement.position);
        if (!Cesium.defined(pickedObject)) {
            return;
        }
        if (!Cesium.defined(pickedObject.mesh)) {
            return;
        }
        if (Cesium.defined(pickedObject)) {
            zhou = pickedObject.mesh.name;
            isAxis = true;
        }
    }, Cesium.ScreenSpaceEventType.LEFT_DOWN);

    window.roate_handler.setInputAction(function(movement) {
        var pickedObject = viewer.scene.pick(movement.endPosition);
        var startCartesian3 = viewer.scene.pickPosition(movement.startPosition);
        var endCartesian3 = viewer.scene.pickPosition(movement.endPosition);
        var m = model.modelMatrix;
        // 旋轉和平移函數得到射線和麪交點
        var axisTransForm = function(surface) {

                var matrix = Cesium.Matrix4.inverseTransformation(m, new Cesium.Matrix4());

                // 獲取相機座標
                var camera1 = viewer.camera.position;

                // 轉 模型座標
                var camera = Cesium.Matrix4.multiplyByPoint(matrix, camera1, new Cesium.Cartesian3());
                var startM = Cesium.Matrix4.multiplyByPoint(matrix, startCartesian3, new Cesium.Cartesian3());
                var endM = Cesium.Matrix4.multiplyByPoint(matrix, endCartesian3, new Cesium.Cartesian3());
                // 從相機看模型的方向
                var startDirection = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(startM, camera, new Cesium.Cartesian3()), new Cesium.Cartesian3());
                var endDirection = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(endM, camera, new Cesium.Cartesian3()), new Cesium.Cartesian3())

                // 面
                var plane = Cesium.Plane.fromPointNormal(Cesium.Cartesian3.ZERO, surface);

                // 射線
                var startRay = new Cesium.Ray(camera, startDirection);
                var endRay = new Cesium.Ray(camera, endDirection);

                // 射線和麪交點
                var start = Cesium.IntersectionTests.rayPlane(startRay, plane);
                var end = Cesium.IntersectionTests.rayPlane(endRay, plane);
                return { start: start, end: end };
            }
            // 平移函數
        var axisMove = function(surface, zeroAxis1, zeroAxis2) {
            var point = axisTransForm(surface);
            // 兩點差值
            var sub = Cesium.Cartesian3.subtract(point.end, point.start, new Cesium.Cartesian3());
            sub[zeroAxis1] = 0;
            sub[zeroAxis2] = 0;
            //  var sub2 = Cesium.Matrix4.multiplyByPoint(m, sub, new Cesium.Cartesian3());
            var mm = Cesium.Matrix4.multiplyByTranslation(m, sub, new Cesium.Matrix4());
            model.modelMatrix = mm;
            // 將座標軸模型移到和模型相同的位置
            axisModel.modelMatrix = model.modelMatrix;
        }

        // 旋轉函數
        var axisRotate = function(surface, tant1, tant2) {
            var point = axisTransForm(surface);
            // 兩點角度
            var tant = (point.start[tant1] * point.end[tant2] - point.start[tant2] * point.end[tant1]) / (point.start[tant1] * point.end[tant1] + point.start[tant2] * point.end[tant2]);

            var quat = Cesium.Quaternion.fromAxisAngle(surface, Math.atan(tant)); //quat爲圍繞這個surface軸旋轉d度的四元數
            var rot_mat3 = Cesium.Matrix3.fromQuaternion(quat);

            var m2 = Cesium.Matrix4.multiplyByMatrix3(m, rot_mat3, new Cesium.Matrix4());
            // 移動模型
            model.modelMatrix = m2;
            // 將座標軸模型移到和模型相同的位置
            axisModel.modelMatrix = model.modelMatrix;
        }
        if (isAxis && startCartesian3 && endCartesian3) {

            cameraControl(false); // 禁止球轉動和拖動
            switch (zhou) {
                case 'YArrow_1':
                    axisMove(Cesium.Cartesian3.UNIT_Z, 'y', 'z');
                    break;
                case 'XArrow_1':
                    axisMove(Cesium.Cartesian3.UNIT_X, 'x', 'z');
                    break;
                case 'ZArrow_1':
                    axisMove(Cesium.Cartesian3.UNIT_Y, 'x', 'y');
                    break;
                case 'YAxis_1':
                    axisRotate(Cesium.Cartesian3.UNIT_X, 'y', 'z');
                    break;
                case 'XAxis_1':
                    axisRotate(Cesium.Cartesian3.UNIT_Y, 'z', 'x');
                    break;
                case 'ZAxis_1':
                    axisRotate(Cesium.Cartesian3.UNIT_Z, 'x', 'y');
                    break;

            }

        }

    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

    window.roate_handler.setInputAction(function(movement) {
        isAxis = false;
        cameraControl(true);
    }, Cesium.ScreenSpaceEventType.LEFT_UP);


    // 球轉動事件
    var cameraControl = function(isCamera) {
        viewer.scene.screenSpaceCameraController.enableRotate = isCamera;
        viewer.scene.screenSpaceCameraController.enableTranslate = isCamera;
        viewer.scene.screenSpaceCameraController.enableZoom = isCamera;
        viewer.scene.screenSpaceCameraController.enableTilt = isCamera;
        viewer.scene.screenSpaceCameraController.enableLook = isCamera;
    }

}

最後結合一下,把圖片貼在透明的glb模型上,按glb模型的方式統一加載,效果可以。貼一張效果圖。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章