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(); | ||
|  |     } | ||
|  | } |