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