Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add JSDoc for extras/splat ply-reader/splat-material/splat #5868

Merged
merged 7 commits into from
Dec 11, 2023
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
5 changes: 5 additions & 0 deletions extras/jsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"compilerOptions": {
"checkJs": true
}
}
26 changes: 25 additions & 1 deletion extras/splat/ply-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,34 @@ const defaultElementsSet = new Set(defaultElements);
const defaultElementFilter = val => defaultElementsSet.has(val);

class PlyParser {
/** @type {import('playcanvas').GraphicsDevice} */
device;

/** @type {import('playcanvas').AssetRegistry} */
assets;

/** @type {number} */
maxRetries;

/**
* @param {import('playcanvas').GraphicsDevice} device - The graphics device.
* @param {import('playcanvas').AssetRegistry} assets - The asset registry.
* @param {number} maxRetries - Maximum amount of retries.
*/
constructor(device, assets, maxRetries) {
this.device = device;
this.assets = assets;
this.maxRetries = maxRetries;
}

/**
* @param {object} url - The URL of the resource to load.
* @param {string} url.load - The URL to use for loading the resource.
* @param {string} url.original - The original URL useful for identifying the resource type.
* @param {import('playcanvas').ResourceHandlerCallback} callback - The callback used when
* the resource is loaded or an error occurs.
* @param {import('playcanvas').Asset} asset - Container asset.
*/
async load(url, callback, asset) {
const response = await fetch(url.load);
readPly(response.body.getReader(), asset.data.elementFilter ?? defaultElementFilter)
Expand All @@ -37,14 +53,22 @@ class PlyParser {
});
}

/**
* @param {string} url - The URL.
* @param {SplatContainerResource} data - The data.
* @returns {SplatContainerResource} Return the data.
*/
open(url, data) {
return data;
}
}

/**
* @param {import('playcanvas').AppBase} app - The application.
*/
const registerPlyParser = (app) => {
const containerHandler = app.loader.getHandler('container');
containerHandler.parsers.ply = new PlyParser(app.graphicsDevice, app.assets, app.loader.maxRetries);
containerHandler.parsers.ply = new PlyParser(app.graphicsDevice, app.assets, containerHandler.maxRetries);
};

const getDefaultPlyElements = () => {
Expand Down
67 changes: 46 additions & 21 deletions extras/splat/ply-reader.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,32 @@ const dataTypeMap = new Map([
['double', Float64Array]
]);

class PlyProperty {
type;

name;

storage;

byteSize;
}

class PlyElement {
name;

count;

properties;
}

// asynchronously read a ply file data
/**
* @typedef {Int8Array|Uint8Array|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array} DataType
*/

/**
* @typedef {object} PlyProperty
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we even use these types anywhere?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, PlyElement is used once in ply-reader.js and three times in splat-data.js:

class SplatData {
    /** @type {import('./ply-reader').PlyElement[]} */
    elements;

    /** @type {import('./ply-reader').PlyElement} */
    vertexElement;

    /**
     * @param {import('./ply-reader').PlyElement[]} elements - The elements.
     * @param {boolean} [performZScale] - Whether to perform z scaling.
     */
    constructor(elements, performZScale = true) {

* @property {string} type - E.g. 'float'.
* @property {string} name - E.g. 'x', 'y', 'z', 'f_dc_0' etc.
* @property {DataType} storage - Data type, e.g. instance of Float32Array.
* @property {number} byteSize - BYTES_PER_ELEMENT of given data type.
*/

/**
* @typedef {object} PlyElement
* @property {string} name - E.g. 'vertex'.
* @property {number} count - Given count.
* @property {PlyProperty[]} properties - The properties.
*/

/**
* asynchronously read a ply file data
*
* @param {ReadableStreamDefaultReader<Uint8Array>} reader - The reader.
* @param {Function|null} propertyFilter - Function to filter properties with.
* @returns {Promise<PlyElement[]>} The ply file data.
*/
const readPly = async (reader, propertyFilter = null) => {
const concat = (a, b) => {
const c = new Uint8Array(a.byteLength + b.byteLength);
Expand All @@ -39,10 +46,18 @@ const readPly = async (reader, propertyFilter = null) => {
return c;
};

/**
* Searches for the first occurrence of a sequence within a buffer.
* @example
* find(new Uint8Array([1, 2, 3, 4]), new Uint8Array([3, 4])); // 2
* @param {Uint8Array} buf - The buffer in which to search.
* @param {Uint8Array} search - The sequence to search for.
* @returns {number} The index of the first occurrence of the search sequence in the buffer, or -1 if not found.
*/
const find = (buf, search) => {
const endIndex = buf.length - search.length;
let i, j;
for (i = 0; i < endIndex; ++i) {
for (i = 0; i <= endIndex; ++i) {
for (j = 0; j < search.length; ++j) {
if (buf[i + j] !== search[j]) {
break;
Expand All @@ -55,6 +70,14 @@ const readPly = async (reader, propertyFilter = null) => {
return -1;
};

/**
* Checks if array 'a' starts with the same elements as array 'b'.
* @example
* startsWith(new Uint8Array([1, 2, 3, 4]), new Uint8Array([1, 2])); // true
* @param {Uint8Array} a - The array to check against.
* @param {Uint8Array} b - The array of elements to look for at the start of 'a'.
* @returns {boolean} - True if 'a' starts with all elements of 'b', otherwise false.
*/
const startsWith = (a, b) => {
if (a.length < b.length) {
return false;
Expand All @@ -69,7 +92,9 @@ const readPly = async (reader, propertyFilter = null) => {
return true;
};

/** @type {Uint8Array|undefined} */
let buf;
/** @type {number} */
let endHeaderIndex;

while (true) {
Expand Down Expand Up @@ -213,4 +238,4 @@ const readPly = async (reader, propertyFilter = null) => {
return elements;
};

export { readPly, PlyProperty, PlyElement };
export { readPly };
17 changes: 16 additions & 1 deletion extras/splat/splat-container-resource.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,19 @@ import { Splat } from './splat.js';
import { SplatInstance } from './splat-instance.js';

class SplatContainerResource extends ContainerResource {
/** @type {import('playcanvas').GraphicsDevice} */
device;

/** @type {import('./splat-data.js').SplatData} */
splatData;

/** @type {Splat} */
splat;

/**
* @param {import('playcanvas').GraphicsDevice} device - The graphics device.
* @param {import('./splat-data.js').SplatData} splatData - The splat data.
*/
constructor(device, splatData) {
super();

Expand Down Expand Up @@ -62,10 +69,18 @@ class SplatContainerResource extends ContainerResource {
return this.splat;
}

instantiateModelEntity(/* options: any */) {
/**
* @param {import('./splat-material.js').SplatMaterialOptions} [options] - The options.
* @returns {null} Null.
*/
instantiateModelEntity(options) {
return null;
}

/**
* @param {import('./splat-material.js').SplatMaterialOptions} [options] - The options.
* @returns {Entity} The GS entity.
*/
instantiateRenderEntity(options = {}) {

// shared splat between instances
Expand Down
43 changes: 42 additions & 1 deletion extras/splat/splat-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,25 @@ const debugLines = [
];
const debugColor = new Color(1, 1, 0, 0.4);

/**
* Defines the shape of a SplatTRS.
* @typedef {object} SplatTRS - Represents a splat object with position, rotation, and scale.
* @property {number} x - The x-coordinate of the position.
* @property {number} y - The y-coordinate of the position.
* @property {number} z - The z-coordinate of the position.
* @property {number} rx - The x-component of the quaternion rotation.
* @property {number} ry - The y-component of the quaternion rotation.
* @property {number} rz - The z-component of the quaternion rotation.
* @property {number} rw - The w-component of the quaternion rotation.
* @property {number} sx - The scale factor in the x-direction.
* @property {number} sy - The scale factor in the y-direction.
* @property {number} sz - The scale factor in the z-direction.
*/

/**
* @param {Mat4} result - Mat4 instance holding calculated rotation matrix.
* @param {SplatTRS} data - The splat TRS object.
*/
const calcSplatMat = (result, data) => {
const px = data.x;
const py = data.y;
Expand Down Expand Up @@ -54,10 +73,16 @@ const calcSplatMat = (result, data) => {
};

class SplatData {
/** @type {import('./ply-reader').PlyElement[]} */
elements;

/** @type {import('./ply-reader').PlyElement} */
vertexElement;

/**
* @param {import('./ply-reader').PlyElement[]} elements - The elements.
* @param {boolean} [performZScale] - Whether to perform z scaling.
*/
constructor(elements, performZScale = true) {
this.elements = elements;
this.vertexElement = elements.find(element => element.name === 'vertex');
Expand All @@ -72,14 +97,22 @@ class SplatData {
return this.vertexElement.count;
}

/**
* @param {BoundingBox} result - Bounding box instance holding calculated result.
* @param {SplatTRS} data - The splat TRS object.
*/
static calcSplatAabb(result, data) {
calcSplatMat(mat4, data);
aabb.center.set(0, 0, 0);
aabb.halfExtents.set(data.sx * 2, data.sy * 2, data.sz * 2);
result.setFromTransformedAabb(aabb, mat4);
}

// transform splat data by the given matrix
/**
* Transform splat data by the given matrix.
*
* @param {Mat4} mat - The matrix.
*/
transform(mat) {
const x = this.getProp('x');
const y = this.getProp('y');
Expand Down Expand Up @@ -175,6 +208,10 @@ class SplatData {
return !first;
}

/**
* @param {Vec3} result - The result.
* @param {Function} pred - Predicate given index for skipping.
*/
calcFocalPoint(result, pred) {
const x = this.getProp('x');
const y = this.getProp('y');
Expand Down Expand Up @@ -202,6 +239,10 @@ class SplatData {
result.mulScalar(1 / sum);
}

/**
* @param {import('playcanvas').AppBase} app - The application.
* @param {Mat4} worldMat - The world matrix.
*/
renderWireframeBounds(app, worldMat) {
const x = this.getProp('x');
const y = this.getProp('y');
Expand Down
15 changes: 15 additions & 0 deletions extras/splat/splat-instance.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,32 @@ const cameraDirection = new Vec3();
const viewport = [0, 0];

class SplatInstance {
/** @type {import('./splat.js').Splat} */
splat;

/** @type {Mesh} */
mesh;

/** @type {MeshInstance} */
meshInstance;

/** @type {import('playcanvas').Material} */
material;

/** @type {VertexBuffer} */
vb;

/** @type {SplatSorter} */
sorter;

lastCameraPosition = new Vec3();

lastCameraDirection = new Vec3();

/**
* @param {import('./splat.js').Splat} splat - The splat instance.
* @param {import('./splat-material.js').SplatMaterialOptions} options - The options.
*/
constructor(splat, options) {
this.splat = splat;

Expand Down Expand Up @@ -115,6 +125,11 @@ class SplatInstance {
this.material.setParameter('viewport', viewport);
}

/**
* Sorts the GS vertices based on the given camera entity.
* @param {import('playcanvas').Entity} camera - The camera entity used for sorting.
* @returns {boolean} Returns true if the sorting was performed, otherwise false.
*/
sort(camera) {

let sorted = false;
Expand Down
13 changes: 13 additions & 0 deletions extras/splat/splat-material.js
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,19 @@ const hashCode = (str) => {
return hash;
};

/**
* @typedef {object} SplatMaterialOptions - The options.
* @property {boolean} [debugRender] - Adds #define DEBUG_RENDER for shader.
* @property {string} [vertex] - Custom vertex shader, see SPLAT MANY example.
* @property {string} [fragment] - Custom fragment shader, see SPLAT MANY example.
*/

/**
* @param {import('playcanvas').GraphicsDevice} device - The graphics device to use
* for the material creation.
* @param {SplatMaterialOptions} [options] - The options.
* @returns {Material} The GS material.
*/
const createSplatMaterial = (device, options = {}) => {

const debugRender = options.debugRender;
Expand Down
Loading