897 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			897 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| const _object_pattern = /^[og]\s*(.+)?/;
 | |
| const _material_library_pattern = /^mtllib /;
 | |
| const _material_use_pattern = /^usemtl /;
 | |
| const _map_use_pattern = /^usemap /;
 | |
| const _face_vertex_data_separator_pattern = /\s+/;
 | |
| 
 | |
| const _color = new Cesium.Color();
 | |
| 
 | |
| function ParserState() {
 | |
|     const state = {
 | |
|         objects: [],
 | |
|         object: {},
 | |
| 
 | |
|         vertices: [],
 | |
|         normals: [],
 | |
|         colors: [],
 | |
|         uvs: [],
 | |
| 
 | |
|         materials: {},
 | |
|         materialLibraries: [],
 | |
| 
 | |
|         startObject: function (name, fromDeclaration) {
 | |
|             if (this.object && this.object.fromDeclaration === false) {
 | |
|                 this.object.name = name;
 | |
|                 this.object.fromDeclaration = (fromDeclaration !== false);
 | |
|                 return;
 | |
|             }
 | |
|             const previousMaterial = (this.object && typeof this.object.currentMaterial === 'function' ? this.object.currentMaterial() : undefined);
 | |
|             if (this.object && typeof this.object._finalize === 'function') {
 | |
|                 this.object._finalize(true);
 | |
|             }
 | |
|             this.object = {
 | |
|                 name: name || '',
 | |
|                 fromDeclaration: (fromDeclaration !== false),
 | |
| 
 | |
|                 geometry: {
 | |
|                     vertices: [],
 | |
|                     normals: [],
 | |
|                     colors: [],
 | |
|                     uvs: [],
 | |
|                     hasUVIndices: false
 | |
|                 },
 | |
|                 materials: [],
 | |
|                 smooth: true,
 | |
| 
 | |
|                 startMaterial: function (name, libraries) {
 | |
|                     const previous = this._finalize(false);
 | |
|                     if (previous && (previous.inherited || previous.groupCount <= 0)) {
 | |
|                         this.materials.splice(previous.index, 1);
 | |
|                     }
 | |
|                     const material = {
 | |
|                         index: this.materials.length,
 | |
|                         name: name || '',
 | |
|                         mtllib: (Array.isArray(libraries) && libraries.length > 0 ? libraries[libraries.length - 1] : ''),
 | |
|                         smooth: (previous !== undefined ? previous.smooth : this.smooth),
 | |
|                         groupStart: (previous !== undefined ? previous.groupEnd : 0),
 | |
|                         groupEnd: -1,
 | |
|                         groupCount: -1,
 | |
|                         inherited: false,
 | |
|                         clone: function (index) {
 | |
|                             const cloned = {
 | |
|                                 index: (typeof index === 'number' ? index : this.index),
 | |
|                                 name: this.name,
 | |
|                                 mtllib: this.mtllib,
 | |
|                                 smooth: this.smooth,
 | |
|                                 groupStart: 0,
 | |
|                                 groupEnd: -1,
 | |
|                                 groupCount: -1,
 | |
|                                 inherited: false
 | |
|                             };
 | |
|                             cloned.clone = this.clone.bind(cloned);
 | |
|                             return cloned;
 | |
|                         }
 | |
|                     };
 | |
|                     this.materials.push(material);
 | |
|                     return material;
 | |
|                 },
 | |
| 
 | |
|                 currentMaterial: function () {
 | |
|                     if (this.materials.length > 0) {
 | |
|                         return this.materials[this.materials.length - 1];
 | |
|                     }
 | |
|                     return undefined;
 | |
|                 },
 | |
| 
 | |
|                 _finalize: function (end) {
 | |
|                     const lastMultiMaterial = this.currentMaterial();
 | |
|                     if (lastMultiMaterial && lastMultiMaterial.groupEnd === -1) {
 | |
|                         lastMultiMaterial.groupEnd = this.geometry.vertices.length / 3;
 | |
|                         lastMultiMaterial.groupCount = lastMultiMaterial.groupEnd - lastMultiMaterial.groupStart;
 | |
|                         lastMultiMaterial.inherited = false;
 | |
|                     }
 | |
| 
 | |
|                     if (end && this.materials.length > 1) {
 | |
|                         for (let mi = this.materials.length - 1; mi >= 0; mi--) {
 | |
|                             if (this.materials[mi].groupCount <= 0) {
 | |
|                                 this.materials.splice(mi, 1);
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
| 
 | |
|                     if (end && this.materials.length === 0) {
 | |
|                         this.materials.push({
 | |
|                             name: '',
 | |
|                             smooth: this.smooth
 | |
|                         });
 | |
|                     }
 | |
|                     return lastMultiMaterial;
 | |
|                 }
 | |
|             };
 | |
| 
 | |
|             if (previousMaterial && previousMaterial.name && typeof previousMaterial.clone === 'function') {
 | |
|                 const declared = previousMaterial.clone(0);
 | |
|                 declared.inherited = true;
 | |
|                 this.object.materials.push(declared);
 | |
|             }
 | |
|             this.objects.push(this.object);
 | |
|         },
 | |
|         finalize: function () {
 | |
|             if (this.object && typeof this.object._finalize === 'function') {
 | |
|                 this.object._finalize(true);
 | |
|             }
 | |
|         },
 | |
|         parseVertexIndex: function (value, len) {
 | |
|             const index = parseInt(value, 10);
 | |
|             return (index >= 0 ? index - 1 : index + len / 3) * 3;
 | |
|         },
 | |
|         parseNormalIndex: function (value, len) {
 | |
|             const index = parseInt(value, 10);
 | |
|             return (index >= 0 ? index - 1 : index + len / 3) * 3;
 | |
|         },
 | |
|         parseUVIndex: function (value, len) {
 | |
|             const index = parseInt(value, 10);
 | |
|             return (index >= 0 ? index - 1 : index + len / 2) * 2;
 | |
|         },
 | |
|         addVertex: function (a, b, c) {
 | |
|             const src = this.vertices;
 | |
|             const dst = this.object.geometry.vertices;
 | |
|             dst.push(src[a + 0], src[a + 1], src[a + 2]);
 | |
|             dst.push(src[b + 0], src[b + 1], src[b + 2]);
 | |
|             dst.push(src[c + 0], src[c + 1], src[c + 2]);
 | |
|         },
 | |
|         addVertexPoint: function (a) {
 | |
|             const src = this.vertices;
 | |
|             const dst = this.object.geometry.vertices;
 | |
| 
 | |
|             dst.push(src[a + 0], src[a + 1], src[a + 2]);
 | |
|         },
 | |
|         addVertexLine: function (a) {
 | |
|             const src = this.vertices;
 | |
|             const dst = this.object.geometry.vertices;
 | |
|             dst.push(src[a + 0], src[a + 1], src[a + 2]);
 | |
|         },
 | |
|         addNormal: function (a, b, c) {
 | |
|             const src = this.normals;
 | |
|             const dst = this.object.geometry.normals;
 | |
| 
 | |
|             dst.push(src[a + 0], src[a + 1], src[a + 2]);
 | |
|             dst.push(src[b + 0], src[b + 1], src[b + 2]);
 | |
|             dst.push(src[c + 0], src[c + 1], src[c + 2]);
 | |
|         },
 | |
|         addFaceNormal: function (a, b, c) {
 | |
|             console.warn("addFaceNormal");
 | |
|             // const src = this.vertices;
 | |
|             // const dst = this.object.geometry.normals;
 | |
| 
 | |
|             // _vA.fromArray( src, a );
 | |
|             // _vB.fromArray( src, b );
 | |
|             // _vC.fromArray( src, c );
 | |
| 
 | |
|             // _cb.subVectors( _vC, _vB );
 | |
|             // _ab.subVectors( _vA, _vB );
 | |
|             // _cb.cross( _ab );
 | |
| 
 | |
|             // _cb.normalize();
 | |
| 
 | |
|             // dst.push( _cb.x, _cb.y, _cb.z );
 | |
|             // dst.push( _cb.x, _cb.y, _cb.z );
 | |
|             // dst.push( _cb.x, _cb.y, _cb.z );
 | |
|         },
 | |
|         addColor: function (a, b, c) {
 | |
|             const src = this.colors;
 | |
|             const dst = this.object.geometry.colors;
 | |
|             if (src[a] !== undefined) dst.push(src[a + 0], src[a + 1], src[a + 2]);
 | |
|             if (src[b] !== undefined) dst.push(src[b + 0], src[b + 1], src[b + 2]);
 | |
|             if (src[c] !== undefined) dst.push(src[c + 0], src[c + 1], src[c + 2]);
 | |
|         },
 | |
|         addUV: function (a, b, c) {
 | |
|             const src = this.uvs;
 | |
|             const dst = this.object.geometry.uvs;
 | |
|             dst.push(src[a + 0], src[a + 1]);
 | |
|             dst.push(src[b + 0], src[b + 1]);
 | |
|             dst.push(src[c + 0], src[c + 1]);
 | |
|         },
 | |
|         addDefaultUV: function () {
 | |
|             const dst = this.object.geometry.uvs;
 | |
|             dst.push(0, 0);
 | |
|             dst.push(0, 0);
 | |
|             dst.push(0, 0);
 | |
|         },
 | |
|         addUVLine: function (a) {
 | |
|             const src = this.uvs;
 | |
|             const dst = this.object.geometry.uvs;
 | |
|             dst.push(src[a + 0], src[a + 1]);
 | |
|         },
 | |
|         addFace: function (a, b, c, ua, ub, uc, na, nb, nc) {
 | |
|             const vLen = this.vertices.length;
 | |
|             let ia = this.parseVertexIndex(a, vLen);
 | |
|             let ib = this.parseVertexIndex(b, vLen);
 | |
|             let ic = this.parseVertexIndex(c, vLen);
 | |
|             this.addVertex(ia, ib, ic);
 | |
|             this.addColor(ia, ib, ic);
 | |
|             if (na !== undefined && na !== '') {
 | |
|                 const nLen = this.normals.length;
 | |
|                 ia = this.parseNormalIndex(na, nLen);
 | |
|                 ib = this.parseNormalIndex(nb, nLen);
 | |
|                 ic = this.parseNormalIndex(nc, nLen);
 | |
|                 this.addNormal(ia, ib, ic);
 | |
|             } else {
 | |
|                 this.addFaceNormal(ia, ib, ic);
 | |
|             }
 | |
|             if (ua !== undefined && ua !== '') {
 | |
|                 const uvLen = this.uvs.length;
 | |
|                 ia = this.parseUVIndex(ua, uvLen);
 | |
|                 ib = this.parseUVIndex(ub, uvLen);
 | |
|                 ic = this.parseUVIndex(uc, uvLen);
 | |
|                 this.addUV(ia, ib, ic);
 | |
|                 this.object.geometry.hasUVIndices = true;
 | |
|             } else {
 | |
|                 this.addDefaultUV();
 | |
|             }
 | |
|         },
 | |
|         addPointGeometry: function (vertices) {
 | |
|             this.object.geometry.type = 'Points';
 | |
|             const vLen = this.vertices.length;
 | |
|             for (let vi = 0, l = vertices.length; vi < l; vi++) {
 | |
|                 const index = this.parseVertexIndex(vertices[vi], vLen);
 | |
|                 this.addVertexPoint(index);
 | |
|                 this.addColor(index);
 | |
|             }
 | |
|         },
 | |
|         addLineGeometry: function (vertices, uvs) {
 | |
|             this.object.geometry.type = 'Line';
 | |
|             const vLen = this.vertices.length;
 | |
|             const uvLen = this.uvs.length;
 | |
|             for (let vi = 0, l = vertices.length; vi < l; vi++) {
 | |
|                 this.addVertexLine(this.parseVertexIndex(vertices[vi], vLen));
 | |
|             }
 | |
|             for (let uvi = 0, l = uvs.length; uvi < l; uvi++) {
 | |
|                 this.addUVLine(this.parseUVIndex(uvs[uvi], uvLen));
 | |
|             }
 | |
|         }
 | |
|     };
 | |
|     state.startObject('', false);
 | |
|     return state;
 | |
| }
 | |
| 
 | |
| class AModelLoader {
 | |
|     constructor(context) {
 | |
|         this.context = context;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * 异步调用
 | |
|      * @param {*} url
 | |
|      */
 | |
|     Load(url) {
 | |
|         //解析obj数据
 | |
|         return Cesium.Resource.fetchText(url).then((result) => {
 | |
|             return this.Parse(result, url.substring(0, url.lastIndexOf('/') + 1));
 | |
|         });
 | |
|     }
 | |
| 
 | |
|     Parse(text, path) {
 | |
|         const state = new ParserState();
 | |
|         if (text.indexOf('\r\n') !== -1) {
 | |
|             text = text.replace(/\r\n/g, '\n');
 | |
|         }
 | |
|         if (text.indexOf('\\\n') !== -1) {
 | |
|             text = text.replace(/\\\n/g, '');
 | |
|         }
 | |
|         const lines = text.split('\n');
 | |
|         let result = [];
 | |
|         for (let i = 0, l = lines.length; i < l; i++) {
 | |
|             const line = lines[i].trimStart();
 | |
|             if (line.length === 0) continue;
 | |
|             const lineFirstChar = line.charAt(0);
 | |
|             if (lineFirstChar === '#') continue;
 | |
|             if (lineFirstChar === 'v') {
 | |
|                 const data = line.split(_face_vertex_data_separator_pattern);
 | |
|                 switch (data[0]) {
 | |
|                     case 'v':
 | |
|                         state.vertices.push(
 | |
|                             parseFloat(data[1]),
 | |
|                             parseFloat(data[2]),
 | |
|                             parseFloat(data[3])
 | |
|                         );
 | |
|                         if (data.length >= 7) {
 | |
|                             Cesium.Color.fromBytes(
 | |
|                                 parseFloat(data[4]),
 | |
|                                 parseFloat(data[5]),
 | |
|                                 parseFloat(data[6]),
 | |
|                                 1,
 | |
|                                 _color
 | |
|                             );
 | |
|                             state.colors.push(_color.red, _color.green, _color.blue);
 | |
|                         } else {
 | |
|                             state.colors.push(undefined, undefined, undefined);
 | |
|                         }
 | |
|                         break;
 | |
|                     case 'vn':
 | |
|                         state.normals.push(
 | |
|                             parseFloat(data[1]),
 | |
|                             parseFloat(data[2]),
 | |
|                             parseFloat(data[3])
 | |
|                         );
 | |
|                         break;
 | |
|                     case 'vt':
 | |
|                         state.uvs.push(
 | |
|                             parseFloat(data[1]),
 | |
|                             parseFloat(data[2])
 | |
|                         );
 | |
|                         break;
 | |
|                 }
 | |
| 
 | |
|             } else if (lineFirstChar === 'f') {
 | |
|                 const lineData = line.slice(1).trim();
 | |
|                 const vertexData = lineData.split(_face_vertex_data_separator_pattern);
 | |
|                 const faceVertices = [];
 | |
|                 for (let j = 0, jl = vertexData.length; j < jl; j++) {
 | |
|                     const vertex = vertexData[j];
 | |
|                     if (vertex.length > 0) {
 | |
|                         const vertexParts = vertex.split('/');
 | |
|                         faceVertices.push(vertexParts);
 | |
|                     }
 | |
|                 }
 | |
|                 const v1 = faceVertices[0];
 | |
|                 for (let j = 1, jl = faceVertices.length - 1; j < jl; j++) {
 | |
|                     const v2 = faceVertices[j];
 | |
|                     const v3 = faceVertices[j + 1];
 | |
|                     state.addFace(
 | |
|                         v1[0], v2[0], v3[0],
 | |
|                         v1[1], v2[1], v3[1],
 | |
|                         v1[2], v2[2], v3[2]
 | |
|                     );
 | |
|                 }
 | |
|             } else if (lineFirstChar === 'l') {
 | |
|                 const lineParts = line.substring(1).trim().split(' ');
 | |
|                 let lineVertices = [];
 | |
|                 const lineUVs = [];
 | |
|                 if (line.indexOf('/') === -1) {
 | |
|                     lineVertices = lineParts;
 | |
|                 } else {
 | |
|                     for (let li = 0, llen = lineParts.length; li < llen; li++) {
 | |
|                         const parts = lineParts[li].split('/');
 | |
|                         if (parts[0] !== '') lineVertices.push(parts[0]);
 | |
|                         if (parts[1] !== '') lineUVs.push(parts[1]);
 | |
|                     }
 | |
|                 }
 | |
|                 state.addLineGeometry(lineVertices, lineUVs);
 | |
|             } else if (lineFirstChar === 'p') {
 | |
|                 const lineData = line.slice(1).trim();
 | |
|                 const pointData = lineData.split(' ');
 | |
|                 state.addPointGeometry(pointData);
 | |
|             } else if ((result = _object_pattern.exec(line)) !== null) {
 | |
|                 const name = (' ' + result[0].slice(1).trim()).slice(1);
 | |
|                 state.startObject(name);
 | |
|             } else if (_material_use_pattern.test(line)) {
 | |
|                 state.object.startMaterial(line.substring(7).trim(), state.materialLibraries);
 | |
|             } else if (_material_library_pattern.test(line)) {
 | |
|                 state.materialLibraries.push(line.substring(7).trim());
 | |
|             } else if (_map_use_pattern.test(line)) {
 | |
|                 console.warn('Rendering identifier "usemap" not supported. Textures must be defined in MTL files.');
 | |
|             } else if (lineFirstChar === 's') {
 | |
|                 result = line.split(' ');
 | |
|                 if (result.length > 1) {
 | |
|                     const value = result[1].trim().toLowerCase();
 | |
|                     state.object.smooth = (value !== '0' && value !== 'off');
 | |
|                 } else {
 | |
|                     state.object.smooth = true;
 | |
|                 }
 | |
|                 const material = state.object.currentMaterial();
 | |
|                 if (material) material.smooth = state.object.smooth;
 | |
|             } else {
 | |
|                 if (line === '\0') continue;
 | |
|                 console.warn('Unexpected line: "' + line + '"');
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         state.finalize();
 | |
| 
 | |
|         const container = new Node();
 | |
|         const hasPrimitives = !(state.objects.length === 1 && state.objects[0].geometry.vertices.length === 0);
 | |
| 
 | |
|         if (hasPrimitives === true) {
 | |
|             for (let i = 0, l = state.objects.length; i < l; i++) {
 | |
|                 const object = state.objects[i];
 | |
|                 const geometry = object.geometry;
 | |
|                 const materials = object.materials;
 | |
|                 if (geometry.vertices.length === 0) continue;
 | |
| 
 | |
|                 let mesh = new Mesh(this.context, geometry);
 | |
|                 for (let mi = 0, miLen = materials.length; mi < miLen; mi++) {
 | |
|                     const sourceMaterial = materials[mi];
 | |
|                     const materialHash = sourceMaterial.name + '_' + sourceMaterial.smooth + '_';
 | |
|                     let material = state.materials[materialHash];
 | |
| 
 | |
|                     if (this.materials !== null) {
 | |
|                         console.log("material");
 | |
|                     }
 | |
| 
 | |
|                     if (material === undefined) {
 | |
|                         material = new Material(this.context, geometry, path, sourceMaterial.mtllib);
 | |
|                         material.name = sourceMaterial.name;
 | |
|                         material.flatShading = sourceMaterial.smooth ? false : true;
 | |
| 
 | |
|                         state.materials[materialHash] = material;
 | |
|                     }
 | |
|                     mesh.setMaterial(material);
 | |
|                 }
 | |
| 
 | |
|                 mesh.name = object.name;
 | |
| 
 | |
|                 container.add(mesh);
 | |
|             }
 | |
|         }
 | |
|         return container;
 | |
|     }
 | |
| 
 | |
| }
 | |
| 
 | |
| class Material {
 | |
|     constructor(context, geometry, path, mtllib) {
 | |
|         this.context = context;
 | |
|         this.ready = false;
 | |
| 
 | |
|         const canvas = document.createElement("canvas");
 | |
|         canvas.width = 512; //默认
 | |
|         canvas.height = 512; //默认
 | |
|         this.canvas = canvas;
 | |
| 
 | |
|         let promise = Cesium.Resource.fetchText(path + mtllib)
 | |
|             .then(async (text) => {
 | |
|                 let result = [];
 | |
|                 const lines = text.split('\n');
 | |
|                 for (let i = 0, l = lines.length; i < l; i++) {
 | |
|                     const line = lines[i].trimStart();
 | |
|                     if (line.length === 0) continue;
 | |
|                     const t = line.split(' ')[0];
 | |
|                     if (t === "map_Kd") {
 | |
|                         let map = line.split(' ')[1];
 | |
|                         result.push({
 | |
|                             diffusemap: await this.loadTexture(path + map)
 | |
|                         })
 | |
|                     }
 | |
|                 }
 | |
|                 return Promise.all(result);
 | |
|             });
 | |
| 
 | |
|         //创建shader
 | |
|         let vs = "attribute vec3 position;\n";
 | |
|         let fs = "";
 | |
| 
 | |
|         let outVS = "";
 | |
| 
 | |
|         let hasNormal = false;
 | |
|         let hasVertexColors = false;
 | |
|         let hasSt = false;
 | |
| 
 | |
|         if (geometry.normals.length > 0) {
 | |
|             hasNormal = true;
 | |
|         }
 | |
|         //顶点色
 | |
|         if (geometry.colors.length > 0) {
 | |
|             hasVertexColors = true;
 | |
|         }
 | |
|         // UV
 | |
|         if (geometry.hasUVIndices === true) {
 | |
|             hasSt = true;
 | |
|         }
 | |
| 
 | |
|         if (hasNormal) {
 | |
|             vs += "attribute vec3 normal;\n";
 | |
| 
 | |
|             vs += "varying vec3 v_normal;\n";
 | |
|             fs += "varying vec3 v_normal;\n";
 | |
|             outVS += "v_normal = normal;\n";
 | |
|         }
 | |
| 
 | |
|         if (hasVertexColors) {
 | |
|             vs += "attribute vec3 color;\n";
 | |
| 
 | |
|             vs += "varying vec2 v_color;\n";
 | |
|             fs += "varying vec2 v_color;\n";
 | |
|             outVS += "v_color = color;\n";
 | |
|         }
 | |
| 
 | |
|         if (hasSt) {
 | |
|             vs += "attribute vec2 uv;\n";
 | |
|             vs += "varying vec2 v_uv;\n";
 | |
| 
 | |
|             fs += "varying vec2 v_uv;\n";
 | |
|             outVS += "v_uv = uv;\n";
 | |
|         }
 | |
| 
 | |
|         vs += `
 | |
|         void main() {
 | |
|             gl_Position = czm_modelViewProjection * vec4(position, 1.);
 | |
|             ${outVS}
 | |
|         }
 | |
|         `;
 | |
| 
 | |
|         fs += `
 | |
| 		uniform sampler2D colorTexture;
 | |
|         void main() {
 | |
| 			vec4 color = texture2D(colorTexture, v_uv);
 | |
|             gl_FragColor = color;
 | |
|         }
 | |
|         `;
 | |
| 
 | |
|         this.program = Cesium.ShaderProgram.fromCache({
 | |
|             context: context,
 | |
|             vertexShaderSource: vs,
 | |
|             fragmentShaderSource: fs
 | |
|         });
 | |
| 
 | |
|         this.uniformMap = {};
 | |
| 
 | |
|         let that = this;
 | |
|         promise.then((images) => {
 | |
|             for (let i = 0; i < images.length; i++) {
 | |
|                 const element = images[i];
 | |
|                 let diffusemap = element.diffusemap;
 | |
|                 this.uniformMap.colorTexture = () => {
 | |
|                     return diffusemap;
 | |
|                 };
 | |
|             }
 | |
|             that.ready = true;
 | |
|         });
 | |
|     }
 | |
| 
 | |
|     updateColorTexture(video, width, height) {
 | |
|         if (this.ready && Cesium.defined(video.videojs)) {
 | |
|             video.videojs.play();
 | |
|             let colorTexture = this.uniformMap.colorTexture();
 | |
|             if (video.playing && video.timeupdate) {
 | |
|                 if (width !== colorTexture.width || height !== colorTexture.height) {
 | |
| 
 | |
|                     this.canvas.width = width;
 | |
|                     this.canvas.height = height;
 | |
| 
 | |
|                     // 重新创建texture
 | |
|                     const canvasContext = this.canvas.getContext("2d");
 | |
|                     canvasContext.drawImage(
 | |
|                         video.dom,
 | |
|                         0,
 | |
|                         0,
 | |
|                         video.width,
 | |
|                         video.height,
 | |
|                         0,
 | |
|                         0,
 | |
|                         this.canvas.width,
 | |
|                         this.canvas.height
 | |
|                     );
 | |
| 
 | |
|                     let texture = new Cesium.Texture({
 | |
|                         context: this.context,
 | |
|                         source: this.canvas
 | |
|                     });
 | |
| 
 | |
|                     this.uniformMap.colorTexture = () => {
 | |
|                         return texture;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 const canvasContext = this.canvas.getContext("2d");
 | |
|                 canvasContext.drawImage(
 | |
|                     video.dom,
 | |
|                     0,
 | |
|                     0,
 | |
|                     video.width,
 | |
|                     video.height,
 | |
|                     0,
 | |
|                     0,
 | |
|                     this.canvas.width,
 | |
|                     this.canvas.height
 | |
|                 );
 | |
|                 this.uniformMap.colorTexture().copyFrom({
 | |
|                     source: this.canvas
 | |
|                 });
 | |
| 
 | |
|             }
 | |
|         }
 | |
| 
 | |
|     }
 | |
| 
 | |
|     setCommand(drawCommand) {
 | |
|         drawCommand.shaderProgram = this.program;
 | |
|         drawCommand.uniformMap = this.uniformMap;
 | |
|     }
 | |
| 
 | |
|     loadTexture(url) {
 | |
|         return Cesium.Resource.fetchImage(url)
 | |
|             .then((image) => {
 | |
|                 this.canvas.width = image.width;
 | |
|                 this.canvas.height = image.height;
 | |
|                 const canvasContext = this.canvas.getContext("2d");
 | |
|                 canvasContext.drawImage(
 | |
|                     image,
 | |
|                     0,
 | |
|                     0,
 | |
|                     image.width,
 | |
|                     image.height,
 | |
|                     0,
 | |
|                     0,
 | |
|                     this.canvas.width,
 | |
|                     this.canvas.height,
 | |
|                 );
 | |
|                 let texture = new Cesium.Texture({
 | |
|                     context: this.context,
 | |
|                     source: this.canvas,
 | |
|                     sampler: Cesium.Sampler.NEAREST
 | |
|                 });
 | |
|                 return texture;
 | |
|             });
 | |
|     }
 | |
| }
 | |
| 
 | |
| class Mesh {
 | |
|     constructor(context, geometry) {
 | |
|         this.name = undefined;
 | |
|         this.geometry = geometry;
 | |
|         const vaAttributes = [];
 | |
|         let index = 0;
 | |
| 
 | |
|         this.material = undefined;
 | |
| 
 | |
|         //创建顶点索引
 | |
|         const vertexBuffer = Cesium.Buffer.createVertexBuffer({
 | |
|             context: context,
 | |
|             typedArray: Cesium.ComponentDatatype.createTypedArray(Cesium.ComponentDatatype.FLOAT, geometry.vertices),
 | |
|             usage: Cesium.BufferUsage.STATIC_DRAW
 | |
|         });
 | |
|         vaAttributes.push({
 | |
|             index: index,
 | |
|             enabled: true,
 | |
|             vertexBuffer: vertexBuffer,
 | |
|             componentDatatype: Cesium.ComponentDatatype.FLOAT,
 | |
|             componentsPerAttribute: 3,
 | |
|             normalize: false
 | |
|         });
 | |
|         //法线
 | |
|         if (geometry.normals.length > 0) {
 | |
|             index++;
 | |
|             const normalBuffer = Cesium.Buffer.createVertexBuffer({
 | |
|                 context: context,
 | |
|                 typedArray: Cesium.ComponentDatatype.createTypedArray(Cesium.ComponentDatatype.FLOAT, geometry.normals),
 | |
|                 usage: Cesium.BufferUsage.STATIC_DRAW
 | |
|             });
 | |
| 
 | |
|             vaAttributes.push({
 | |
|                 index: index,
 | |
|                 enabled: true,
 | |
|                 vertexBuffer: normalBuffer,
 | |
|                 componentDatatype: Cesium.ComponentDatatype.FLOAT,
 | |
|                 componentsPerAttribute: 3,
 | |
|                 normalize: false
 | |
|             });
 | |
|         }
 | |
|         //顶点色
 | |
|         if (geometry.colors.length > 0) {
 | |
|             index++;
 | |
|             const colorBuffer = Cesium.Buffer.createVertexBuffer({
 | |
|                 context: context,
 | |
|                 typedArray: Cesium.ComponentDatatype.createTypedArray(Cesium.ComponentDatatype.FLOAT, geometry.colors),
 | |
|                 usage: Cesium.BufferUsage.STATIC_DRAW
 | |
|             });
 | |
| 
 | |
|             vaAttributes.push({
 | |
|                 index: index,
 | |
|                 enabled: true,
 | |
|                 vertexBuffer: colorBuffer,
 | |
|                 componentDatatype: Cesium.ComponentDatatype.FLOAT,
 | |
|                 componentsPerAttribute: 3,
 | |
|                 normalize: false
 | |
|             });
 | |
|         }
 | |
|         // UV
 | |
|         if (geometry.hasUVIndices === true) {
 | |
|             index++;
 | |
|             const uvBuffer = Cesium.Buffer.createVertexBuffer({
 | |
|                 context: context,
 | |
|                 typedArray: Cesium.ComponentDatatype.createTypedArray(Cesium.ComponentDatatype.FLOAT, geometry.uvs),
 | |
|                 usage: Cesium.BufferUsage.STATIC_DRAW
 | |
|             });
 | |
| 
 | |
|             vaAttributes.push({
 | |
|                 index: index,
 | |
|                 enabled: true,
 | |
|                 vertexBuffer: uvBuffer,
 | |
|                 componentDatatype: Cesium.ComponentDatatype.FLOAT,
 | |
|                 componentsPerAttribute: 2,
 | |
|                 normalize: false
 | |
|             });
 | |
|         }
 | |
| 
 | |
|         const vertexArray = new Cesium.VertexArray({
 | |
|             context: context,
 | |
|             attributes: vaAttributes
 | |
|         });
 | |
| 
 | |
|         const renderState = Cesium.RenderState.fromCache({
 | |
|             cull: {
 | |
|                 enabled: false
 | |
|             },
 | |
|             depthMask: true,
 | |
|             depthTest: {
 | |
|                 enabled: true,
 | |
|             }
 | |
|         });
 | |
| 
 | |
|         this.drawCommand = new Cesium.DrawCommand({
 | |
|             owner: this,
 | |
|             primitiveType: Cesium.PrimitiveType.TRIANGLES,
 | |
|             vertexArray: vertexArray,
 | |
|             renderState: renderState,
 | |
|             pass: Cesium.Pass.OPAQUE,
 | |
|             // debugShowBoundingVolume: true
 | |
|         });
 | |
| 
 | |
|     }
 | |
| 
 | |
|     setMaterial(material) {
 | |
|         this.material = material;
 | |
|         material.setCommand(this.drawCommand);
 | |
|     }
 | |
| 
 | |
|     update(frameState) {
 | |
|         if (Cesium.defined(this.material)) {
 | |
|             if (this.material.ready) {
 | |
|                 frameState.commandList.push(this.drawCommand);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     updateVideo(camera, video, cullingVolume) {
 | |
|         if (Cesium.defined(this.material)) {
 | |
|             if (this.material.ready) {
 | |
|                 const visibility = cullingVolume.computeVisibility(this.drawCommand.boundingVolume);
 | |
|                 if (visibility >= 0 && this.material.ready) {
 | |
|                     //如果视频可见
 | |
|                     //计算level
 | |
|                     // cam
 | |
|                     let distance = camera.distanceToBoundingSphere(this.drawCommand.boundingVolume);
 | |
|                     let width = video.width;
 | |
|                     let height = video.height;
 | |
|                     if (distance >= 20 && distance < 100) {
 | |
|                         width = video.width / 2;
 | |
|                         height = video.height / 2;
 | |
|                     } else if (distance >= 100) {
 | |
|                         width = video.width / 10;
 | |
|                         height = video.height / 10;
 | |
|                     }
 | |
|                     this.material.updateColorTexture(video, width, height)
 | |
|                 } else {
 | |
|                     if (video.videojs) {
 | |
|                         video.videojs.pause();
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|     }
 | |
| 
 | |
| }
 | |
| 
 | |
| class Node {
 | |
|     constructor() {
 | |
|         this._modelMatrix = Cesium.Matrix4.IDENTITY;
 | |
| 
 | |
|         this.parent = null;
 | |
|         this.children = [];
 | |
| 
 | |
|         this.video = {
 | |
|             videojs: null,
 | |
|             dom: null,
 | |
|             playing: false,
 | |
|             timeupdate: false,
 | |
|             width: 0,
 | |
|             height: 0
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     get modelMatrix() {
 | |
|         return this._modelMatrix;
 | |
|     }
 | |
| 
 | |
|     set modelMatrix(matrix) {
 | |
|         this._modelMatrix = matrix.clone();
 | |
|         this.updateModelMatrix();
 | |
|     }
 | |
| 
 | |
|     updateModelMatrix() {
 | |
|         for (let i = 0; i < this.children.length; i++) {
 | |
|             const child = this.children[i];
 | |
| 
 | |
|             child.drawCommand.modelMatrix = this._modelMatrix;
 | |
|             //计算包围盒
 | |
|             const sphere = Cesium.BoundingSphere.fromVertices(child.geometry.vertices);
 | |
|             let newMat = Cesium.Matrix4.multiplyByTranslation(this._modelMatrix, sphere.center, new Cesium.Matrix4());
 | |
|             sphere.center = Cesium.Matrix4.getTranslation(newMat, new Cesium.Cartesian3());
 | |
|             child.drawCommand.boundingVolume = sphere;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     setPosition(position) {
 | |
|         Cesium.Matrix4.multiplyByTranslation(this._modelMatrix, position, this._modelMatrix);
 | |
|         this.updateModelMatrix();
 | |
|     }
 | |
| 
 | |
|     add(object) {
 | |
|         object.parent = this;
 | |
|         this.children.push(object);
 | |
|     }
 | |
| 
 | |
|     update(frameState) {
 | |
|         let camera = frameState.camera;
 | |
|         const cullingVolume = camera.frustum.computeCullingVolume(
 | |
|             camera.positionWC,
 | |
|             camera.directionWC,
 | |
|             camera.upWC
 | |
|         );
 | |
| 
 | |
|         for (let i = 0; i < this.children.length; i++) {
 | |
|             const child = this.children[i];
 | |
|             child.update(frameState);
 | |
| 
 | |
|             if (Cesium.defined(this.video.videojs)) {
 | |
|                 child.updateVideo(camera, this.video, cullingVolume);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * 设置视频
 | |
|      * @param {*} url
 | |
|      */
 | |
|     setVideo(url) {
 | |
|         this.video.playing = false;
 | |
|         this.video.timeupdate = false;
 | |
| 
 | |
|         let videoType = /^.+\.m3u8$/.test(url) ? "application/x-mpegURL" : "video/mp4";
 | |
|         if (!Cesium.defined(this.video.videojs)) {
 | |
|             //
 | |
|             const video = document.createElement('video');
 | |
|             video.setAttribute("id", "video_" + Cesium.createGuid());
 | |
|             video.setAttribute('crossorigin', 'anonymous');
 | |
|             video.setAttribute('muted', '');
 | |
|             // video.muted = true;
 | |
|             video.autoplay = true;
 | |
|             video.loop = true;
 | |
|             video.preload = "auto";
 | |
|             video.style.display = 'none';
 | |
|             video.width = 512;
 | |
|             video.height = 512;
 | |
|             video.style.objectFit = 'fill'
 | |
| 
 | |
|             this.video.videojs = videojs(video, {
 | |
|                 techOrder: ['html5']
 | |
|             }, () => {
 | |
|             });
 | |
| 
 | |
|             video.addEventListener('playing', () => {
 | |
|                 // console.log(video.videoWidth)
 | |
|                 // //获取video 宽高
 | |
|                 this.video.width = video.videoWidth;
 | |
|                 this.video.height = video.videoHeight;
 | |
|                 this.video.playing = true;
 | |
|             }, true);
 | |
| 
 | |
|             video.addEventListener('timeupdate', () => {
 | |
|                 this.video.timeupdate = true;
 | |
|             }, true);
 | |
| 
 | |
|             this.video.dom = video;
 | |
|             // document.body.appendChild(video)
 | |
|         }
 | |
| 
 | |
|         this.video.videojs.src([{
 | |
|             src: url,
 | |
|             type: videoType
 | |
|         }]);
 | |
|         this.video.videojs.play();
 | |
|     }
 | |
| }
 |