<!DOCTYPE html>
|
<html lang="en">
|
|
<head>
|
<meta charset="UTF-8">
|
<title>Cesium 视频投影 + 视椎体控制</title>
|
|
<script src="./Build/Cesium.js"></script>
|
<script src="./ZLMRTCClient.js"></script>
|
|
<script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
|
|
<link href="https://cdn.bootcdn.net/ajax/libs/video.js/5.15.0/video-js.css" rel="stylesheet">
|
<script src="https://cdn.bootcdn.net/ajax/libs/video.js/5.15.0/video.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/videojs-contrib-hls/5.15.0/videojs-contrib-hls.min.js"
|
type="text/javascript"></script>
|
|
<style>
|
@import url(./Build/Widgets/widgets.css);
|
|
html,
|
body,
|
#cesiumContainer {
|
width: 100%;
|
height: 100%;
|
margin: 0;
|
padding: 0;
|
overflow: hidden;
|
}
|
|
.toolbar {
|
position: absolute;
|
top: 10px;
|
left: 10px;
|
background: rgba(42, 42, 42, 0.8);
|
padding: 10px;
|
border-radius: 5px;
|
color: white;
|
font-family: sans-serif;
|
z-index: 999;
|
}
|
|
.toolbar button {
|
margin: 2px;
|
}
|
</style>
|
</head>
|
|
<body>
|
<div id="cesiumContainer"></div>
|
<div class="toolbar">
|
<div>
|
<button onclick="adjustPos(0.0005,0)">东移</button>
|
<button onclick="adjustPos(-0.0005,0)">西移</button>
|
<button onclick="adjustPos(0,0.0005)">北移</button>
|
<button onclick="adjustPos(0,-0.0005)">南移</button>
|
</div>
|
<div>
|
<button onclick="adjustHeight(5)">升高</button>
|
<button onclick="adjustHeight(-5)">降低</button>
|
</div>
|
<div>
|
<button onclick="adjustHeading(5)">左转</button>
|
<button onclick="adjustHeading(-5)">右转</button>
|
</div>
|
<div>
|
<button onclick="adjustPitch(5)">抬头</button>
|
<button onclick="adjustPitch(-5)">低头</button>
|
</div>
|
<div>
|
<button onclick="adjustRoll(5)">左倾</button>
|
<button onclick="adjustRoll(-5)">右倾</button>
|
</div>
|
</div>
|
|
<script>
|
const viewer = new Cesium.Viewer("cesiumContainer", {
|
shadows: true,
|
terrain: Cesium.Terrain.fromWorldTerrain()
|
})
|
viewer.scene.globe.depthTestAgainstTerrain = true
|
|
let pos = { lon: 113.5, lat: 23.5, height: 100 }
|
let att = { heading: 0, pitch: -20, roll: 0 }
|
|
// 视频元素
|
const videoElement = document.createElement('video')
|
videoElement.src = './5b49f586a6ad3.mp4' // 你的视频路径
|
videoElement.autoplay = true
|
videoElement.loop = true
|
videoElement.muted = true
|
videoElement.playsInline = true
|
videoElement.crossOrigin = "anonymous"
|
|
let videoTex = null
|
let shadowMap = null
|
|
videoElement.addEventListener('loadeddata', () => {
|
if (videoElement.videoWidth > 0 && videoElement.videoHeight > 0) {
|
// 创建视频纹理
|
videoTex = new Cesium.Texture({
|
context: viewer.scene.context,
|
source: videoElement
|
})
|
createProjection()
|
}
|
})
|
|
function createProjection () {
|
const scene = viewer.scene
|
|
// 创建视椎体
|
const frustum = new Cesium.PerspectiveFrustum({
|
fov: Cesium.Math.toRadians(40),
|
aspectRatio: videoElement.videoWidth / videoElement.videoHeight,
|
near: 1.0,
|
far: 500.0
|
})
|
|
const frustumEntity = viewer.entities.add({
|
position: Cesium.Cartesian3.fromDegrees(pos.lon, pos.lat, pos.height),
|
orientation: Cesium.Transforms.headingPitchRollQuaternion(
|
Cesium.Cartesian3.fromDegrees(pos.lon, pos.lat, pos.height),
|
Cesium.HeadingPitchRoll.fromDegrees(att.heading, att.pitch, att.roll)
|
),
|
viewFrustum: {
|
frustum: frustum,
|
originColor: Cesium.Color.YELLOW,
|
farOpacity: 0.1
|
}
|
})
|
|
// 光源相机
|
const lightCamera = new Cesium.Camera(scene)
|
updateLightCamera(lightCamera)
|
|
// 创建 ShadowMap
|
shadowMap = new Cesium.ShadowMap({
|
context: scene.context,
|
lightCamera: lightCamera,
|
enabled: true,
|
isPointLight: false,
|
pointLightRadius: 100.0,
|
cascadesEnabled: false,
|
size: 1024
|
})
|
scene.shadowMaps = shadowMap
|
|
// 检查时间对象是否可用
|
const currentTime = viewer.clock && viewer.clock.currentTime
|
if (!currentTime) {
|
console.error("Error: viewer.clock.currentTime is undefined!")
|
return // 如果 time 不可用,则退出函数
|
}
|
|
// 创建 PostProcessStage,限制视频只投影到视椎体远端面
|
const stage = new Cesium.PostProcessStage({
|
fragmentShader: `
|
uniform sampler2D shadowMap_texture;
|
uniform sampler2D videoTexture;
|
uniform sampler2D colorTexture;
|
uniform mat4 frustumModelMatrix;
|
|
in vec2 v_textureCoordinates;
|
|
out vec4 fragColor;
|
|
void main() {
|
vec4 color = texture(colorTexture, v_textureCoordinates);
|
vec4 proj = texture(videoTexture, v_textureCoordinates);
|
|
// 通过视椎体的矩阵来判断是否在远端面区域内
|
vec4 transformedCoords = frustumModelMatrix * vec4(v_textureCoordinates, 0.0, 1.0);
|
if (transformedCoords.z > 0.0) {
|
fragColor = mix(color, proj, 0.7); // 在远端面显示视频
|
} else {
|
fragColor = color; // 其他区域保留原场景颜色
|
}
|
}
|
`,
|
uniforms: {
|
shadowMap_texture: () => shadowMap._shadowMapTexture,
|
videoTexture: () => videoTex || Cesium.Texture.create({
|
context: viewer.scene.context,
|
width: 1, height: 1,
|
pixelFormat: Cesium.PixelFormat.RGBA
|
}),
|
frustumModelMatrix: () => frustumEntity.computeModelMatrix(), // 传递视椎体的矩阵
|
time: () => currentTime // 确保传递正确的时间对象
|
}
|
})
|
scene.postProcessStages.add(stage)
|
|
// 每帧更新视频纹理和光源相机
|
scene.preRender.addEventListener(() => {
|
if (videoTex && !videoElement.paused) {
|
videoTex.copyFrom(videoElement)
|
}
|
updateLightCamera(lightCamera)
|
})
|
}
|
|
function updateLightCamera (cam) {
|
const cart = Cesium.Cartesian3.fromDegrees(pos.lon, pos.lat, pos.height)
|
cam.position = cart.clone()
|
cam.direction = Cesium.Cartesian3.negate(Cesium.Cartesian3.UNIT_Z, new Cesium.Cartesian3())
|
cam.up = Cesium.Cartesian3.clone(Cesium.Cartesian3.UNIT_Y)
|
cam.frustum.fov = Cesium.Math.toRadians(40)
|
cam.frustum.aspectRatio = videoElement.videoWidth / videoElement.videoHeight
|
cam.frustum.near = 1.0
|
cam.frustum.far = 500.0
|
cam.setView({
|
destination: cart,
|
orientation: {
|
heading: Cesium.Math.toRadians(att.heading),
|
pitch: Cesium.Math.toRadians(att.pitch),
|
roll: Cesium.Math.toRadians(att.roll)
|
}
|
})
|
}
|
|
// 控制函数
|
function adjustPos (dLon, dLat) {
|
pos.lon += dLon
|
pos.lat += dLat
|
}
|
function adjustHeight (dH) {
|
pos.height += dH
|
}
|
function adjustHeading (d) {
|
att.heading += d
|
}
|
function adjustPitch (d) {
|
att.pitch += d
|
}
|
function adjustRoll (d) {
|
att.roll += d
|
}
|
</script>
|
</body>
|
|
</html>
|