Appearance
视频投放
ts
import { Viewer, VideoShadow } from "joDVF";
import {
Cartesian3,
Math as CesiumMath,
JulianDate,
ClassificationType,
ClockRange,
ShadowMode,
Transforms,
HeadingPitchRoll,
VelocityOrientationProperty,
SampledPositionProperty,
Color,
Cartographic,
PolylineGlowMaterialProperty,
TimeIntervalCollection,
TimeInterval
} from "joCesium";
import { Pane } from "tweakpane";
const { mapContainer, uiContainer } = createContainer();
const viewer = new Viewer(mapContainer);
const scene = viewer.scene;
scene.globe.depthTestAgainstTerrain = true;
let gltfModel;
let videoShaderInstance;
viewer.camera.flyTo({
destination: Cartesian3.fromDegrees(108.979413027, 34.3397688922, 7890.5),
orientation: {
heading: CesiumMath.toRadians(175.0),
pitch: CesiumMath.toRadians(-20.0),
roll: 0.0
},
complete: () => {
videoShaderInstance = new VideoShadow(viewer, {
id: "videoShaderLayer",
position: [108.959413027, 34.2197688922, 2487.8386],
fov: 90,
near: 130,
far: 2736.8386,
pitch: -92.5,
url: "./assets/video/op.mp4",
rotation: {
pitch: -92.5,
yaw: 0
},
alpha: 1,
debugFrustum: true,
classificationType: ClassificationType.BOTH,
isOutputTexture: false
});
}
});
const start = JulianDate.fromDate(new Date(2023, 2, 25, 16));
const stop = JulianDate.addSeconds(start, 360, new JulianDate());
CesiumMath.setRandomNumberSeed(3);
viewer.clock.startTime = start.clone();
viewer.clock.stopTime = stop.clone();
viewer.clock.currentTime = start.clone();
viewer.clock.clockRange = ClockRange.LOOP_STOP; // Loop at the end
viewer.clock.multiplier = 10;
addUI(uiContainer);
addModel();
addPath();
function addModel() {
//模型加载 by entity
gltfModel = viewer.entities.add({
orientation: Transforms.headingPitchRollQuaternion(
Cartesian3.fromDegrees(108.959413027, 34.2197688922, 2587.8386),
new HeadingPitchRoll(
CesiumMath.toRadians(-90), // 顺时针旋转的角度值
CesiumMath.toRadians(180),
CesiumMath.toRadians(0)
)
),
position: Cartesian3.fromDegrees(108.959413027, 34.2197688922, 2587.8386), //模型的加载位置,
model: {
uri: "./assets/model/glb/15-0.glb",
scale: 0.5,
incrementallyLoadTextures: true,
runAnimations: true,
clampAnimations: true,
eyeOffset: new Cartesian3(0, 0, -10000),
disableDepthTestDistance: Number.POSITIVE_INFINITY,
shadows: ShadowMode.DISABLED,
show: true
}
});
}
function addPath() {
const position = computeCirclularFlight(108.959413027, 34.2197688922, 0.03);
viewer.entities.add({
availability: new TimeIntervalCollection([
new TimeInterval({
start: start,
stop: stop
})
]),
position,
orientation: new VelocityOrientationProperty(position),
path: {
resolution: 1,
material: new PolylineGlowMaterialProperty({
glowPower: 0.1,
color: Color.YELLOW
}),
width: 10
}
});
}
function createContainer() {
const container = document.createElement("div");
container.style.width = "100%";
container.style.height = "100%";
const uiContainer = document.createElement("div");
uiContainer.style.position = "fixed";
uiContainer.style.top = "5px";
uiContainer.style.left = "5px";
document.body.appendChild(container);
document.body.appendChild(uiContainer);
const img = document.createElement("img");
img.id = "put_img";
img.style.position = "fixed";
img.style.bottom = "5px";
img.style.left = "5px";
img.style.width = "200px";
img.style.height = "200px";
document.body.appendChild(img);
return {
mapContainer: container,
uiContainer
};
}
function addUI(uiContainer) {
const PARAMS = {
videoPlay: false,
isShowDebugFrustum: true,
opacity: 1,
fov: 90,
yaw: 0,
pitch: -92.5,
near: 130,
far: 2736.8386,
position: [108.959413027, 34.2197688922, 2487.8386],
show: true,
isOutputTexture: false
};
const pane = new Pane({
container: uiContainer,
title: "参数"
});
// opacity
pane.addBinding(PARAMS, "opacity", {
step: 0.1,
min: 0.1,
max: 1
});
// fov
pane.addBinding(PARAMS, "fov", {
step: 1,
min: 0.1,
max: 180
});
// yaw
pane.addBinding(PARAMS, "yaw", {
step: 1,
min: -180,
max: 180
});
// pitch
pane.addBinding(PARAMS, "pitch", {
step: 0.5,
min: -180,
max: 180
});
// far
pane.addBinding(PARAMS, "far", {
step: 0.1,
min: 0.1,
max: 10000
});
pane.addBinding(PARAMS, "videoPlay");
pane.addBinding(PARAMS, "isShowDebugFrustum");
pane.addBinding(PARAMS, "isOutputTexture");
pane.addBinding(PARAMS, "show", {
label: "是否显示"
});
// 改变飞机位置
const changePositionBtn = pane.addButton({
title: "change",
label: "改变飞机位置" // optional
});
changePositionBtn.on("click", () => {
// Compute the entity position property.
const position = computeCirclularFlight(108.959413027, 34.2197688922, 0.03);
gltfModel.position = position;
gltfModel.orientation = new VelocityOrientationProperty(position);
// pathEntity.position = position
// pathEntity.orientation = new VelocityOrientationProperty(position)
viewer.clock.onTick.addEventListener((clock) => {
const cartesian = position.getValue(clock.currentTime);
if (!cartesian) {
return;
}
if (!videoShaderInstance) return;
const cartographic = Cartographic.fromCartesian(cartesian);
videoShaderInstance.position = [
CesiumMath.toDegrees(cartographic.longitude),
CesiumMath.toDegrees(cartographic.latitude),
cartographic.height
];
const q = gltfModel.orientation.getValue(clock.currentTime);
const pitch = Math.atan2(
2 * q.x * q.w - 2 * q.y * q.z,
1 - 2 * q.x * q.x - 2 * q.z * q.z
);
const yaw = Math.atan2(
2 * q.y * q.w - 2 * q.x * q.z,
1 - 2 * q.y * q.y - 2 * q.z * q.z
);
const roll = Math.asin(2 * q.x * q.y + 2 * q.z * q.w);
videoShaderInstance.yaw = CesiumMath.toDegrees(-roll + 90);
if (PARAMS.isOutputTexture) {
if (videoShaderInstance.reflectionImageData) {
// const canvas = document.getElementById("canvas-cap");
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = videoShaderInstance.reflectionImageData.width;
canvas.height = videoShaderInstance.reflectionImageData.height;
ctx &&
ctx.putImageData(videoShaderInstance.reflectionImageData, 0, 0);
const image = document.getElementById("put_img");
if (image) {
(image as HTMLImageElement).src = canvas.toDataURL();
image.style.display = "block";
}
}
}
});
});
// 获取参数
const btn = pane.addButton({
title: "获取参数",
label: "参数" // optional
});
btn.on("click", () => {
console.info("控制台已打印参数");
console.log(PARAMS);
});
// 销毁对象
const destoryBtn = pane.addButton({
title: "destroy",
label: "销毁对象" // optional
});
destoryBtn.on("click", () => {
if (videoShaderInstance) {
videoShaderInstance.destroy();
videoShaderInstance = null;
}
});
pane.on("change", (ev) => {
let timer: NodeJS.Timeout | null = null;
if (timer) {
clearTimeout(timer);
timer = null;
}
timer = setTimeout(() => {
console.log("changed: " + JSON.stringify(ev.value), ev);
if (videoShaderInstance) {
videoShaderInstance[ev.target.key] = ev.value;
}
}, 300);
});
}
function computeCirclularFlight(lon, lat, radius) {
const property = new SampledPositionProperty();
for (let i = 0; i <= 360; i += 45) {
const radians = CesiumMath.toRadians(i);
const time = JulianDate.addSeconds(start, i, new JulianDate());
const position = Cartesian3.fromDegrees(
lon + radius * 1.5 * Math.cos(radians),
lat + radius * Math.sin(radians),
2480.8386
);
property.addSample(time, position);
// Also create a point for each sample we generate.
viewer.entities.add({
position: position,
point: {
pixelSize: 8,
color: Color.TRANSPARENT,
outlineColor: Color.YELLOW,
outlineWidth: 3
}
});
}
return property;
}
