Added basic Geometry

This commit is contained in:
Richard Davey 2020-09-30 15:30:50 +01:00
parent 6ab0803469
commit 5313356fb0
5 changed files with 503 additions and 0 deletions

View file

@ -0,0 +1,83 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2020 Photon Storm Ltd.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
var Class = require('../../utils/Class');
var BufferAttribute = new Class({
initialize:
function BufferAttribute (array, size, normalized)
{
/**
* The array holding data stored in the buffer.
* @type {TypedArray}
*/
this.array = array;
/**
* The length of vectors that are being stored in the array.
* @type {Integer}
*/
this.size = size;
/**
* Stores the array's length divided by the size.
* If the buffer is storing a 3-component vector (such as a position, normal, or color), then this will count the number of such vectors stored.
* @type {Integer}
*/
this.count = array !== undefined ? array.length / size : 0;
/**
* Indicates how the underlying data in the buffer maps to the values in the GLSL shader code.
* See the constructor above for details.
* @type {boolean}
*/
this.normalized = normalized === true;
/**
* Whether the buffer is dynamic or not.
* If false, the GPU is informed that contents of the buffer are likely to be used often and not change often.
* This corresponds to the gl.STATIC_DRAW flag.
* If true, the GPU is informed that contents of the buffer are likely to be used often and change often.
* This corresponds to the gl.DYNAMIC_DRAW flag.
* @type {boolean}
* @default false
*/
this.dynamic = false;
/**
* Object containing:
* offset: Default is 0. Position at whcih to start update.
* count: Default is -1, which means don't use update ranges.
* This can be used to only update some components of stored vectors (for example, just the component related to color).
*/
this.updateRange = { offset: 0, count: -1 };
/**
* A version number, incremented every time the data changes.
* @type {Integer}
* @default 0
*/
this.version = 0;
},
setArray: function (array)
{
this.count = array !== undefined ? array.length / this.size : 0;
this.array = array;
// inc version?
return this;
}
// copy / clone?
});
module.exports = BufferAttribute;

View file

@ -0,0 +1,185 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2020 Photon Storm Ltd.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
var Box3 = require('../math/Box3');
var BufferAttribute = require('./BufferAttribute');
var Class = require('../../utils/Class');
var Sphere = require('../math/Sphere');
var geometryId = 1;
var Geometry = new Class({
initialize:
function Geometry ()
{
this.id = geometryId++;
/**
* This hashmap has an id the name of the attribute to be set and as value the buffer to set it to.
* Rather than accessing this property directly, use `addAttribute` and `getAttribute` to access attributes of this geometry.
*/
this.attributes = {};
/**
* Hashmap of Attributes Array for morph targets.
*/
this.morphAttributes = {};
/**
* Allows for vertices to be re-used across multiple triangles; this is called using "indexed triangles" and each triangle is associated with the indices of three vertices.
* This attribute therefore stores the index of each vertex for each triangular face.
* If this attribute is not set, the renderer assumes that each three contiguous positions represent a single triangle.
* @type {BufferAttribute}
*/
this.index = null;
/**
* Bounding box for the bufferGeometry, which can be calculated with `computeBoundingBox`.
* @type {Box3}
*/
this.boundingBox = new Box3();
/**
* Bounding sphere for the bufferGeometry, which can be calculated with `computeBoundingSphere`.
* @type {Sphere}
*/
this.boundingSphere = new Sphere();
/**
* Split the geometry into groups, each of which will be rendered in a separate WebGL draw call. This allows an array of materials to be used with the geometry.
* Each group is an object of the form:
* { start: Integer, count: Integer, materialIndex: Integer }
*/
this.groups = [];
/**
* A version number, incremented every time the attribute object or index object changes to mark VAO drity.
*/
this.version = 0;
},
/**
* Adds an attribute to this geometry.
* Use this rather than the attributes property.
* @param {string} name
* @param {BufferAttribute|InterleavedBufferAttribute} attribute
*/
addAttribute: function (name, attribute)
{
this.attributes[name] = attribute;
},
/**
* Returns the attribute with the specified name.
* @return {BufferAttribute|InterleavedBufferAttribute}
*/
getAttribute: function (name)
{
return this.attributes[name];
},
/**
* Removes the attribute with the specified name.
*/
removeAttribute: function (name)
{
delete this.attributes[name];
},
/**
* Set the index buffer.
* @param {Array|BufferAttribute} index
*/
setIndex: function (index)
{
if (Array.isArray(index))
{
this.index = new BufferAttribute(new Uint16Array(index), 1);
}
else
{
this.index = index;
}
},
/**
* Adds a group to this geometry; see the groups for details.
* @param {number} start
* @param {number} count
* @param {number} materialIndex
*/
addGroup: function (start, count, materialIndex)
{
this.groups.push({
start: start,
count: count,
materialIndex: materialIndex !== undefined ? materialIndex : 0
});
},
/**
* Clears all groups.
*/
clearGroups: function ()
{
this.groups = [];
},
/**
* Computes bounding box of the geometry, updating `boundingBox`.
* Bounding boxes aren't computed by default. They need to be explicitly computed.
*/
computeBoundingBox: function ()
{
var position = this.attributes['a_Position'] || this.attributes['position'];
if (position.isInterleavedBufferAttribute)
{
var data = position.data;
this.boundingBox.setFromArray(data.array, data.stride);
}
else
{
this.boundingBox.setFromArray(position.array, position.size);
}
},
/**
* Computes bounding sphere of the geometry, updating `boundingSphere`.
*
* Bounding spheres aren't computed by default. They need to be explicitly computed.
*/
computeBoundingSphere: function ()
{
var position = this.attributes['a_Position'] || this.attributes['position'];
if (position.isInterleavedBufferAttribute)
{
var data = position.data;
this.boundingSphere.setFromArray(data.array, data.stride);
}
else
{
this.boundingSphere.setFromArray(position.array, position.size);
}
},
/**
* Disposes the object from memory.
* You need to call this when you want the BufferGeometry removed while the application is running.
*/
dispose: function ()
{
// TODO
}
});
module.exports = Geometry;

View file

@ -0,0 +1,100 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2020 Photon Storm Ltd.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
var BufferAttribute = require('./BufferAttribute');
var Class = require('../../utils/Class');
var Geometry = require('./Geometry');
var PlaneGeometry = new Class({
Extends: Geometry,
initialize:
function PlaneGeometry (width, height, widthSegments, heightSegments)
{
Geometry.call(this);
this.build(width, height, widthSegments, heightSegments);
},
build: function (width, height, widthSegments, heightSegments)
{
width = width || 1;
height = height || 1;
var halfWidth = width / 2;
var halfHeight = height / 2;
var gridX = Math.floor(widthSegments) || 1;
var gridY = Math.floor(heightSegments) || 1;
var gridX1 = gridX + 1;
var gridY1 = gridY + 1;
var segmentWidth = width / gridX;
var segmentHeight = height / gridY;
var ix, iy;
// buffers
var indices = [];
var vertices = [];
var normals = [];
var uvs = [];
// generate vertices, normals and uvs
for (iy = 0; iy < gridY1; iy++)
{
var y = iy * segmentHeight - halfHeight;
for (ix = 0; ix < gridX1; ix++)
{
var x = ix * segmentWidth - halfWidth;
vertices.push(x, 0, y);
normals.push(0, 1, 0);
uvs.push(ix / gridX);
uvs.push(1 - (iy / gridY));
}
}
// indices
for (iy = 0; iy < gridY; iy++)
{
for (ix = 0; ix < gridX; ix++)
{
var a = ix + gridX1 * iy;
var b = ix + gridX1 * (iy + 1);
var c = (ix + 1) + gridX1 * (iy + 1);
var d = (ix + 1) + gridX1 * iy;
// faces
indices.push(a, b, d);
indices.push(b, c, d);
}
}
// build geometry
this.setIndex(indices);
this.addAttribute('a_Position', new BufferAttribute(new Float32Array(vertices), 3));
this.addAttribute('a_Normal', new BufferAttribute(new Float32Array(normals), 3));
this.addAttribute('a_Uv', new BufferAttribute(new Float32Array(uvs), 2));
this.computeBoundingBox();
this.computeBoundingSphere();
}
});
module.exports = PlaneGeometry;

View file

@ -0,0 +1,117 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2020 Photon Storm Ltd.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
var BufferAttribute = require('./BufferAttribute');
var Class = require('../../utils/Class');
var Geometry = require('./Geometry');
var Vector3 = require('../../math/Vector3');
var SphereGeometry = new Class({
Extends: Geometry,
initialize:
function SphereGeometry (radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength)
{
Geometry.call(this);
this.build(radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength);
},
build: function (radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength)
{
radius = radius || 1;
widthSegments = Math.max(3, Math.floor(widthSegments) || 8);
heightSegments = Math.max(2, Math.floor(heightSegments) || 6);
phiStart = phiStart !== undefined ? phiStart : 0;
phiLength = phiLength !== undefined ? phiLength : Math.PI * 2;
thetaStart = thetaStart !== undefined ? thetaStart : 0;
thetaLength = thetaLength !== undefined ? thetaLength : Math.PI;
var thetaEnd = thetaStart + thetaLength;
var ix, iy;
var index = 0;
var grid = [];
var vertex = new Vector3();
var normal = new Vector3();
// buffers
var indices = [];
var vertices = [];
var normals = [];
var uvs = [];
// generate vertices, normals and uvs
for (iy = 0; iy <= heightSegments; iy++)
{
var verticesRow = [];
var v = iy / heightSegments;
for (ix = 0; ix <= widthSegments; ix++)
{
var u = ix / widthSegments;
// vertex
vertex.x = -radius * Math.cos(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength);
vertex.y = radius * Math.cos(thetaStart + v * thetaLength);
vertex.z = radius * Math.sin(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength);
vertices.push(vertex.x, vertex.y, vertex.z);
// normal
normal.set(vertex.x, vertex.y, vertex.z).normalize();
normals.push(normal.x, normal.y, normal.z);
// uv
uvs.push(u, 1 - v);
verticesRow.push(index++);
}
grid.push(verticesRow);
}
// indices
for (iy = 0; iy < heightSegments; iy++)
{
for (ix = 0; ix < widthSegments; ix++)
{
var a = grid[iy][ix + 1];
var b = grid[iy][ix];
var c = grid[iy + 1][ix];
var d = grid[iy + 1][ix + 1];
if (iy !== 0 || thetaStart > 0) { indices.push(a, b, d); }
if (iy !== heightSegments - 1 || thetaEnd < Math.PI) { indices.push(b, c, d); }
}
}
this.setIndex(indices);
this.addAttribute('a_Position', new BufferAttribute(new Float32Array(vertices), 3));
this.addAttribute('a_Normal', new BufferAttribute(new Float32Array(normals), 3));
this.addAttribute('a_Uv', new BufferAttribute(new Float32Array(uvs), 2));
this.computeBoundingBox();
this.computeBoundingSphere();
}
});
module.exports = SphereGeometry;

View file

@ -0,0 +1,18 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2020 Photon Storm Ltd.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
/**
* @namespace Phaser.Layer3D.Geometry
*/
module.exports = {
BufferAttribute: require('./BufferAttribute'),
Geometry: require('./Geometry'),
PlaneGeometry: require('./PlaneGeometry'),
SphereGeometry: require('./SphereGeometry')
};