Skip to content

Commit e274227

Browse files
committed
feat(engine): Add GL renderers for BufferPrimitiveCollections
1 parent f3706de commit e274227

13 files changed

+1045
-0
lines changed

packages/engine/Source/Renderer/VertexArray.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import Buffer from "./Buffer.js";
1212
import BufferUsage from "./BufferUsage.js";
1313
import ContextLimits from "./ContextLimits.js";
1414
import AttributeType from "../Scene/AttributeType.js";
15+
import assert from "../Core/assert.js";
16+
17+
/** @import {TypedArray, TypedArrayConstructor} from "../Core/globalTypes.js"; */
1518

1619
function addAttribute(attributes, attribute, index, context) {
1720
const hasVertexBuffer = defined(attribute.vertexBuffer);
@@ -801,6 +804,83 @@ function setConstantAttributes(vertexArray, gl) {
801804
}
802805
}
803806

807+
/**
808+
* Copies into a vertex attribute buffer from the given array, at a given
809+
* range specified as offset and count, in number of (VECN) vertices. Array
810+
* and vertex attribute must have the same length, which can be larger
811+
* than the specified range to update.
812+
* @param {number} attributeIndex
813+
* @param {TypedArray} array
814+
* @param {number} vertexOffset
815+
* @param {number} vertexCount
816+
*/
817+
VertexArray.prototype.copyAttributeFromRange = function (
818+
attributeIndex,
819+
array,
820+
vertexOffset,
821+
vertexCount,
822+
) {
823+
const attribute = this.getAttribute(attributeIndex);
824+
const buffer = /** @type {Buffer} */ (attribute.vertexBuffer);
825+
const elementsPerVertex = attribute.componentsPerAttribute;
826+
827+
//>>includeStart('debug', pragmas.debug);
828+
assert(buffer.sizeInBytes === array.byteLength, "Invalid buffer length");
829+
//>>includeEnd('debug');
830+
831+
const ArrayConstructor = /** @type {TypedArrayConstructor} */ (
832+
array.constructor
833+
);
834+
835+
const byteOffset =
836+
vertexOffset * elementsPerVertex * ArrayConstructor.BYTES_PER_ELEMENT;
837+
838+
// Create a zero-copy ArrayView onto the specified range of the source array.
839+
const rangeArrayView = new ArrayConstructor(
840+
/** @type {ArrayBuffer} */ (array.buffer),
841+
array.byteOffset + byteOffset,
842+
vertexCount * elementsPerVertex,
843+
);
844+
845+
buffer.copyFromArrayView(rangeArrayView, byteOffset);
846+
};
847+
848+
/**
849+
* Copies into the index buffer from the given array, at a given range
850+
* specified as offset and count, in number of (uint) indices. Array
851+
* and index buffer must have the same length, which can be larger
852+
* than the specified range to update.
853+
* @param {TypedArray} array
854+
* @param {number} indexOffset
855+
* @param {number} indexCount
856+
*/
857+
VertexArray.prototype.copyIndexFromRange = function (
858+
array,
859+
indexOffset,
860+
indexCount,
861+
) {
862+
const buffer = /** @type {Buffer} */ (this._indexBuffer);
863+
864+
//>>includeStart('debug', pragmas.debug);
865+
assert(buffer.sizeInBytes === array.byteLength, "Invalid buffer length");
866+
//>>includeEnd('debug');
867+
868+
const ArrayConstructor = /** @type {TypedArrayConstructor} */ (
869+
array.constructor
870+
);
871+
872+
const byteOffset = indexOffset * ArrayConstructor.BYTES_PER_ELEMENT;
873+
874+
// Create a zero-copy ArrayView onto the specified range of the source array.
875+
const rangeArrayView = new ArrayConstructor(
876+
/** @type {ArrayBuffer} */ (array.buffer),
877+
array.byteOffset + byteOffset,
878+
indexCount,
879+
);
880+
881+
buffer.copyFromArrayView(rangeArrayView, byteOffset);
882+
};
883+
804884
VertexArray.prototype._bind = function () {
805885
if (defined(this._vao)) {
806886
this._context.glBindVertexArray(this._vao);

packages/engine/Source/Scene/BufferPointCollection.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import BufferPrimitiveCollection from "./BufferPrimitiveCollection.js";
44
import BufferPoint from "./BufferPoint.js";
55
import Cartesian3 from "../Core/Cartesian3.js";
6+
import renderPoints from "./renderBufferPointCollection.js";
67

78
/** @import Color from "../Core/Color.js"; */
89
/** @import FrameState from "./FrameState.js" */
@@ -64,6 +65,8 @@ class BufferPointCollection extends BufferPrimitiveCollection {
6465
*/
6566
update(frameState) {
6667
super.update(frameState);
68+
69+
this._renderContext = renderPoints(this, frameState, this._renderContext);
6770
}
6871
}
6972

packages/engine/Source/Scene/BufferPolygonCollection.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import BufferPrimitiveCollection from "./BufferPrimitiveCollection.js";
55
import BufferPolygon from "./BufferPolygon.js";
66
import Frozen from "../Core/Frozen.js";
77
import assert from "../Core/assert.js";
8+
import renderPolygons from "./renderBufferPolygonCollection.js";
89

910
/** @import Color from "../Core/Color.js"; */
1011
/** @import FrameState from "./FrameState.js" */
@@ -239,6 +240,8 @@ class BufferPolygonCollection extends BufferPrimitiveCollection {
239240
*/
240241
update(frameState) {
241242
super.update(frameState);
243+
244+
this._renderContext = renderPolygons(this, frameState, this._renderContext);
242245
}
243246

244247
/////////////////////////////////////////////////////////////////////////////

packages/engine/Source/Scene/BufferPolylineCollection.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import defined from "../Core/defined.js";
44
import BufferPrimitiveCollection from "./BufferPrimitiveCollection.js";
55
import BufferPolyline from "./BufferPolyline.js";
6+
import renderPolylines from "./renderBufferPolylineCollection.js";
67

78
/** @import Color from "../Core/Color.js"; */
89
/** @import FrameState from "./FrameState.js" */
@@ -69,6 +70,12 @@ class BufferPolylineCollection extends BufferPrimitiveCollection {
6970
*/
7071
update(frameState) {
7172
super.update(frameState);
73+
74+
this._renderContext = renderPolylines(
75+
this,
76+
frameState,
77+
this._renderContext,
78+
);
7279
}
7380
}
7481

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
// @ts-check
2+
3+
import defined from "../Core/defined.js";
4+
import Cartesian3 from "../Core/Cartesian3.js";
5+
import BufferPoint from "./BufferPoint.js";
6+
import Buffer from "../Renderer/Buffer.js";
7+
import BufferUsage from "../Renderer/BufferUsage.js";
8+
import VertexArray from "../Renderer/VertexArray.js";
9+
import ComponentDatatype from "../Core/ComponentDatatype.js";
10+
import RenderState from "../Renderer/RenderState.js";
11+
import BlendingState from "./BlendingState.js";
12+
import Color from "../Core/Color.js";
13+
import ShaderSource from "../Renderer/ShaderSource.js";
14+
import ShaderProgram from "../Renderer/ShaderProgram.js";
15+
import DrawCommand from "../Renderer/DrawCommand.js";
16+
import Pass from "../Renderer/Pass.js";
17+
import PrimitiveType from "../Core/PrimitiveType.js";
18+
import BufferPointCollectionVS from "../Shaders/BufferPointCollectionVS.js";
19+
import BufferPointCollectionFS from "../Shaders/BufferPointCollectionFS.js";
20+
import EncodedCartesian3 from "../Core/EncodedCartesian3.js";
21+
import AttributeCompression from "../Core/AttributeCompression.js";
22+
23+
/** @import FrameState from "./FrameState.js"; */
24+
/** @import BufferPointCollection from "./BufferPointCollection.js"; */
25+
/** @import {TypedArray, TypedArrayConstructor} from "../Core/globalTypes.js"; */
26+
27+
/** @type {{positionHighAndShow: number, positionLowAndColor: number}} */
28+
const BufferPointAttributeLocations = {
29+
/** @type {number} */
30+
positionHighAndShow: 0,
31+
/** @type {number} */
32+
positionLowAndColor: 1,
33+
};
34+
35+
/**
36+
* @typedef {object} BufferPointRenderContext
37+
* @property {VertexArray} [vertexArray]
38+
* @property {Record<number, TypedArray>} [attributeArrays]
39+
* @property {RenderState} [renderState]
40+
* @property {ShaderProgram} [shaderProgram]
41+
* @property {object} [uniformMap]
42+
* @ignore
43+
*/
44+
45+
/**
46+
* @param {BufferPointCollection} collection
47+
* @param {FrameState} frameState
48+
* @param {BufferPointRenderContext} [renderContext]
49+
* @returns {BufferPointRenderContext}
50+
* @ignore
51+
*/
52+
function renderBufferPointCollection(collection, frameState, renderContext) {
53+
const context = frameState.context;
54+
renderContext = renderContext || {};
55+
56+
if (!defined(renderContext.attributeArrays)) {
57+
const featureCountMax = collection.primitiveCountMax;
58+
const positionHighAndShowArray = new Float32Array(featureCountMax * 4);
59+
const positionLowAndColorArray = new Float32Array(featureCountMax * 4);
60+
61+
renderContext.attributeArrays = {
62+
[BufferPointAttributeLocations.positionHighAndShow]:
63+
positionHighAndShowArray,
64+
[BufferPointAttributeLocations.positionLowAndColor]:
65+
positionLowAndColorArray,
66+
};
67+
}
68+
69+
if (collection._dirtyCount > 0) {
70+
const point = new BufferPoint();
71+
const color = new Color();
72+
const cartesian = new Cartesian3();
73+
const encodedCartesian = new EncodedCartesian3();
74+
75+
const positionHighAndShowArray =
76+
renderContext.attributeArrays[
77+
BufferPointAttributeLocations.positionHighAndShow
78+
];
79+
const positionLowAndColorArray =
80+
renderContext.attributeArrays[
81+
BufferPointAttributeLocations.positionLowAndColor
82+
];
83+
84+
const { _dirtyOffset, _dirtyCount } = collection;
85+
86+
for (let i = _dirtyOffset, il = _dirtyOffset + _dirtyCount; i < il; i++) {
87+
collection.get(i, point);
88+
89+
if (!point._dirty) {
90+
continue;
91+
}
92+
93+
point.getPosition(cartesian);
94+
EncodedCartesian3.fromCartesian(cartesian, encodedCartesian);
95+
96+
point.getColor(color);
97+
98+
positionHighAndShowArray[i * 4] = encodedCartesian.high.x;
99+
positionHighAndShowArray[i * 4 + 1] = encodedCartesian.high.y;
100+
positionHighAndShowArray[i * 4 + 2] = encodedCartesian.high.z;
101+
positionHighAndShowArray[i * 4 + 3] = point.show ? 1 : 0;
102+
103+
positionLowAndColorArray[i * 4] = encodedCartesian.low.x;
104+
positionLowAndColorArray[i * 4 + 1] = encodedCartesian.low.y;
105+
positionLowAndColorArray[i * 4 + 2] = encodedCartesian.low.z;
106+
positionLowAndColorArray[i * 4 + 3] =
107+
AttributeCompression.encodeRGB8(color);
108+
109+
point._dirty = false;
110+
}
111+
}
112+
113+
if (!defined(renderContext.vertexArray)) {
114+
const attributeArrays = renderContext.attributeArrays;
115+
116+
const positionHighBuffer = Buffer.createVertexBuffer({
117+
typedArray:
118+
attributeArrays[BufferPointAttributeLocations.positionHighAndShow],
119+
context,
120+
// @ts-expect-error Requires https://github.com/CesiumGS/cesium/pull/13203.
121+
usage: BufferUsage.STATIC_DRAW,
122+
});
123+
124+
const positionLowBuffer = Buffer.createVertexBuffer({
125+
typedArray:
126+
attributeArrays[BufferPointAttributeLocations.positionLowAndColor],
127+
context,
128+
// @ts-expect-error Requires https://github.com/CesiumGS/cesium/pull/13203.
129+
usage: BufferUsage.STATIC_DRAW,
130+
});
131+
132+
renderContext.vertexArray = new VertexArray({
133+
context,
134+
attributes: [
135+
{
136+
index: BufferPointAttributeLocations.positionHighAndShow,
137+
vertexBuffer: positionHighBuffer,
138+
componentDatatype: ComponentDatatype.FLOAT,
139+
componentsPerAttribute: 4,
140+
},
141+
{
142+
index: BufferPointAttributeLocations.positionLowAndColor,
143+
vertexBuffer: positionLowBuffer,
144+
componentDatatype: ComponentDatatype.FLOAT,
145+
componentsPerAttribute: 4,
146+
},
147+
],
148+
});
149+
} else if (collection._dirtyCount > 0) {
150+
const { positionHighAndShow, positionLowAndColor } =
151+
BufferPointAttributeLocations;
152+
renderContext.vertexArray.copyAttributeFromRange(
153+
positionHighAndShow,
154+
renderContext.attributeArrays[positionHighAndShow],
155+
collection._dirtyOffset,
156+
collection._dirtyCount,
157+
);
158+
renderContext.vertexArray.copyAttributeFromRange(
159+
positionLowAndColor,
160+
renderContext.attributeArrays[positionLowAndColor],
161+
collection._dirtyOffset,
162+
collection._dirtyCount,
163+
);
164+
}
165+
166+
if (!defined(renderContext.renderState)) {
167+
renderContext.renderState = RenderState.fromCache({
168+
blending: BlendingState.DISABLED,
169+
depthMask: false,
170+
depthTest: { enabled: true },
171+
polygonOffset: { enabled: false },
172+
});
173+
}
174+
175+
if (!defined(renderContext.uniformMap)) {
176+
renderContext.uniformMap = {};
177+
}
178+
179+
if (!defined(renderContext.shaderProgram)) {
180+
const vertexShaderSource = new ShaderSource({
181+
sources: [BufferPointCollectionVS],
182+
});
183+
184+
const fragmentShaderSource = new ShaderSource({
185+
sources: [BufferPointCollectionFS],
186+
});
187+
188+
renderContext.shaderProgram = ShaderProgram.fromCache({
189+
context,
190+
vertexShaderSource,
191+
fragmentShaderSource,
192+
attributeLocations: BufferPointAttributeLocations,
193+
});
194+
}
195+
196+
const command = new DrawCommand({
197+
primitiveType: PrimitiveType.POINTS,
198+
pass: Pass.OPAQUE,
199+
200+
vertexArray: renderContext.vertexArray,
201+
renderState: renderContext.renderState,
202+
shaderProgram: renderContext.shaderProgram,
203+
uniformMap: renderContext.uniformMap,
204+
205+
owner: collection,
206+
count: collection.primitiveCount,
207+
boundingVolume: collection.boundingVolume,
208+
debugShowBoundingVolume: collection.debugShowBoundingVolume,
209+
});
210+
211+
frameState.commandList.push(command);
212+
213+
collection._dirtyCount = 0;
214+
collection._dirtyOffset = 0;
215+
216+
return renderContext;
217+
}
218+
219+
export default renderBufferPointCollection;

0 commit comments

Comments
 (0)