Merge branch 'master' of https://github.com/svipal/phaser into master

This commit is contained in:
Svipal 2020-09-19 11:04:49 +02:00
commit 7ca2f9f10b
17 changed files with 727 additions and 397 deletions

View file

@ -11,7 +11,9 @@ var GameObjectEvents = require('../events');
var GetCalcMatrix = require('../GetCalcMatrix');
var MeshRender = require('./MeshRender');
var MeshCamera = require('./MeshCamera');
var MeshLight = require('./MeshLight');
var Model = require('../../geom/mesh/Model');
var Vector3 = require('../../math/Vector3');
/**
* @classdesc
@ -84,6 +86,8 @@ var Mesh = new Class({
*/
this.camera = new MeshCamera(45, 0, 0, -10, 0.01, 1000);
this.light = new MeshLight();
/**
* An array of Model instances that have been created in this Mesh.
*
@ -152,7 +156,8 @@ var Mesh = new Class({
this.setSize(renderer.width, renderer.height);
this.initPipeline();
// TODO - Change to const
this.initPipeline('MeshPipeline');
if (vertices)
{
@ -324,6 +329,7 @@ var Mesh = new Class({
var vertices = modelData.vertices;
var textureCoords = modelData.textureCoords;
var normals = modelData.vertexNormals;
var faces = modelData.faces;
var defaultUV1 = { u: 0, v: 1 };
@ -334,14 +340,20 @@ var Mesh = new Class({
{
var face = faces[i];
// {textureCoordsIndex: 0, vertexIndex: 16, vertexNormalIndex: 16}
var v1 = face.vertices[0];
var v2 = face.vertices[1];
var v3 = face.vertices[2];
// {x: 0.19509, y: 0.980785, z: 0}
var m1 = vertices[v1.vertexIndex];
var m2 = vertices[v2.vertexIndex];
var m3 = vertices[v3.vertexIndex];
var n1 = normals[v1.vertexNormalIndex];
var n2 = normals[v2.vertexNormalIndex];
var n3 = normals[v3.vertexNormalIndex];
var t1 = v1.textureCoordsIndex;
var t2 = v2.textureCoordsIndex;
var t3 = v3.textureCoordsIndex;
@ -350,9 +362,9 @@ var Mesh = new Class({
var uv2 = (t2 === -1) ? defaultUV2 : textureCoords[t2];
var uv3 = (t3 === -1) ? defaultUV3 : textureCoords[t3];
var vert1 = model.addVertex(originX + m1.x * scale, originY + m1.y * scale, originZ + m1.z * scale, uv1.u, uv1.v);
var vert2 = model.addVertex(originX + m2.x * scale, originY + m2.y * scale, originZ + m2.z * scale, uv2.u, uv2.v);
var vert3 = model.addVertex(originX + m3.x * scale, originY + m3.y * scale, originZ + m3.z * scale, uv3.u, uv3.v);
var vert1 = model.addVertex(originX + m1.x * scale, originY + m1.y * scale, originZ + m1.z * scale, uv1.u, uv1.v, n1.x, n1.y, n1.z);
var vert2 = model.addVertex(originX + m2.x * scale, originY + m2.y * scale, originZ + m2.z * scale, uv2.u, uv2.v, n2.x, n2.y, n2.z);
var vert3 = model.addVertex(originX + m3.x * scale, originY + m3.y * scale, originZ + m3.z * scale, uv3.u, uv3.v, n3.x, n3.y, n3.z);
model.addFace(vert1, vert2, vert3);
}
@ -533,6 +545,7 @@ var Mesh = new Class({
var camera = this.camera;
/*
if (camera.dirty || width !== this._prevWidth || height !== this._prevHeight)
{
// Mesh has resized, flow that down to the Camera
@ -541,6 +554,9 @@ var Mesh = new Class({
this._prevWidth = width;
this._prevHeight = height;
}
*/
camera.update(width, height);
var models = this.models;

View file

@ -39,9 +39,10 @@ var MeshCamera = new Class({
this.up = new Vector4(); // What the up direction is, invert to get bottom
this.right = new Vector4(); // What the right direction is, invert to get left
this.matView = new Matrix4();
this.viewMatrix = new Matrix4();
this.projectionMatrix = new Matrix4();
this.matrix = new Matrix4(); // the transform matrix
this.viewMatrix = new Matrix4(); // the inverse of the transform matrix
this.projectionMatrix = new Matrix4(); // perspective projection matrix
this.viewProjectionMatrix = new Matrix4(); // perspective projection matrix multiplied by the view matrix
this.mode = MeshCamera.MODE_ORBIT;
},
@ -88,30 +89,20 @@ var MeshCamera = new Class({
// To have different modes of movements, this function handles the view matrix update for the transform object.
updateViewMatrix: function ()
{
var d = Math.PI / 180;
var matView = this.matView;
var rotation = this.rotation;
var matView = this.matrix;
matView.identity();
// Optimize camera transform update, no need for scale nor rotateZ
if (this.mode === MeshCamera.MODE_FREE)
{
matView.translate(this.position);
matView.rotateX(rotation.x * d);
matView.rotateY(rotation.y * d);
matView.fromRotationXYTranslation(this.rotation, this.position, true);
}
else
{
matView.rotateX(rotation.x * d);
matView.rotateY(rotation.y * d);
matView.translate(this.position);
matView.fromRotationXYTranslation(this.rotation, this.position, false);
}
this.updateDirection();
this.viewMatrix.copy(matView);
this.viewMatrix.invert();
this.viewMatrix.copy(matView).invert();
this.dirty = true;
},
@ -120,28 +111,21 @@ var MeshCamera = new Class({
{
this.aspectRatio = width / height;
this.updateViewMatrix();
// TODO - Only needs changing when the fov/etc does
this.projectionMatrix.perspective(DegToRad(this._fov), this.aspectRatio, this._near, this._far);
// TODO - Only needs calculating when this camera is dirty
this.projectionMatrix.multiplyToMat4(this.viewMatrix, this.viewProjectionMatrix);
},
updateDirection: function ()
{
var matView = this.matView;
var matView = this.matrix;
this.forward.set(0, 0, 1, 0).transformMat4(matView);
this.up.set(0, 1, 0, 0).transformMat4(matView);
this.right.set(1, 0, 0, 0).transformMat4(matView);
},
reset: function ()
{
this.position.set();
this.rotation.set();
this.updateViewMatrix();
},
fov: {
get: function ()

View file

@ -0,0 +1,103 @@
/**
* @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 Vector3 = require('../../math/Vector3');
/**
* @classdesc
* The Mesh Light.
*
* @class MeshLight
* @memberof Phaser.GameObjects
* @constructor
* @since 3.50.0
*/
var MeshLight = new Class({
initialize:
function MeshLight (x, y, z)
{
this.position = new Vector3(x, y, z);
this.ambient = new Vector3(1, 1, 1);
this.diffuse = new Vector3(1, 1, 1);
this.specular = new Vector3(1, 1, 1);
},
setPosition: function (x, y, z)
{
this.position.set(x, y, z);
return this;
},
setAmbient: function (r, g, b)
{
this.ambient.set(r, g, b);
return this;
},
setDiffuse: function (r, g, b)
{
this.diffuse.set(r, g, b);
return this;
},
setSpecular: function (r, g, b)
{
this.specular.set(r, g, b);
return this;
},
x: {
get: function ()
{
return this.position.x;
},
set: function (value)
{
this.position.x = value;
}
},
y: {
get: function ()
{
return this.position.y;
},
set: function (value)
{
this.position.y = value;
}
},
z: {
get: function ()
{
return this.position.z;
},
set: function (value)
{
this.position.z = value;
}
}
});
module.exports = MeshLight;

View file

@ -4,8 +4,6 @@
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
var GetCalcMatrix = require('../GetCalcMatrix');
/**
* Renders this Game Object with the WebGL Renderer to the given Camera.
* The object will not render if any of its renderFlags are set or it is being actively filtered out by the Camera.
@ -20,7 +18,7 @@ var GetCalcMatrix = require('../GetCalcMatrix');
* @param {Phaser.Cameras.Scene2D.Camera} camera - The Camera that is rendering the Game Object.
* @param {Phaser.GameObjects.Components.TransformMatrix} parentMatrix - This transform matrix is defined if the game object is nested
*/
var MeshWebGLRenderer = function (renderer, src, camera, parentMatrix)
var MeshWebGLRenderer = function (renderer, src)
{
var models = src.models;
var totalModels = models.length;
@ -30,88 +28,18 @@ var MeshWebGLRenderer = function (renderer, src, camera, parentMatrix)
return;
}
renderer.pipelines.clear();
var pipeline = renderer.pipelines.set(src.pipeline, src);
var calcMatrix = GetCalcMatrix(src, camera, parentMatrix).calc;
var vertexOffset = (pipeline.vertexCount * pipeline.vertexComponentCount) - 1;
var debugVerts;
var debugCallback = src.debugCallback;
var a = calcMatrix.a;
var b = calcMatrix.b;
var c = calcMatrix.c;
var d = calcMatrix.d;
var e = calcMatrix.e;
var f = calcMatrix.f;
var F32 = pipeline.vertexViewF32;
var U32 = pipeline.vertexViewU32;
var globalAlpha = camera.alpha * src.alpha;
for (var m = 0; m < totalModels; m++)
{
var model = models[m];
var faces = model.faces;
var totalFaces = faces.length;
var alpha = globalAlpha * model.alpha;
if (totalFaces === 0 || !model.visible || alpha <= 0)
{
continue;
}
if (debugCallback)
{
debugVerts = [];
}
var tintEffect = model.tintFill;
var textureUnit = pipeline.setGameObject(model);
for (var i = 0; i < totalFaces; i++)
{
var face = faces[i];
if (model.hideCCW && !face.isCounterClockwise())
{
continue;
}
if (pipeline.shouldFlush(3))
{
pipeline.flush();
vertexOffset = 0;
}
vertexOffset = face.vertex1.load(F32, U32, vertexOffset, textureUnit, tintEffect, alpha, a, b, c, d, e, f);
vertexOffset = face.vertex2.load(F32, U32, vertexOffset, textureUnit, tintEffect, alpha, a, b, c, d, e, f);
vertexOffset = face.vertex3.load(F32, U32, vertexOffset, textureUnit, tintEffect, alpha, a, b, c, d, e, f);
pipeline.vertexCount += 3;
if (debugCallback && model.drawDebug)
{
debugVerts.push(
F32[vertexOffset - 20],
F32[vertexOffset - 19],
F32[vertexOffset - 13],
F32[vertexOffset - 12],
F32[vertexOffset - 6],
F32[vertexOffset - 5]
);
}
}
if (debugCallback && model.drawDebug)
{
debugCallback.call(src, src, debugVerts);
}
pipeline.drawModel(src, model);
}
renderer.pipelines.rebind();
};
module.exports = MeshWebGLRenderer;

View file

@ -8,9 +8,8 @@ var AnimationState = require('../../animations/AnimationState');
var Class = require('../../utils/Class');
var Components = require('../../gameobjects/components');
var Face = require('./Face');
var GetCalcMatrix = require('../../gameobjects/GetCalcMatrix');
var Matrix4 = require('../../math/Matrix4');
var StableSort = require('../../utils/array/StableSort');
var Quaternion = require('../../math/Quaternion');
var Vector3 = require('../../math/Vector3');
var Vertex = require('./Vertex');
var WrapAngle = require('../../math/angle/Wrap');
@ -59,7 +58,7 @@ var Model = new Class({
*
* A Face consists of 3 Vertex objects.
*
* This array is populated during the `setVertices` method.
* This array is populated during the `addVertices` method.
*
* @name Phaser.Geom.Mesh.Model#faces
* @type {Phaser.Geom.Mesh.Face[]}
@ -78,39 +77,18 @@ var Model = new Class({
*/
this.vertices = [];
/**
* The tint fill mode.
*
* `false` = An additive tint (the default), where vertices colors are blended with the texture.
* `true` = A fill tint, where the vertices colors replace the texture, but respects texture alpha.
*
* @name Phaser.Geom.Mesh.Model#tintFill
* @type {boolean}
* @default false
* @since 3.50.0
*/
this.tintFill = false;
/**
* When rendering, skip any Face that isn't counter clockwise?
*
* Enable this to hide backward-facing Faces during rendering.
* Disable it to render all Faces.
*
* @name Phaser.Geom.Mesh.Model#hideCCW
* @type {boolean}
* @since 3.50.0
*/
this.hideCCW = true;
this.drawDebug = true;
this.position = new Vector3(x, y, z);
this.rotation = new Vector3();
this.scale = new Vector3(1, 1, 1);
this.rotation = new Quaternion();
this.dirtyCache = [ x, y, z, 0, 0, 0, 1, 1, 1, 0 ];
this.dirtyCache = [ x, y, z, 0, 0, 0, 0, 1, 1, 1, 0 ];
this.ambient = new Vector3(1, 1, 1);
this.diffuse = new Vector3(1, 1, 1);
this.specular = new Vector3(1, 1, 1);
this.shine = 0.25;
this.normalMatrix = new Matrix4();
this.transformMatrix = new Matrix4();
if (!texture)
@ -165,6 +143,7 @@ var Model = new Class({
var rx = rotation.x;
var ry = rotation.y;
var rz = rotation.z;
var rw = rotation.w;
var sx = scale.x;
var sy = scale.y;
@ -179,12 +158,13 @@ var Model = new Class({
var rxCached = dirtyCache[3];
var ryCached = dirtyCache[4];
var rzCached = dirtyCache[5];
var rwCached = dirtyCache[6];
var sxCached = dirtyCache[6];
var syCached = dirtyCache[7];
var szCached = dirtyCache[8];
var sxCached = dirtyCache[7];
var syCached = dirtyCache[8];
var szCached = dirtyCache[9];
var fCached = dirtyCache[9];
var fCached = dirtyCache[10];
dirtyCache[0] = px;
dirtyCache[1] = py;
@ -193,43 +173,40 @@ var Model = new Class({
dirtyCache[3] = rx;
dirtyCache[4] = ry;
dirtyCache[5] = rz;
dirtyCache[6] = rw;
dirtyCache[6] = sx;
dirtyCache[7] = sy;
dirtyCache[8] = sz;
dirtyCache[7] = sx;
dirtyCache[8] = sy;
dirtyCache[9] = sz;
dirtyCache[9] = faces;
dirtyCache[10] = faces;
return (
pxCached !== px || pyCached !== py || pzCached !== pz ||
rxCached !== rx || ryCached !== ry || rzCached !== rz ||
rxCached !== rx || ryCached !== ry || rzCached !== rz || rwCached !== rw ||
sxCached !== sx || syCached !== sy || szCached !== sz ||
fCached !== faces
);
},
preUpdate: function (time, delta, camera, width, height)
preUpdate: function (time, delta)
{
this.anims.update(time, delta);
if (!camera.dirty && !this.isDirty())
// If the model isn't dirty we can bail out and save lots of math
if (this.isDirty())
{
// If neither the camera or the model is dirty, we can bail out and save lots of math
return;
var normalMatrix = this.normalMatrix;
var transformMatrix = this.transformMatrix;
// TODO - No scale
transformMatrix.fromRotationTranslation(this.rotation, this.position);
transformMatrix.scale(this.scale);
normalMatrix.copy(transformMatrix);
normalMatrix.invert();
normalMatrix.transpose();
}
var transformMatrix = this.transformMatrix;
transformMatrix.setWorldMatrix(this.rotation, this.position, this.scale, camera.viewMatrix, camera.projectionMatrix);
var vertices = this.vertices;
for (var i = 0; i < vertices.length; i++)
{
vertices[i].transformCoordinatesLocal(transformMatrix, width, height);
}
this.depthSort();
},
/**
@ -273,79 +250,6 @@ var Model = new Class({
return this.faces[index];
},
/**
* Return an array of Face objects from this Mesh that intersect with the given coordinates.
*
* The given position is translated through the matrix of this Mesh and the given Camera,
* before being compared against the vertices.
*
* If more than one Face intersects, they will all be returned in the array, but the array will
* be depth sorted first, so the first element will always be that closest to the camera.
*
* @method Phaser.Geom.Mesh.Model#getFaceAt
* @since 3.50.0
*
* @param {number} x - The x position to check against.
* @param {number} y - The y position to check against.
* @param {Phaser.Cameras.Scene2D.Camera} [camera] - The camera to pass the coordinates through. If not given, the default Scene Camera is used.
*
* @return {Phaser.Geom.Mesh.Face[]} An array of Face objects that intersect with the given point, ordered by depth.
*/
getFaceAt: function (x, y, camera, calcMatrix)
{
if (camera === undefined) { camera = this.scene.sys.cameras.main; }
if (calcMatrix === undefined) { calcMatrix = GetCalcMatrix(this.mesh, camera).calc; }
var faces = this.faces;
var results = [];
for (var i = 0; i < faces.length; i++)
{
var face = faces[i];
if (face.contains(x, y, calcMatrix))
{
results.push(face);
}
}
return StableSort(results, this.sortByDepth);
},
/**
* Runs a depth sort across all Faces in this Mesh, comparing their averaged depth.
*
* This is called automatically if you use any of the `rotate` methods, but you can
* also invoke it to sort the Faces should you manually position them.
*
* @method Phaser.Geom.Mesh.Model#depthSort
* @since 3.50.0
*
* @return {this} This Mesh Game Object.
*/
depthSort: function ()
{
StableSort(this.faces, this.sortByDepth);
return this;
},
/**
* Compare the depth of two Faces.
*
* @method Phaser.Geom.Mesh.Model#sortByDepth
* @since 3.50.0
*
* @param {Phaser.Geom.Mesh.Face} faceA - The first Face.
* @param {Phaser.Geom.Mesh.Face} faceB - The second Face.
*
* @return {integer} The difference between the depths of each Face.
*/
sortByDepth: function (faceA, faceB)
{
return faceA.depth - faceB.depth;
},
/**
* Adds a new Vertex into the vertices array of this Mesh.
*
@ -513,102 +417,6 @@ var Model = new Class({
return this;
},
/**
* Rotates all vertices of this Mesh around the X axis by the amount given.
*
* It then runs a depth sort on the faces before returning.
*
* @method Phaser.Geom.Mesh.Model#rotateVerticesX
* @since 3.50.0
*
* @param {number} theta - The amount to rotate by in radians.
*
* @return {this} This Mesh Game Object.
*/
rotateVerticesX: function (theta)
{
var ts = Math.sin(theta);
var tc = Math.cos(theta);
var verts = this.vertices;
for (var n = 0; n < verts.length; n++)
{
var vert = verts[n];
var y = vert.y;
var z = vert.z;
vert.y = y * tc - z * ts;
vert.z = z * tc + y * ts;
}
return this.depthSort();
},
/**
* Rotates all vertices of this Mesh around the Y axis by the amount given.
*
* It then runs a depth sort on the faces before returning.
*
* @method Phaser.Geom.Mesh.Model#rotateVerticesY
* @since 3.50.0
*
* @param {number} theta - The amount to rotate by in radians.
*
* @return {this} This Mesh Game Object.
*/
rotateVerticesY: function (theta)
{
var ts = Math.sin(theta);
var tc = Math.cos(theta);
var verts = this.vertices;
for (var n = 0; n < verts.length; n++)
{
var vert = verts[n];
var x = vert.x;
var z = vert.z;
vert.x = x * tc - z * ts;
vert.z = z * tc + x * ts;
}
return this.depthSort();
},
/**
* Rotates all vertices of this Mesh around the Z axis by the amount given.
*
* It then runs a depth sort on the faces before returning.
*
* @method Phaser.Geom.Mesh.Model#rotateVerticesZ
* @since 3.50.0
*
* @param {number} theta - The amount to rotate by in radians.
*
* @return {this} This Mesh Game Object.
*/
rotateVerticesZ: function (theta)
{
var ts = Math.sin(theta);
var tc = Math.cos(theta);
var verts = this.vertices;
for (var n = 0; n < verts.length; n++)
{
var vert = verts[n];
var x = vert.x;
var y = vert.y;
vert.x = x * tc - y * ts;
vert.y = y * tc + x * ts;
}
return this.depthSort();
},
x: {
get: function ()

View file

@ -5,8 +5,6 @@
*/
var Class = require('../../utils/Class');
var Vector3 = require('../../math/Vector3');
var Utils = require('../../renderer/webgl/Utils');
/**
* @classdesc
@ -17,7 +15,6 @@ var Utils = require('../../renderer/webgl/Utils');
*
* @class Vertex
* @memberof Phaser.Geom.Mesh
* @extends Phaser.Math.Vector3
* @constructor
* @since 3.50.0
*
@ -31,43 +28,69 @@ var Utils = require('../../renderer/webgl/Utils');
*/
var Vertex = new Class({
Extends: Vector3,
initialize:
function Vertex (x, y, z, u, v, color, alpha)
function Vertex (x, y, z, u, v, normalX, normalY, normalZ, color, alpha)
{
if (normalX === undefined) { normalX = 0; }
if (normalY === undefined) { normalY = 0; }
if (normalZ === undefined) { normalZ = 0; }
if (color === undefined) { color = 0xffffff; }
if (alpha === undefined) { alpha = 1; }
Vector3.call(this, x, y, z);
/**
* The projected x coordinate of this vertex.
* The x coordinate of this vertex.
*
* @name Phaser.Geom.Mesh.Vertex#vx
* @type {number}
* @since 3.50.0
*/
this.vx = 0;
this.x = x;
/**
* The projected y coordinate of this vertex.
* The y coordinate of this vertex.
*
* @name Phaser.Geom.Mesh.Vertex#vy
* @type {number}
* @since 3.50.0
*/
this.vy = 0;
this.y = y;
/**
* The projected z coordinate of this vertex.
* The z coordinate of this vertex.
*
* @name Phaser.Geom.Mesh.Vertex#vz
* @type {number}
* @since 3.50.0
*/
this.vz = 0;
this.z = z;
/**
* The x normal of this vertex.
*
* @name Phaser.Geom.Mesh.Vertex#nx
* @type {number}
* @since 3.50.0
*/
this.nx = normalX;
/**
* The y normal of this vertex.
*
* @name Phaser.Geom.Mesh.Vertex#ny
* @type {number}
* @since 3.50.0
*/
this.ny = normalY;
/**
* The z normal of this vertex.
*
* @name Phaser.Geom.Mesh.Vertex#nz
* @type {number}
* @since 3.50.0
*/
this.nz = normalZ;
/**
* UV u coordinate of this vertex.
@ -115,7 +138,6 @@ var Vertex = new Class({
* @param {Phaser.Math.Matrix4} transformMatrix - The transform matrix to apply to this vertex.
* @param {number} width - The width of the parent Mesh.
* @param {number} height - The height of the parent Mesh.
*/
transformCoordinatesLocal: function (transformMatrix, width, height)
{
var x = this.x;
@ -133,39 +155,7 @@ var Vertex = new Class({
this.vy = -(ty / tw) * height;
this.vz = (tz / tw);
},
/**
* Loads this vertex into the given Typed Arrays.
*
* @method Phaser.Geom.Mesh.Model#load
* @since 3.50.0
*
* @param {Float32Array} F32 - The Float32 Array to put the position data in.
* @param {Uint32Array} U32 - The Uint32 Array to put the color data in.
* @param {number} offset - The vertex offset to place the data at.
* @param {number} textureUnit - The currently bound texture unit.
* @param {number} alpha - The alpha value.
* @param {number} a - The transform matrix a value.
* @param {number} b - The transform matrix b value.
* @param {number} c - The transform matrix c value.
* @param {number} d - The transform matrix d value.
* @param {number} e - The transform matrix e value.
* @param {number} f - The transform matrix f value.
*
* @return {number} The new vertex offset.
*/
load: function (F32, U32, offset, textureUnit, tintEffect, alpha, a, b, c, d, e, f)
{
F32[++offset] = this.vx * a + this.vy * c + e;
F32[++offset] = this.vx * b + this.vy * d + f;
F32[++offset] = this.u;
F32[++offset] = this.v;
F32[++offset] = textureUnit;
F32[++offset] = tintEffect;
U32[++offset] = Utils.getTintAppendFloatAlpha(this.color, alpha * this.alpha);
return offset;
}
});

View file

@ -79,6 +79,90 @@ var Matrix4 = new Class({
return this.copy(src);
},
// TODO - Docs
fromRotationXYTranslation: function (rotation, position, translateFirst)
{
var x = position.x;
var y = position.y;
var z = position.z;
var sx = Math.sin(rotation.x);
var cx = Math.cos(rotation.x);
var sy = Math.sin(rotation.y);
var cy = Math.cos(rotation.y);
var a30 = x;
var a31 = y;
var a32 = z;
// Rotate X
var b21 = -sx;
// Rotate Y
var c01 = 0 - b21 * sy;
var c02 = 0 - cx * sy;
var c21 = b21 * cy;
var c22 = cx * cy;
// Translate
if (!translateFirst)
{
// a30 = cy * x + 0 * y + sy * z;
a30 = cy * x + sy * z;
a31 = c01 * x + cx * y + c21 * z;
a32 = c02 * x + sx * y + c22 * z;
}
return this.setValues(
cy,
c01,
c02,
0,
0,
cx,
sx,
0,
sy,
c21,
c22,
0,
a30,
a31,
a32,
1
);
},
setValues: function (m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33)
{
var out = this.val;
out[0] = m00;
out[1] = m01;
out[2] = m02;
out[3] = m03;
out[4] = m10;
out[5] = m11;
out[6] = m12;
out[7] = m13;
out[8] = m20;
out[9] = m21;
out[10] = m22;
out[11] = m23;
out[12] = m30;
out[13] = m31;
out[14] = m32;
out[15] = m33;
return this;
},
/**
* Copy the values of a given Matrix into this Matrix.
*
@ -478,6 +562,69 @@ var Matrix4 = new Class({
return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
},
// TODO - Docs
multiplyToMat4: function (src, out)
{
var a = this.val;
var b = src.val;
var a00 = a[0];
var a01 = a[1];
var a02 = a[2];
var a03 = a[3];
var a10 = a[4];
var a11 = a[5];
var a12 = a[6];
var a13 = a[7];
var a20 = a[8];
var a21 = a[9];
var a22 = a[10];
var a23 = a[11];
var a30 = a[12];
var a31 = a[13];
var a32 = a[14];
var a33 = a[15];
var b00 = b[0];
var b01 = b[1];
var b02 = b[2];
var b03 = b[3];
var b10 = b[4];
var b11 = b[5];
var b12 = b[6];
var b13 = b[7];
var b20 = b[8];
var b21 = b[9];
var b22 = b[10];
var b23 = b[11];
var b30 = b[12];
var b31 = b[13];
var b32 = b[14];
var b33 = b[15];
return out.setValues(
b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30,
b01 * a01 + b01 * a11 + b02 * a21 + b03 * a31,
b02 * a02 + b01 * a12 + b02 * a22 + b03 * a32,
b03 * a03 + b01 * a13 + b02 * a23 + b03 * a33,
b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30,
b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31,
b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32,
b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33,
b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30,
b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31,
b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32,
b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33,
b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30,
b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31,
b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32,
b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33
);
},
/**
* Multiply this Matrix by the given Matrix.
*

View file

@ -11,6 +11,7 @@ var CONST = require('./pipelines/const');
// Default Phaser 3 Pipelines
var BitmapMaskPipeline = require('./pipelines/BitmapMaskPipeline');
var LightPipeline = require('./pipelines/LightPipeline');
var MeshPipeline = require('./pipelines/MeshPipeline');
var MultiPipeline = require('./pipelines/MultiPipeline');
var RopePipeline = require('./pipelines/RopePipeline');
var SinglePipeline = require('./pipelines/SinglePipeline');
@ -131,6 +132,7 @@ var PipelineManager = new Class({
this.add(CONST.SINGLE_PIPELINE, new SinglePipeline({ game: game }));
this.add(CONST.ROPE_PIPELINE, new RopePipeline({ game: game }));
this.add(CONST.LIGHT_PIPELINE, new LightPipeline({ game: game }));
this.add(CONST.MESH_PIPELINE, new MeshPipeline({ game: game }));
this.set(this.MULTI_PIPELINE);
},

View file

@ -126,13 +126,19 @@ var WebGLPipeline = new Class({
this.vertexCapacity = GetFastValue(config, 'vertexCapacity', renderer.config.batchSize * 6);
/**
* The size in bytes of a vertex.
* The size, in bytes, of a single vertex.
*
* Derived by adding together all of the vertex attributes.
* This is derived by adding together all of the vertex attributes.
*
* For example, the Texture Tint Pipeline has 2 + 2 + 1 + 1 + 4 for the attributes
* `inPosition` (size 2), `inTexCoord` (size 2), `inTexId` (size 1), `inTintEffect` (size 1)
* and `inTint` (size 4), for a total of 28, which is the default for this property.
* For example, the Multi Pipeline has the following attributes:
*
* inPosition - (size 2 x gl.FLOAT) = 8
* inTexCoord - (size 2 x gl.FLOAT) = 8
* inTexId - (size 1 x gl.FLOAT) = 4
* inTintEffect - (size 1 x gl.FLOAT) = 4
* inTint - (size 4 x gl.UNSIGNED_BYTE) = 4
*
* The total is 8 + 8 + 4 + 4 + 4 = 28, which is the default for this property.
*
* @name Phaser.Renderer.WebGL.WebGLPipeline#vertexSize
* @type {integer}
@ -459,13 +465,16 @@ var WebGLPipeline = new Class({
},
/**
* Set whenever this WebGL Pipeline is bound to a WebGL Renderer.
* This method is called every time a Game Object asks the Pipeline Manager to use this pipeline.
*
* This method is called every time the WebGL Pipeline is attempted to be bound, even if it already is the current pipeline.
* Unlike the `bind` method, which is only called once per frame, this is called for every object
* that requests it, allowing you to perform per-object GL set-up.
*
* @method Phaser.Renderer.WebGL.WebGLPipeline#onBind
* @since 3.0.0
*
* @param {Phaser.GameObjects.GameObject} [gameObject] - The Game Object that invoked this pipeline, if any.
*
* @return {this} This WebGLPipeline instance.
*/
onBind: function ()

View file

@ -0,0 +1,190 @@
/**
* @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 GetFastValue = require('../../../utils/object/GetFastValue');
var ShaderSourceFS = require('../shaders/Mesh-frag.js');
var ShaderSourceVS = require('../shaders/Mesh-vert.js');
var WebGLPipeline = require('../WebGLPipeline');
/**
* @classdesc
* TODO
*
* @class MeshPipeline
* @extends Phaser.Renderer.WebGL.WebGLPipeline
* @memberof Phaser.Renderer.WebGL.Pipelines
* @constructor
* @since 3.50.0
*
* @param {Phaser.Types.Renderer.WebGL.WebGLPipelineConfig} config - The configuration options for this pipeline.
*/
var MeshPipeline = new Class({
Extends: WebGLPipeline,
initialize:
function MeshPipeline (config)
{
var gl = config.game.renderer.gl;
config.fragShader = GetFastValue(config, 'fragShader', ShaderSourceFS),
config.vertShader = GetFastValue(config, 'vertShader', ShaderSourceVS),
config.vertexCapacity = GetFastValue(config, 'vertexCapacity', 2048 * 8),
config.vertexSize = GetFastValue(config, 'vertexSize', 32),
config.attributes = GetFastValue(config, 'attributes', [
{
name: 'aVertexPosition',
size: 3,
type: gl.FLOAT,
normalized: false,
offset: 0,
enabled: false,
location: -1
},
{
name: 'aVertexNormal',
size: 3,
type: gl.FLOAT,
normalized: false,
offset: 12,
enabled: false,
location: -1
},
{
name: 'aTextureCoord',
size: 2,
type: gl.FLOAT,
normalized: false,
offset: 24,
enabled: false,
location: -1
}
]);
WebGLPipeline.call(this, config);
/**
* Float32 view of the array buffer containing the pipeline's vertices.
*
* @name Phaser.Renderer.WebGL.Pipelines.MeshPipeline#vertexViewF32
* @type {Float32Array}
* @since 3.0.0
*/
this.vertexViewF32 = new Float32Array(this.vertexData);
this.forceZero = true;
},
/**
* Called every time the pipeline is bound by the renderer.
* Sets the shader program, vertex buffer and other resources.
* Should only be called when changing pipeline.
*
* @method Phaser.Renderer.WebGL.Pipelines.MeshPipeline#bind
* @since 3.50.0
*
* @param {boolean} [reset=false] - Should the pipeline be fully re-bound after a renderer pipeline clear?
*
* @return {this} This WebGLPipeline instance.
*/
bind: function (reset)
{
if (reset === undefined) { reset = false; }
WebGLPipeline.prototype.bind.call(this, reset);
var gl = this.gl;
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
gl.cullFace(gl.BACK);
return this;
},
/**
* This method is called every time a Game Object asks the Pipeline Manager to use this pipeline.
*
* Unlike the `bind` method, which is only called once per frame, this is called for every object
* that requests it, allowing you to perform per-object GL set-up.
*
* @method Phaser.Renderer.WebGL.Pipelines.MeshPipeline#onBind
* @since 3.50.0
*
* @param {Phaser.GameObjects.Mesh} mesh - The Mesh that requested this pipeline.
*
* @return {this} This WebGLPipeline instance.
*/
onBind: function (mesh)
{
var program = this.program;
var renderer = this.renderer;
var camera = mesh.camera;
var light = mesh.light;
renderer.setMatrix4(program, 'uViewProjectionMatrix', false, camera.viewProjectionMatrix.val);
renderer.setFloat3(program, 'uLightPosition', light.x, light.y, light.z);
renderer.setFloat3(program, 'uLightAmbient', light.ambient.x, light.ambient.y, light.ambient.z);
renderer.setFloat3(program, 'uLightDiffuse', light.diffuse.x, light.diffuse.y, light.diffuse.z);
renderer.setFloat3(program, 'uLightSpecular', light.specular.x, light.specular.y, light.specular.z);
renderer.setFloat3(program, 'uCameraPosition', camera.x, camera.y, camera.z);
},
drawModel: function (mesh, model)
{
var program = this.program;
var renderer = this.renderer;
renderer.setMatrix4(program, 'uModelMatrix', false, model.transformMatrix.val);
renderer.setMatrix4(program, 'uNormalMatrix', false, model.normalMatrix.val);
renderer.setFloat3(program, 'uMaterialAmbient', model.ambient.x, model.ambient.y, model.ambient.z);
renderer.setFloat3(program, 'uMaterialDiffuse', model.diffuse.x, model.diffuse.y, model.diffuse.z);
renderer.setFloat3(program, 'uMaterialSpecular', model.specular.x, model.specular.y, model.specular.z);
renderer.setFloat1(program, 'uMaterialShine', model.shine);
renderer.setTextureZero(model.frame.glTexture);
renderer.setInt1(program, 'uTexture', 0);
// All the uniforms are finally bound, so now lets draw our faces!
var vertexViewF32 = this.vertexViewF32;
var vertices = model.vertices;
for (var i = 0; i < vertices.length; i++)
{
if (this.shouldFlush(1))
{
this.flush();
}
var vertexOffset = (this.vertexCount * this.vertexComponentCount) - 1;
var vert = vertices[i];
vertexViewF32[++vertexOffset] = vert.x;
vertexViewF32[++vertexOffset] = vert.y;
vertexViewF32[++vertexOffset] = vert.z;
vertexViewF32[++vertexOffset] = vert.nx;
vertexViewF32[++vertexOffset] = vert.ny;
vertexViewF32[++vertexOffset] = vert.nz;
vertexViewF32[++vertexOffset] = vert.u;
vertexViewF32[++vertexOffset] = vert.v;
this.vertexCount++;
}
this.flush();
}
});
module.exports = MeshPipeline;

View file

@ -156,7 +156,7 @@ var SinglePipeline = new Class({
var hasFlushed = false;
if (this.vertexCount + 6 > this.vertexCapacity)
if (this.shouldFlush(6))
{
this.flush();
@ -260,7 +260,7 @@ var SinglePipeline = new Class({
var hasFlushed = false;
if (this.vertexCount + 3 > this.vertexCapacity)
if (this.shouldFlush(3))
{
this.flush();

View file

@ -54,7 +54,17 @@ var PIPELINE_CONST = {
* @const
* @since 3.50.0
*/
ROPE_PIPELINE: 'RopePipeline'
ROPE_PIPELINE: 'RopePipeline',
/**
* The Mesh Pipeline.
*
* @name Phaser.Renderer.WebGL.Pipelines.MESH_PIPELINE
* @type {string}
* @const
* @since 3.50.0
*/
MESH_PIPELINE: 'MeshPipeline'
};

View file

@ -15,10 +15,11 @@ var Pipelines = {
BitmapMaskPipeline: require('./BitmapMaskPipeline'),
LightPipeline: require('./LightPipeline'),
SinglePipeline: require('./SinglePipeline'),
MeshPipeline: require('./MeshPipeline'),
ModelViewProjection: require('./components/ModelViewProjection'),
MultiPipeline: require('./MultiPipeline'),
RopePipeline: require('./RopePipeline'),
ModelViewProjection: require('./components/ModelViewProjection')
SinglePipeline: require('./SinglePipeline')
};

View file

@ -0,0 +1,45 @@
module.exports = [
'#define SHADER_NAME PHASER_MESH_FS',
'',
'precision mediump float;',
'',
'uniform vec3 uLightPosition;',
'uniform vec3 uLightAmbient;',
'uniform vec3 uLightDiffuse;',
'uniform vec3 uLightSpecular;',
'',
'uniform vec3 uMaterialAmbient;',
'uniform vec3 uMaterialDiffuse;',
'uniform vec3 uMaterialSpecular;',
'uniform float uMaterialShine;',
'',
'uniform vec3 uCameraPosition;',
'',
'uniform sampler2D uTexture;',
'',
'varying vec2 vTextureCoord;',
'varying vec3 vNormal;',
'varying vec3 vPosition;',
'',
'void main (void)',
'{',
' vec4 color = texture2D(uTexture, vTextureCoord);',
'',
' vec3 ambient = uLightAmbient * uMaterialAmbient;',
'',
' vec3 norm = normalize(vNormal);',
' vec3 lightDir = normalize(uLightPosition - vPosition);',
' float diff = max(dot(norm, lightDir), 0.0);',
' vec3 diffuse = uLightDiffuse * (diff * uMaterialDiffuse);',
'',
' vec3 viewDir = normalize(uCameraPosition - vPosition);',
' vec3 reflectDir = reflect(-lightDir, norm);',
' float spec = pow(max(dot(viewDir, reflectDir), 0.0), uMaterialShine);',
' vec3 specular = uLightSpecular * (spec * uMaterialSpecular);',
'',
' vec3 result = (ambient + diffuse + specular) * color.rgb;',
'',
' gl_FragColor = vec4(result, color.a);',
'}',
''
].join('\n');

View file

@ -0,0 +1,29 @@
module.exports = [
'#define SHADER_NAME PHASER_MESH_VS',
'',
'precision mediump float;',
'',
'attribute vec3 aVertexPosition;',
'attribute vec3 aVertexNormal;',
'attribute vec2 aTextureCoord;',
'',
'uniform mat4 uViewProjectionMatrix;',
'uniform mat4 uModelMatrix;',
'uniform mat4 uNormalMatrix;',
'',
'varying vec2 vTextureCoord;',
'varying vec3 vNormal;',
'varying vec3 vPosition;',
'',
'void main ()',
'{',
' vTextureCoord = aTextureCoord;',
'',
' vPosition = vec3(uModelMatrix * vec4(aVertexPosition, 1.0));',
'',
' vNormal = vec3(uNormalMatrix * vec4(aVertexNormal, 1.0));',
'',
' gl_Position = uViewProjectionMatrix * uModelMatrix * vec4(aVertexPosition, 1.0);',
'}',
''
].join('\n');

View file

@ -0,0 +1,42 @@
#define SHADER_NAME PHASER_MESH_FS
precision mediump float;
uniform vec3 uLightPosition;
uniform vec3 uLightAmbient;
uniform vec3 uLightDiffuse;
uniform vec3 uLightSpecular;
uniform vec3 uMaterialAmbient;
uniform vec3 uMaterialDiffuse;
uniform vec3 uMaterialSpecular;
uniform float uMaterialShine;
uniform vec3 uCameraPosition;
uniform sampler2D uTexture;
varying vec2 vTextureCoord;
varying vec3 vNormal;
varying vec3 vPosition;
void main (void)
{
vec4 color = texture2D(uTexture, vTextureCoord);
vec3 ambient = uLightAmbient * uMaterialAmbient;
vec3 norm = normalize(vNormal);
vec3 lightDir = normalize(uLightPosition - vPosition);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = uLightDiffuse * (diff * uMaterialDiffuse);
vec3 viewDir = normalize(uCameraPosition - vPosition);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), uMaterialShine);
vec3 specular = uLightSpecular * (spec * uMaterialSpecular);
vec3 result = (ambient + diffuse + specular) * color.rgb;
gl_FragColor = vec4(result, color.a);
}

View file

@ -0,0 +1,26 @@
#define SHADER_NAME PHASER_MESH_VS
precision mediump float;
attribute vec3 aVertexPosition;
attribute vec3 aVertexNormal;
attribute vec2 aTextureCoord;
uniform mat4 uViewProjectionMatrix;
uniform mat4 uModelMatrix;
uniform mat4 uNormalMatrix;
varying vec2 vTextureCoord;
varying vec3 vNormal;
varying vec3 vPosition;
void main ()
{
vTextureCoord = aTextureCoord;
vPosition = vec3(uModelMatrix * vec4(aVertexPosition, 1.0));
vNormal = vec3(uNormalMatrix * vec4(aVertexNormal, 1.0));
gl_Position = uViewProjectionMatrix * uModelMatrix * vec4(aVertexPosition, 1.0);
}