在实现视频投射的时候,接触了一下视椎体,但是研究并不透彻。
后来在群里见到有人想在线看一下视椎体效果,以及实现过程,于是就试了一下。
本文包含视锥体核心代码、完整代码以及在线示例三部分。
// 定义创建四棱锥类
function CreateFrustum(options) {
// 位置点
this.position = options.position;
// 方向
this.orientation = options.orientation;
// 相机视场角
this.fov = options.fov || 30;
// 近距离点,0 则会显示四棱锥的顶点
this.near = options.near || 10;
// 远距离点
this.far = options.far || 100;
// 视锥的宽度/高度
this.aspectRatio = options.aspectRatio;
this.add();
}
CreateFrustum.prototype.add = function add() {
this.clear();
this.addFrustum();
this.addOutline();
}
CreateFrustum.prototype.update = function (position, orientation) {
this.position = position;
this.orientation = orientation;
this.add();
}
CreateFrustum.prototype.clear = function () {
this.clearFrustum();
this.clearOutline();
}
CreateFrustum.prototype.clearFrustum = function () {
if (this.frustumPrimitive) {
viewer.scene.primitives.remove(this.frustumPrimitive);
this.frustumPrimitive = null;
}
}
CreateFrustum.prototype.clearOutline = function () {
if (this.outlinePrimitive) {
viewer.scene.primitives.remove(this.outlinePrimitive);
this.outlinePrimitive = null;
}
}
// 创建视锥体
CreateFrustum.prototype.addFrustum = function () {
// 创建视锥
let frustum = new Cesium.PerspectiveFrustum({
fov: Cesium.Math.toRadians(this.fov),
aspectRatio: this.aspectRatio,
near: this.near,
far: this.far,
});
// 创建视锥几何数据
let geometry = new Cesium.FrustumGeometry({
frustum: frustum,
origin: this.position,
orientation: this.orientation,
vertexFormat: Cesium.VertexFormat.POSITION_ONLY,
});
// 创建实例
let instance = new Cesium.GeometryInstance({
geometry: geometry,
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
new Cesium.Color(1.0, 1.0, 1.0, 0.2)
),
},
});
let primitive = new Cesium.Primitive({
geometryInstances: instance,
appearance: new Cesium.PerInstanceColorAppearance({
closed: true,
flat: true,
}),
asynchronous: false,
});
this.frustumPrimitive = viewer.scene.primitives.add(primitive);
}
// 创建视锥边框
CreateFrustum.prototype.addOutline = function () {
let frustum = new Cesium.PerspectiveFrustum({
fov: Cesium.Math.toRadians(this.fov),
aspectRatio: this.aspectRatio,
near: this.near,
far: this.far,
});
let geometry = new Cesium.FrustumOutlineGeometry({
frustum: frustum,
origin: this.position,
orientation: this.orientation,
vertexFormat: Cesium.VertexFormat.POSITION_ONLY,
});
let instance = new Cesium.GeometryInstance({
geometry: geometry,
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
new Cesium.Color(0.0, 1.0, 1.0, 1.0)
),
},
});
let primitive = new Cesium.Primitive({
geometryInstances: instance,
appearance: new Cesium.PerInstanceColorAppearance({
closed: true,
flat: true,
}),
asynchronous: false,
});
this.outlinePrimitive = viewer.scene.primitives.add(primitive);
}
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Use correct character set. -->
<meta charset="utf-8"/>
<!-- Tell IE to use the latest, best version. -->
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<!-- Make the application on mobile take up the full browser screen and disable user scaling. -->
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
/>
<title>Cesium entity frustum</title>
<script src="http://openlayers.vip/examples/csdn/Cesium.js"></script>
<script src="./cesium_init.js"></script>
<script src="http://www.openlayers.vip/examples/resources/jquery-3.5.1.min.js"></script>
<style>
@import url(./Widgets/widgets.css);
html,
body,
#cesiumContainer {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
</style>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?f80a36f14f8a73bb0f82e0fdbcee3058";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</head>
<body>
<button id="clearFunc" onClick="clearFunc()">清空</button>
<button id="restoreFunc" onClick="addFrustum()">还原</button>
<div id="cesiumContainer"></div>
<script>
// 创建三维球
const viewer = init();
// 定义创建四棱锥类
function CreateFrustum(options) {
// 位置点
this.position = options.position;
// 方向
this.orientation = options.orientation;
// 相机视场角
this.fov = options.fov || 30;
// 近距离点,0 则会显示四棱锥的顶点
this.near = options.near || 10;
// 远距离点
this.far = options.far || 100;
// 视锥的宽度/高度
this.aspectRatio = options.aspectRatio;
this.add();
}
CreateFrustum.prototype.add = function add() {
this.clear();
this.addFrustum();
this.addOutline();
}
CreateFrustum.prototype.update = function (position, orientation) {
this.position = position;
this.orientation = orientation;
this.add();
}
CreateFrustum.prototype.clear = function () {
this.clearFrustum();
this.clearOutline();
}
CreateFrustum.prototype.clearFrustum = function () {
if (this.frustumPrimitive) {
viewer.scene.primitives.remove(this.frustumPrimitive);
this.frustumPrimitive = null;
}
}
CreateFrustum.prototype.clearOutline = function () {
if (this.outlinePrimitive) {
viewer.scene.primitives.remove(this.outlinePrimitive);
this.outlinePrimitive = null;
}
}
// 创建视锥体
CreateFrustum.prototype.addFrustum = function () {
// 创建视锥
let frustum = new Cesium.PerspectiveFrustum({
fov: Cesium.Math.toRadians(this.fov),
aspectRatio: this.aspectRatio,
near: this.near,
far: this.far,
});
// 创建视锥几何数据
let geometry = new Cesium.FrustumGeometry({
frustum: frustum,
origin: this.position,
orientation: this.orientation,
vertexFormat: Cesium.VertexFormat.POSITION_ONLY,
});
// 创建实例
let instance = new Cesium.GeometryInstance({
geometry: geometry,
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
new Cesium.Color(1.0, 1.0, 1.0, 0.2)
),
},
});
let primitive = new Cesium.Primitive({
geometryInstances: instance,
appearance: new Cesium.PerInstanceColorAppearance({
closed: true,
flat: true,
}),
asynchronous: false,
});
this.frustumPrimitive = viewer.scene.primitives.add(primitive);
}
// 创建视锥边框
CreateFrustum.prototype.addOutline = function () {
let frustum = new Cesium.PerspectiveFrustum({
fov: Cesium.Math.toRadians(this.fov),
aspectRatio: this.aspectRatio,
near: this.near,
far: this.far,
});
let geometry = new Cesium.FrustumOutlineGeometry({
frustum: frustum,
origin: this.position,
orientation: this.orientation,
vertexFormat: Cesium.VertexFormat.POSITION_ONLY,
});
let instance = new Cesium.GeometryInstance({
geometry: geometry,
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
new Cesium.Color(0.0, 1.0, 1.0, 1.0)
),
},
});
let primitive = new Cesium.Primitive({
geometryInstances: instance,
appearance: new Cesium.PerInstanceColorAppearance({
closed: true,
flat: true,
}),
asynchronous: false,
});
this.outlinePrimitive = viewer.scene.primitives.add(primitive);
}
let createFrustum, stopAnimation;
function addFrustum() {
stopAnimation = undefined;
// 创建视点
let origin = Cesium.Cartesian3.fromDegrees(120, 30, 1000000);
let heading = 340;
let pitch = 0;
let roll = 130;
let hpr = new Cesium.HeadingPitchRoll(
Cesium.Math.toRadians(heading), pitch, Cesium.Math.toRadians(roll));
let orientation = Cesium.Quaternion.fromHeadingPitchRoll(hpr);
// 创建视锥体
createFrustum = new CreateFrustum({
position: origin,
orientation: orientation,
fov: 20,
near: 1,
far: 1000000,
aspectRatio: 1080 / 1080,
});
let flag = false;
// 创建视锥动画
function Animation(){
if(stopAnimation){
return;
}
if (flag) {
roll += 0.2;
} else {
roll -= 0.2;
}
// 设置角度范围
if (roll < 125) {
flag = true;
} else if (roll > 135) {
flag = false;
}
// 修改视锥姿态
hpr = new Cesium.HeadingPitchRoll(heading, pitch, Cesium.Math.toRadians(roll))
orientation = Cesium.Quaternion.fromHeadingPitchRoll(hpr);
createFrustum.update(origin, orientation);
requestAnimationFrame(Animation)
}
requestAnimationFrame(Animation)
// 视角定位
viewer.camera.flyTo({
destination: origin,
});
}
addFrustum();
function clearFunc(){
createFrustum && createFrustum.clear();
createFrustum = undefined;
stopAnimation = true;
}
</script>
</body>
</html>