Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 28 additions & 8 deletions packages/gl/src/layer/raycaster/RayCaster.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,29 +66,49 @@ export default class RayCaster {

_testMesh(mesh, ray, map, positions, altitudes, indices, dim, matrix, count) {
const coordinates = [];
const glRes = map.getGLRes();
for (let j = 0; j < indices.length; j += 3) {
if (j > mesh.properties.skirtOffset) {
break;
}
const a = indices[j];
const b = indices[j + 1];
const c = indices[j + 2];
const positionsA = vec3.set(pA_VEC, positions[a * dim], positions[a * dim + 1], positions[a * dim + 2]);
const pA = this._toWorldPosition(POS_A, map, positionsA, altitudes[a] / 100, matrix);
const positionsB = vec3.set(pB_VEC, positions[b * dim], positions[b * dim + 1], positions[b * dim + 2]);
const pB = this._toWorldPosition(POS_B, map, positionsB, altitudes[b] / 100, matrix);
const positionsC = vec3.set(pC_VEC, positions[c * dim], positions[c * dim + 1], positions[c * dim + 2]);
const pC = this._toWorldPosition(POS_C, map, positionsC, altitudes[c] / 100, matrix);
const aindex = a * dim, bindex = b * dim, cindex = c * dim;
//高频操作,尽可能的减少function(vec3.set) call,
pA_VEC[0] = positions[aindex];
pA_VEC[1] = positions[aindex + 1];
pA_VEC[2] = positions[aindex + 2];

pB_VEC[0] = positions[bindex];
pB_VEC[1] = positions[bindex + 1];
pB_VEC[2] = positions[bindex + 2];

pC_VEC[0] = positions[cindex];
pC_VEC[1] = positions[cindex + 1];
pC_VEC[2] = positions[cindex + 2];


const pA = this._toWorldPosition(POS_A, map, pA_VEC, altitudes[a] / 100, matrix);
const pB = this._toWorldPosition(POS_B, map, pB_VEC, altitudes[b] / 100, matrix);
const pC = this._toWorldPosition(POS_C, map, pC_VEC, altitudes[c] / 100, matrix);

// const positionsA = vec3.set(pA_VEC, positions[a * dim], positions[a * dim + 1], positions[a * dim + 2]);
// const pA = this._toWorldPosition(POS_A, map, positionsA, altitudes[a] / 100, matrix);
// const positionsB = vec3.set(pB_VEC, positions[b * dim], positions[b * dim + 1], positions[b * dim + 2]);
// const pB = this._toWorldPosition(POS_B, map, positionsB, altitudes[b] / 100, matrix);
// const positionsC = vec3.set(pC_VEC, positions[c * dim], positions[c * dim + 1], positions[c * dim + 2]);
// const pC = this._toWorldPosition(POS_C, map, positionsC, altitudes[c] / 100, matrix);

const triangle = vec3.set(TRIANGLE, pA, pB, pC);
const vAB = vec3.sub(TEMP_VEC_AB, pA, pB);
const vAC = vec3.sub(TEMP_VEC_AC, pA, pC);
const intersectPoint = this._testIntersection(INTERSECT_POINT, triangle, ray);
if (intersectPoint) {
const altitude = map.pointAtResToAltitude(intersectPoint[2], map.getGLRes());
const altitude = map.pointAtResToAltitude(intersectPoint[2], glRes);
TEMP_POINT.x = intersectPoint[0];
TEMP_POINT.y = intersectPoint[1];
const coord = map.pointAtResToCoordinate(TEMP_POINT, map.getGLRes());
const coord = map.pointAtResToCoordinate(TEMP_POINT, glRes);
coord.z = altitude;
coordinates.push({
coordinate: coord,
Expand Down
13 changes: 5 additions & 8 deletions packages/gl/src/layer/terrain/TerrainLitPainter.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as reshader from '../../reshader';
import TerrainPainter from './TerrainPainter';
import { extend, isNil } from '../util/util';
import { extend, isNil } from '../util/util';
import * as ContextUtil from '../util/context';

const { getIBLResOnCanvas, getPBRUniforms, loginIBLResOnCanvas, logoutIBLResOnCanvas } = reshader.pbr.PBRUtils;
Expand Down Expand Up @@ -52,7 +52,7 @@ class TerrainLitPainter extends TerrainPainter {

createTerrainMesh(tileInfo, terrainImage) {
const { mesh: terrainGeo, image: heightTexture } = terrainImage;
const { positions, texcoords, triangles, leftSkirtIndex, rightSkirtIndex, bottomSkirtIndex, numVerticesWithoutSkirts } = terrainGeo;
const { positions, texcoords, triangles, leftSkirtIndex, rightSkirtIndex, bottomSkirtIndex, numVerticesWithoutSkirts, tangents } = terrainGeo;
const normals = new Int8Array(positions.length);
for (let i = 2; i < normals.length; i += 3) {
if (i < numVerticesWithoutSkirts * 3) {
Expand All @@ -72,15 +72,12 @@ class TerrainLitPainter extends TerrainPainter {
aPosition: positions,
aTexCoord: texcoords,
aNormal: normals
},
triangles,
0);

}, triangles, 0);
// 共用端点时,法线值会出现错误,造成视觉上不连续,所以需要唯一化
// 唯一化后,三角形数量不变,但端点数组大概会膨胀5倍以上
// geo.buildUniqueVertex();
// geo.createNormal();
geo.createTangent();
geo.createTangent('aTangent', tangents);
delete geo.data.aNormal;

geo.generateBuffers(this.graphics);
Expand Down Expand Up @@ -161,7 +158,7 @@ class TerrainLitPainter extends TerrainPainter {
extend(uniforms, {
viewMatrix: map.viewMatrix,
projMatrix: map.projMatrix,
projViewMatrix : map.projViewMatrix,
projViewMatrix: map.projViewMatrix,
outSize: [canvas.width, canvas.height],
polygonFill: [1, 1, 1, 1],
terrainHeightMapResolution: [tileSize, tileSize],
Expand Down
50 changes: 49 additions & 1 deletion packages/gl/src/layer/terrain/worker/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import "./zlib.min";
import { vec2, vec3 } from 'gl-matrix';
import { createMartiniData } from '../util/martini';
import { ColorIn } from 'colorin';
import { buildTangents } from '@maptalks/tbn-packer';

function isNumber(val) {
return (typeof val === 'number') && !isNaN(val);
}
// 保存当前的workerId,用于告知主线程结果回传给哪个worker
let workerId;

Expand Down Expand Up @@ -764,6 +769,41 @@ function createColorsTexture(data, colors, tileSize) {

}

/**
* create terrain geometry tangents by worker for perf
* @param {*} terrainMesh
* @returns
*/
function createTerrainGeometryTangents(terrainMesh) {
if (!terrainMesh) {
return;
}
const { positions, texcoords, triangles, leftSkirtIndex, rightSkirtIndex, bottomSkirtIndex, numVerticesWithoutSkirts } = terrainMesh;
if (!positions || !texcoords || !triangles) {
return;
}
if (!isNumber(leftSkirtIndex) || !isNumber(rightSkirtIndex) || !isNumber(bottomSkirtIndex) || !isNumber(numVerticesWithoutSkirts)) {
return;
}
const normals = new Int8Array(positions.length);
for (let i = 2; i < normals.length; i += 3) {
if (i < numVerticesWithoutSkirts * 3) {
normals[i] = 1;
} else if (i < leftSkirtIndex / 2 * 3) {
normals[i - 2] = -1;
} else if (i < rightSkirtIndex / 2 * 3) {
normals[i - 2] = 1;
} else if (i < bottomSkirtIndex / 2 * 3) {
normals[i - 1] = -1;
} else {
// top
normals[i - 1] = 1;
}
}
const tangents = buildTangents(positions, normals, texcoords, triangles);
return new Float32Array(tangents);
}

export const onmessage = function (message, postResponse) {
const data = message.data;
if (data.command === 'addLayer' || data.command === 'removeLayer') {
Expand All @@ -775,12 +815,20 @@ export const onmessage = function (message, postResponse) {
const colors = (data.params || {}).colors;
const tileSize = (data.params || {}).tileSize;
loadTerrain(data.params, (data, transferables) => {
transferables = transferables || [];
//create terrain colors texture
const texture = createColorsTexture(data, colors, tileSize);
if (texture) {
data.colorsTexture = texture;
transferables = transferables || [];
transferables.push(texture);
}

//create terrain geometry tangents attribute
const tangents = createTerrainGeometryTangents(data.mesh);
if (tangents && data.mesh) {
data.mesh.tangents = tangents;
transferables.push(tangents.buffer);
}
postResponse(data.error, data, transferables);
});
} else if (data.command === 'abortTerrain') {
Expand Down
48 changes: 30 additions & 18 deletions packages/gl/src/reshader/Geometry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export default class Geometry {
}
}

static padGPUBufferAlignment(array:TypedArray, vertexCount: number): TypedArray {
static padGPUBufferAlignment(array: TypedArray, vertexCount: number): TypedArray {
const itemBytes = array.byteLength / vertexCount;
if (itemBytes % 4 === 0) {
return array;
Expand Down Expand Up @@ -226,7 +226,7 @@ export default class Geometry {
if (!id) {
id = attribute.array.buffer['__id'] = GUID();
}
this.data[attr] = {
this.data[attr] = {
buffer: id,
offset: attribute.byteOffset,
stride: attribute.byteStride,
Expand Down Expand Up @@ -467,9 +467,15 @@ export default class Geometry {
} else {
ctor = this.elements.constructor;
}
this.indices = new ctor(elements.length);
for (let i = 0; i < elements.length; i++) {
this.indices[i] = elements[i];
if (elements instanceof ctor) {
//2x faster by new TypeArray(typearray)
//https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Uint32Array
this.indices = new ctor(elements);
} else {
this.indices = new ctor(elements.length);
for (let i = 0; i < elements.length; i++) {
this.indices[i] = elements[i];
}
}
}
this.elements = this.elements.destroy ? this.elements : Geometry.createElementBuffer(device, this.elements);
Expand All @@ -495,7 +501,7 @@ export default class Geometry {
if (isArray(data)) {
// 因为data可能被转成regl buffer,需要保存到this._vertexCount
// 在 updateData时再更新
this._vertexCount = Math.ceil(data.length / positionSize);
this._vertexCount = Math.ceil(data.length / positionSize);
} else if (data && data.count !== undefined) {
this._vertexCount = data.count;
}
Expand Down Expand Up @@ -600,6 +606,7 @@ export default class Geometry {
return this;
}


_updateGPUBuffer(buffer : GPUBuffer, data : AttributeData, offset: number, byteLength: number) {
if (Array.isArray(data)) {
data = new Float32Array(data);
Expand Down Expand Up @@ -899,7 +906,7 @@ export default class Geometry {
//对于POSITION数据,为避免updateBBox时频繁创建临时数组,采用缓存tempPosArray的策略获取interleavedArray,
//对于非POSITION的数据,直接readInterleavedArray读取即可
if (name === this.desc.positionAttribute) {
if (!this._tempPosArray || (this._tempPosArray && this._tempPosArray.length < size *count)) {
if (!this._tempPosArray || (this._tempPosArray && this._tempPosArray.length < size * count)) {
this._tempPosArray = new ctor(size * count);
return gltf.GLTFLoader.readInterleavedArray(this._tempPosArray, attribute, count, size, stride, offset, componentType);
}
Expand All @@ -915,18 +922,23 @@ export default class Geometry {
}
}

createTangent(name = 'aTangent') {
createTangent(name = 'aTangent', tangentsDataArray?: Float32Array | Array<number>) {
this._incrVersion();
//TODO data 可能是含stride的interleaved类型
const { normalAttribute, positionAttribute, uv0Attribute } = this.desc;
const normals = this._getAttributeData(normalAttribute);
const positions = this._getAttributeData(positionAttribute);
const tangents = buildTangents(
positions,
normals,
this.data[uv0Attribute],
this.elements
);
let tangents;
if (tangentsDataArray && tangentsDataArray.length) {
tangents = tangentsDataArray;
} else {
tangents = buildTangents(
positions,
normals,
this.data[uv0Attribute],
this.elements
);
}
const aTangent = this.data[name] = new Float32Array(tangents.length);
const t: vec4 = [0, 0, 0, 0], n: vec3 = [0, 0, 0], q: vec4 = [0, 0, 0, 0];
for (let i = 0; i < tangents.length; i += 4) {
Expand Down Expand Up @@ -982,7 +994,7 @@ export default class Geometry {
const oldData = {};

let pos = data[this.desc.positionAttribute];
pos = pos.length ? pos : pos.array; //存在两种结构 array或者 { array }
pos = pos.length ? pos : pos.array; //存在两种结构 array或者 { array }
if (!isArray(pos)) {
throw new Error(this.desc.positionAttribute + ' must be array to build unique vertex.');
}
Expand Down Expand Up @@ -1016,7 +1028,7 @@ export default class Geometry {
indices[i] = cursor++;
}
pos = this.data[this.desc.positionAttribute];
this._vertexCount = Math.ceil(pos.length / this.desc.positionSize);
this._vertexCount = Math.ceil(pos.length / this.desc.positionSize);
delete this._reglData;
}

Expand Down Expand Up @@ -1048,7 +1060,7 @@ export default class Geometry {

//@internal
_forEachBuffer(fn: (buffer: any) => void) {
if (this.elements && this.elements.destroy) {
if (this.elements && this.elements.destroy) {
fn(this.elements);
}
for (const p in this.data) {
Expand Down Expand Up @@ -1283,7 +1295,7 @@ function createGPUBuffer(device, data, usage, label) {
data = new Float32Array(data);
}
const ctor = data.constructor;
// f32 in default
// f32 in default
const byteLength = data.byteLength;
// mappedAtCreation requires size is a multiplier of 4
// https://github.com/gpuweb/gpuweb/issues/5105
Expand Down
2 changes: 1 addition & 1 deletion packages/maptalks/src/map/Map.DomEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ Map.include(/** @lends Map.prototype */ {

//@internal
_wrapTerrainData(eventParam: MapEventDataType) {
if (this.options['queryTerrainInMapEvents'] && eventParam.containerPoint && !eventParam.terrain) {
if (this.options['queryTerrainInMapEvents'] && eventParam.containerPoint && !eventParam.terrain && !this.isInteracting()) {
eventParam.terrain = this._queryTerrainInfo(eventParam.containerPoint);
}
},
Expand Down
Loading