mirror of
https://github.com/photonstorm/phaser
synced 2024-11-22 04:33:31 +00:00
Merged the Layer3D Game Object and pipeline back in for now
This commit is contained in:
parent
c3fe480905
commit
dda4431366
19 changed files with 3395 additions and 1 deletions
214
src/display/RGB.js
Normal file
214
src/display/RGB.js
Normal file
|
@ -0,0 +1,214 @@
|
|||
/**
|
||||
* @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 NOOP = require('../utils/NOOP');
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* The RGB class holds a single color value and allows for easy modification and reading of it,
|
||||
* with optional on-change callback notification and a dirty flag.
|
||||
*
|
||||
* @class RGB
|
||||
* @memberof Phaser.Display
|
||||
* @constructor
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {number} [red=0] - The red color value. A number between 0 and 1.
|
||||
* @param {number} [green=0] - The green color value. A number between 0 and 1.
|
||||
* @param {number} [blue=0] - The blue color value. A number between 0 and 1.
|
||||
*/
|
||||
var RGB = new Class({
|
||||
|
||||
initialize:
|
||||
|
||||
function RGB (red, green, blue)
|
||||
{
|
||||
/**
|
||||
* Cached RGB values.
|
||||
*
|
||||
* @name Phaser.Display.RGB#_rgb
|
||||
* @type {number[]}
|
||||
* @private
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this._rgb = [ 0, 0, 0 ];
|
||||
|
||||
/**
|
||||
* This callback will be invoked each time one of the RGB color values change.
|
||||
*
|
||||
* The callback is sent the new color values as the parameters.
|
||||
*
|
||||
* @name Phaser.Display.RGB#onChangeCallback
|
||||
* @type {function}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.onChangeCallback = NOOP;
|
||||
|
||||
/**
|
||||
* Is this color dirty?
|
||||
*
|
||||
* @name Phaser.Display.RGB#dirty
|
||||
* @type {boolean}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.dirty = false;
|
||||
|
||||
this.set(red, green, blue);
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the red, green and blue values of this RGB object, flags it as being
|
||||
* dirty and then invokes the `onChangeCallback`, if set.
|
||||
*
|
||||
* @method Phaser.Display.RGB#set
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {number} [red=0] - The red color value. A number between 0 and 1.
|
||||
* @param {number} [green=0] - The green color value. A number between 0 and 1.
|
||||
* @param {number} [blue=0] - The blue color value. A number between 0 and 1.
|
||||
*
|
||||
* @return {this} This RGB instance.
|
||||
*/
|
||||
set: function (red, green, blue)
|
||||
{
|
||||
if (red === undefined) { red = 0; }
|
||||
if (green === undefined) { green = 0; }
|
||||
if (blue === undefined) { blue = 0; }
|
||||
|
||||
this._rgb = [ red, green, blue ];
|
||||
|
||||
this.onChange();
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Compares the given rgb parameters with those in this object and returns
|
||||
* a boolean `true` value if they are equal, otherwise it returns `false`.
|
||||
*
|
||||
* @method Phaser.Display.RGB#equals
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {number} red - The red value to compare with this object.
|
||||
* @param {number} green - The green value to compare with this object.
|
||||
* @param {number} blue - The blue value to compare with this object.
|
||||
*
|
||||
* @return {boolean} `true` if the given values match those in this object, otherwise `false`.
|
||||
*/
|
||||
equals: function (red, green, blue)
|
||||
{
|
||||
var rgb = this._rgb;
|
||||
|
||||
return (rgb.r === red && rgb.g === green && rgb.b === blue);
|
||||
},
|
||||
|
||||
/**
|
||||
* Internal on change handler. Sets this object as being dirty and
|
||||
* then invokes the `onChangeCallback`, if set, passing in the
|
||||
* new RGB values.
|
||||
*
|
||||
* @method Phaser.Display.RGB#onChange
|
||||
* @since 3.50.0
|
||||
*/
|
||||
onChange: function ()
|
||||
{
|
||||
this.dirty = true;
|
||||
|
||||
var rgb = this._rgb;
|
||||
|
||||
this.onChangeCallback.call(this, rgb[0], rgb[1], rgb[2]);
|
||||
},
|
||||
|
||||
/**
|
||||
* The red color value. Between 0 and 1.
|
||||
*
|
||||
* Changing this property will flag this RGB object as being dirty
|
||||
* and invoke the `onChangeCallback` , if set.
|
||||
*
|
||||
* @name Phaser.Display.RGB#r
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
r: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this._rgb[0];
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
this._rgb[0] = value;
|
||||
this.onChange();
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* The green color value. Between 0 and 1.
|
||||
*
|
||||
* Changing this property will flag this RGB object as being dirty
|
||||
* and invoke the `onChangeCallback` , if set.
|
||||
*
|
||||
* @name Phaser.Display.RGB#g
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
g: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this._rgb[1];
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
this._rgb[1] = value;
|
||||
this.onChange();
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* The blue color value. Between 0 and 1.
|
||||
*
|
||||
* Changing this property will flag this RGB object as being dirty
|
||||
* and invoke the `onChangeCallback` , if set.
|
||||
*
|
||||
* @name Phaser.Display.RGB#b
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
b: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this._rgb[2];
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
this._rgb[2] = value;
|
||||
this.onChange();
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Nulls any external references this object contains.
|
||||
*
|
||||
* @method Phaser.Display.RGB#destroy
|
||||
* @since 3.50.0
|
||||
*/
|
||||
destroy: function ()
|
||||
{
|
||||
this.onChangeCallback = null;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
module.exports = RGB;
|
|
@ -124,12 +124,15 @@ if (typeof WEBGL_RENDERER)
|
|||
// WebGL only Game Objects
|
||||
GameObjects.Shader = require('./shader/Shader');
|
||||
GameObjects.Mesh = require('./mesh/Mesh');
|
||||
GameObjects.Layer3D = require('./layer3d/Layer3D');
|
||||
|
||||
GameObjects.Factories.Shader = require('./shader/ShaderFactory');
|
||||
GameObjects.Factories.Mesh = require('./mesh/MeshFactory');
|
||||
GameObjects.Factories.Layer3D = require('./layer3d/Layer3DFactory');
|
||||
|
||||
GameObjects.Creators.Shader = require('./shader/ShaderCreator');
|
||||
GameObjects.Creators.Mesh = require('./mesh/MeshCreator');
|
||||
GameObjects.Creators.Layer3D = require('./layer3d/Layer3DCreator');
|
||||
|
||||
GameObjects.Light = require('./lights/Light');
|
||||
GameObjects.LightsManager = require('./lights/LightsManager');
|
||||
|
|
575
src/gameobjects/layer3d/Layer3D.js
Normal file
575
src/gameobjects/layer3d/Layer3D.js
Normal file
|
@ -0,0 +1,575 @@
|
|||
/**
|
||||
* @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 Components = require('../components');
|
||||
var CONST = require('../../renderer/webgl/pipelines/const');
|
||||
var GameObject = require('../GameObject');
|
||||
var GameObjectEvents = require('../events');
|
||||
var Layer3DCamera = require('./Layer3DCamera');
|
||||
var Layer3DLight = require('./Layer3DLight');
|
||||
var Layer3DRender = require('./Layer3DRender');
|
||||
var Model = require('../../geom/mesh/Model');
|
||||
var RGB = require('../../display/RGB');
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* A Layer3D Game Object.
|
||||
*
|
||||
* The Mesh object is WebGL only and does not have a Canvas counterpart.
|
||||
*
|
||||
* TODO - Finish this.
|
||||
*
|
||||
* @class Layer3D
|
||||
* @extends Phaser.GameObjects.GameObject
|
||||
* @memberof Phaser.GameObjects
|
||||
* @constructor
|
||||
* @webglOnly
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @extends Phaser.GameObjects.Components.AlphaSingle
|
||||
* @extends Phaser.GameObjects.Components.BlendMode
|
||||
* @extends Phaser.GameObjects.Components.Depth
|
||||
* @extends Phaser.GameObjects.Components.Mask
|
||||
* @extends Phaser.GameObjects.Components.Pipeline
|
||||
* @extends Phaser.GameObjects.Components.Transform
|
||||
* @extends Phaser.GameObjects.Components.Visible
|
||||
* @extends Phaser.GameObjects.Components.ScrollFactor
|
||||
* @extends Phaser.GameObjects.Components.Size
|
||||
*
|
||||
* @param {Phaser.Scene} scene - The Scene to which this Game Object belongs. A Game Object can only belong to one Scene at a time.
|
||||
* @param {number} [x] - The horizontal position of this Game Object in the world.
|
||||
* @param {number} [y] - The vertical position of this Game Object in the world.
|
||||
*/
|
||||
var Layer3D = new Class({
|
||||
|
||||
Extends: GameObject,
|
||||
|
||||
Mixins: [
|
||||
Components.AlphaSingle,
|
||||
Components.BlendMode,
|
||||
Components.Depth,
|
||||
Components.Mask,
|
||||
Components.Pipeline,
|
||||
Components.Transform,
|
||||
Components.Visible,
|
||||
Components.ScrollFactor,
|
||||
Components.Size,
|
||||
Layer3DRender
|
||||
],
|
||||
|
||||
initialize:
|
||||
|
||||
function Layer3D (scene, x, y)
|
||||
{
|
||||
GameObject.call(this, scene, 'Layer3D');
|
||||
|
||||
/**
|
||||
* A Camera which can be used to control the view of the models being managed
|
||||
* by this Layer3D. It will default to have an fov of 45 and be positioned at 0, 0, -10,
|
||||
* with a near of 0.01 and far of 1000. You can change all of these by using the
|
||||
* methods and properties available on the `Layer3DCamera` class.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3D#camera
|
||||
* @type {Phaser.GameObjects.Layer3DCamera}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.camera = new Layer3DCamera(this, 45, 0, 0, -10, 0.01, 1000);
|
||||
|
||||
/**
|
||||
* An ambient light source for the entire Layer3D scene and all models it is rendering.
|
||||
*
|
||||
* It is created at a position of 0, -100, 0 with full ambient, diffuse and specular
|
||||
* values. You can change all of these by using the methods and properties
|
||||
* available on the `Layer3DLight` class.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3D#light
|
||||
* @type {Phaser.GameObjects.Layer3DLight}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.light = new Layer3DLight(this, 0, 100, 0);
|
||||
|
||||
/**
|
||||
* The color of the fog.
|
||||
*
|
||||
* By default it is 0,0,0, which is black.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3D#fogColor
|
||||
* @type {Phaser.Display.RGB}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.fogColor = new RGB();
|
||||
|
||||
/**
|
||||
* The minimum distance from which fog starts to affect objects closer than it.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3D#fogNear
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.fogNear = 0;
|
||||
|
||||
/**
|
||||
* The maximum distance from which fog starts to affect objects further than it.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3D#fogFar
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.fogFar = Infinity;
|
||||
|
||||
/**
|
||||
* An array of model instances that have been created in this Layer3D.
|
||||
*
|
||||
* This array can be sorted, by your own functions, to control model rendering order.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3D#models
|
||||
* @type {Phaser.Geom.Mesh.Model[]}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.models = [];
|
||||
|
||||
/**
|
||||
* Internal cached value.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3D#_prevWidth
|
||||
* @type {number}
|
||||
* @private
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this._prevWidth = 0;
|
||||
|
||||
/**
|
||||
* Internal cached value.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3D#_prevHeight
|
||||
* @type {number}
|
||||
* @private
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this._prevHeight = 0;
|
||||
|
||||
var renderer = scene.sys.renderer;
|
||||
|
||||
this.setPosition(x, y);
|
||||
this.setSize(renderer.width, renderer.height);
|
||||
this.initPipeline(CONST.MESH_PIPELINE);
|
||||
|
||||
this.on(GameObjectEvents.ADDED_TO_SCENE, this.addedToScene, this);
|
||||
this.on(GameObjectEvents.REMOVED_FROM_SCENE, this.removedFromScene, this);
|
||||
},
|
||||
|
||||
// Overrides Game Object method
|
||||
addedToScene: function ()
|
||||
{
|
||||
this.scene.sys.updateList.add(this);
|
||||
},
|
||||
|
||||
// Overrides Game Object method
|
||||
removedFromScene: function ()
|
||||
{
|
||||
this.scene.sys.updateList.remove(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes all models from this Layer3D, calling `destroy` on each one of them.
|
||||
*
|
||||
* @method Phaser.GameObjects.Layer3D#clearModels
|
||||
* @since 3.50.0
|
||||
*/
|
||||
clearModels: function ()
|
||||
{
|
||||
var models = this.models;
|
||||
|
||||
for (var i = 0; i < models.length; i++)
|
||||
{
|
||||
models[i].destroy();
|
||||
}
|
||||
|
||||
this.models = [];
|
||||
},
|
||||
|
||||
/**
|
||||
* This method creates a new blank Model instance and adds it to this Layer3D.
|
||||
*
|
||||
* You still need to tell it how many vertices it's going to contain in total, but you can
|
||||
* populate the vertex data at a later stage after calling this. It won't try to render
|
||||
* while it has no vertices.
|
||||
*
|
||||
* @method Phaser.GameObjects.Layer3D#addModel
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {number} verticesCount - The total number of vertices this model can contain.
|
||||
* @param {string|Phaser.Textures.Texture} [texture] - The key, or instance of the Texture this model will use to render with, as stored in the Texture Manager.
|
||||
* @param {string|integer} [frame] - An optional frame from the Texture this model is rendering with. Ensure your UV data also matches this frame.
|
||||
* @param {number} [x=0] - The x position of the Model.
|
||||
* @param {number} [y=0] - The y position of the Model.
|
||||
* @param {number} [z=0] - The z position of the Model.
|
||||
*
|
||||
* @return {Phaser.Geom.Mesh.Model} The model instance that was created.
|
||||
*/
|
||||
addModel: function (verticesCount, texture, frame, x, y, z)
|
||||
{
|
||||
var model = new Model(this, verticesCount, texture, frame, x, y, z);
|
||||
|
||||
this.models.push(model);
|
||||
|
||||
return model;
|
||||
},
|
||||
|
||||
/**
|
||||
* This method creates a new Model based on a loaded triangulated Wavefront OBJ.
|
||||
*
|
||||
* The obj file should have been loaded via OBJFile:
|
||||
*
|
||||
* ```javascript
|
||||
* this.load.obj(key, url, [ flipUV ]);
|
||||
* ```
|
||||
*
|
||||
* Then use the key it was loaded under in this method.
|
||||
*
|
||||
* If the model has a texture, you must provide it as the second parameter.
|
||||
*
|
||||
* The model is then added to this Layer3D. A single Layer3D can contain multiple models
|
||||
* without impacting each other. Equally, multiple models can all share the same base OBJ
|
||||
* data.
|
||||
*
|
||||
* Make sure your 3D package has triangulated the model data prior to exporting it.
|
||||
*
|
||||
* You can scale the model data during import, which will set the new 'base' scale for the model.
|
||||
*
|
||||
* You can also offset the models generated vertex positions via the `originX`, `originY` and `originZ`
|
||||
* parameters, which will change the rotation origin of the model. The model itself can be positioned,
|
||||
* rotated and scaled independantly of these settings, so don't use them to position the model, just
|
||||
* use them to offset the base values.
|
||||
*
|
||||
* @method Phaser.GameObjects.Layer3D#addModelFromOBJ
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {string} key - The key of the data in the OBJ Cache to create the model from.
|
||||
* @param {string|Phaser.Textures.Texture} [texture] - The key, or instance of the Texture this model will use to render with, as stored in the Texture Manager.
|
||||
* @param {string|integer} [frame] - An optional frame from the Texture this model is rendering with. Ensure your UV data also matches this frame.
|
||||
* @param {number} [scale=1] - An amount to scale the model data by during creation.
|
||||
* @param {number} [originX=0] - The x origin of the model vertices during creation.
|
||||
* @param {number} [originY=0] - The y origin of the model vertices during creation.
|
||||
* @param {number} [originZ=0] - The z origin of the model vertices during creation.
|
||||
*
|
||||
* @return {Phaser.Geom.Mesh.Model|Phaser.Geom.Mesh.Model[]} The Model instance that was created. If the OBJ contained multiple models then an array of Model instances is returned.
|
||||
*/
|
||||
addModelFromOBJ: function (key, texture, frame, scale, originX, originY, originZ)
|
||||
{
|
||||
var model = [];
|
||||
var data = this.scene.sys.cache.obj.get(key);
|
||||
|
||||
if (data)
|
||||
{
|
||||
model = this.addModelFromData(data, texture, frame, scale, originX, originY, originZ);
|
||||
}
|
||||
|
||||
return (model.length === 1) ? model[0] : model;
|
||||
},
|
||||
|
||||
/**
|
||||
* This method creates a new Model based on the parsed triangulated model data.
|
||||
*
|
||||
* The data should have been parsed in advance via a function such as `ParseObj`:
|
||||
*
|
||||
* ```javascript
|
||||
* const data = Phaser.Geom.Mesh.ParseObj(rawData, flipUV);
|
||||
*
|
||||
* Layer3D.addModelFromData(data, texture, frame);
|
||||
* ```
|
||||
*
|
||||
* If the model has a texture, you must provide it as the second parameter.
|
||||
*
|
||||
* The model is then added to this Layer3D. A single Layer3D can contain multiple models
|
||||
* without impacting each other. Equally, multiple models can all share the same base OBJ
|
||||
* data.
|
||||
*
|
||||
* Make sure your 3D package has triangulated the model data prior to exporting it.
|
||||
*
|
||||
* You can scale the model data during import, which will set the new 'base' scale for the model.
|
||||
*
|
||||
* You can also offset the models generated vertex positions via the `originX`, `originY` and `originZ`
|
||||
* parameters, which will change the rotation origin of the model. The model itself can be positioned,
|
||||
* rotated and scaled independantly of these settings, so don't use them to position the model, just
|
||||
* use them to offset the base values.
|
||||
*
|
||||
* @method Phaser.GameObjects.Layer3D#addModelFromData
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {array} data - The parsed model data.
|
||||
* @param {string|Phaser.Textures.Texture} [texture] - The key, or instance of the Texture this model will use to render with, as stored in the Texture Manager.
|
||||
* @param {string|integer} [frame] - An optional frame from the Texture this model is rendering with. Ensure your UV data also matches this frame.
|
||||
* @param {number} [scale=1] - An amount to scale the model data by during creation.
|
||||
* @param {number} [originX=0] - The x origin of the model vertices during creation.
|
||||
* @param {number} [originY=0] - The y origin of the model vertices during creation.
|
||||
* @param {number} [originZ=0] - The z origin of the model vertices during creation.
|
||||
*
|
||||
* @return {Phaser.Geom.Mesh.Model|Phaser.Geom.Mesh.Model[]} The Model instance that was created. If the data contained multiple models then an array of Model instances is returned.
|
||||
*/
|
||||
addModelFromData: function (data, texture, frame, scale, originX, originY, originZ)
|
||||
{
|
||||
if (scale === undefined) { scale = 1; }
|
||||
if (originX === undefined) { originX = 0; }
|
||||
if (originY === undefined) { originY = 0; }
|
||||
if (originZ === undefined) { originZ = 0; }
|
||||
|
||||
var results = [];
|
||||
|
||||
for (var m = 0; m < data.models.length; m++)
|
||||
{
|
||||
var modelData = data.models[m];
|
||||
|
||||
var vertices = modelData.vertices;
|
||||
var textureCoords = modelData.textureCoords;
|
||||
var normals = modelData.vertexNormals;
|
||||
var faces = modelData.faces;
|
||||
|
||||
var model = this.addModel(faces.length * 3, texture, frame);
|
||||
|
||||
var defaultUV1 = { u: 0, v: 1 };
|
||||
var defaultUV2 = { u: 0, v: 0 };
|
||||
var defaultUV3 = { u: 1, v: 1 };
|
||||
|
||||
for (var i = 0; i < faces.length; i++)
|
||||
{
|
||||
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;
|
||||
|
||||
var uv1 = (t1 === -1) ? defaultUV1 : textureCoords[t1];
|
||||
var uv2 = (t2 === -1) ? defaultUV2 : textureCoords[t2];
|
||||
var uv3 = (t3 === -1) ? defaultUV3 : textureCoords[t3];
|
||||
|
||||
model.addVertex(originX + m1.x * scale, originY + m1.y * scale, originZ + m1.z * scale, uv1.u, uv1.v, n1.x, n1.y, n1.z);
|
||||
model.addVertex(originX + m2.x * scale, originY + m2.y * scale, originZ + m2.z * scale, uv2.u, uv2.v, n2.x, n2.y, n2.z);
|
||||
model.addVertex(originX + m3.x * scale, originY + m3.y * scale, originZ + m3.z * scale, uv3.u, uv3.v, n3.x, n3.y, n3.z);
|
||||
}
|
||||
|
||||
results.push(model);
|
||||
}
|
||||
|
||||
return results;
|
||||
},
|
||||
|
||||
/**
|
||||
* This method creates a new Model based on the given triangulated vertices arrays.
|
||||
*
|
||||
* Adds vertices to this model by parsing the given arrays.
|
||||
*
|
||||
* This method will take vertex data in one of two formats, based on the `containsZ` parameter.
|
||||
*
|
||||
* If your vertex data are `x`, `y` pairs, then `containsZ` should be `false` (this is the default)
|
||||
*
|
||||
* If your vertex data is groups of `x`, `y` and `z` values, then the `containsZ` parameter must be true.
|
||||
*
|
||||
* The `uvs` parameter is a numeric array consisting of `u` and `v` pairs.
|
||||
* The `normals` parameter is a numeric array consisting of `x`, `y` vertex normal values and, if `containsZ` is true, `z` values as well.
|
||||
* The `indicies` parameter is an optional array that, if given, is an indexed list of vertices to be added.
|
||||
*
|
||||
* The following example will create a 256 x 256 sized quad using an index array:
|
||||
*
|
||||
* ```javascript
|
||||
* const vertices = [
|
||||
* -128, 128,
|
||||
* 128, 128,
|
||||
* -128, -128,
|
||||
* 128, -128
|
||||
* ];
|
||||
*
|
||||
* const uvs = [
|
||||
* 0, 1,
|
||||
* 1, 1,
|
||||
* 0, 0,
|
||||
* 1, 0
|
||||
* ];
|
||||
*
|
||||
* const indices = [ 0, 2, 1, 2, 3, 1 ];
|
||||
*
|
||||
* Layer3D.addModelFromVertices(vertices, uvs, indicies);
|
||||
* ```
|
||||
*
|
||||
* You cannot add more vertices to a model than the total specified when the model was created.
|
||||
* If you need to clear all vertices first, call `Model.resetVertices`.
|
||||
*
|
||||
* @method Phaser.GameObjects.Layer3D#addModelFromVertices
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {number[]} vertices - The vertices array. Either `xy` pairs, or `xyz` if the `containsZ` parameter is `true`.
|
||||
* @param {number[]} uvs - The UVs pairs array.
|
||||
* @param {number[]} [normals] - Optional vertex normals array. If you don't have one, pass `null` or an empty array.
|
||||
* @param {number[]} [indicies] - Optional vertex indicies array. If you don't have one, pass `null` or an empty array.
|
||||
* @param {boolean} [containsZ=false] - Does the vertices data include a `z` component?
|
||||
* @param {string|Phaser.Textures.Texture} [texture] - The key, or instance of the Texture the model will use to render with, as stored in the Texture Manager.
|
||||
* @param {string|integer} [frame] - An optional frame from the Texture the model is rendering with.
|
||||
*
|
||||
* @return {Phaser.Geom.Mesh.Model} The Model instance that was created.
|
||||
*/
|
||||
addModelFromVertices: function (vertices, uvs, normals, indicies, containsZ, texture, frame)
|
||||
{
|
||||
var isIndexed = (Array.isArray(indicies) && indicies.length > 0);
|
||||
|
||||
var verticesCount = (isIndexed) ? indicies.length : vertices.length;
|
||||
|
||||
if (!isIndexed)
|
||||
{
|
||||
verticesCount /= 2;
|
||||
}
|
||||
|
||||
var model = this.addModel(verticesCount, texture, frame, 0, 0, 0);
|
||||
|
||||
model.addVertices(vertices, uvs, normals, indicies, containsZ);
|
||||
|
||||
return model;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the fog values for this Layer3D, including the fog color and the near and
|
||||
* far distance values.
|
||||
*
|
||||
* By default, fog effects all models in this layer.
|
||||
*
|
||||
* If you do not wish to have a fog effect, see the `disableFog` method.
|
||||
*
|
||||
* @method Phaser.GameObjects.Layer3D#setFog
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {number} red - The red color component of the fog. A value between 0 and 1.
|
||||
* @param {number} green - The green color component of the fog. A value between 0 and 1.
|
||||
* @param {number} blue - The blue color component of the fog. A value between 0 and 1.
|
||||
* @param {number} [near] - The 'near' value of the fog.
|
||||
* @param {number} [far] - The 'far' value of the fog, beyond which objects are 'fogged' out.
|
||||
*
|
||||
* @return {this} This Layer3D Game Object.
|
||||
*/
|
||||
setFog: function (red, green, blue, near, far)
|
||||
{
|
||||
if (near === undefined) { near = this.fogNear; }
|
||||
if (far === undefined) { far = this.fogFar; }
|
||||
|
||||
this.fogColor.set(red, green, blue);
|
||||
|
||||
this.fogNear = near;
|
||||
this.fogFar = far;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Disables fog for this Layer3D and all models it renders.
|
||||
*
|
||||
* To re-enable fog, just call `setFog` and provide new color, near and far values.
|
||||
*
|
||||
* @method Phaser.GameObjects.Layer3D#disableFog
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @return {this} This Layer3D Game Object.
|
||||
*/
|
||||
disableFog: function ()
|
||||
{
|
||||
this.fogFar = Infinity;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* The Layer3D update loop.
|
||||
*
|
||||
* @method Phaser.GameObjects.Layer3D#preUpdate
|
||||
* @protected
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {number} time - The current timestamp.
|
||||
* @param {number} delta - The delta time, in ms, elapsed since the last frame.
|
||||
*/
|
||||
preUpdate: function (time, delta)
|
||||
{
|
||||
var width = this.width;
|
||||
var height = this.height;
|
||||
|
||||
var camera = this.camera;
|
||||
|
||||
if (camera.dirtyProjection || width !== this._prevWidth || height !== this._prevHeight)
|
||||
{
|
||||
camera.updateProjectionMatrix(width, height);
|
||||
|
||||
this._prevWidth = width;
|
||||
this._prevHeight = height;
|
||||
}
|
||||
|
||||
var models = this.models;
|
||||
|
||||
for (var i = 0; i < models.length; i++)
|
||||
{
|
||||
var model = models[i];
|
||||
|
||||
if (model.visible)
|
||||
{
|
||||
model.preUpdate(time, delta);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Resets all of the dirty cache values this Layer3D object uses.
|
||||
*
|
||||
* This is called automatically at the end of the render step.
|
||||
*
|
||||
* @method Phaser.GameObjects.Layer3D#resetDirtyFlags
|
||||
* @protected
|
||||
* @since 3.50.0
|
||||
*/
|
||||
resetDirtyFlags: function ()
|
||||
{
|
||||
this.camera.dirtyView = false;
|
||||
this.camera.dirtyProjection = false;
|
||||
|
||||
this.light.ambient.dirty = false;
|
||||
this.light.diffuse.dirty = false;
|
||||
this.light.specular.dirty = false;
|
||||
|
||||
this.fogColor.dirty = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* The destroy step for this Layer3D, which removes all models, destroys the camera and
|
||||
* nulls external references.
|
||||
*
|
||||
* @method Phaser.GameObjects.Layer3D#preDestroy
|
||||
* @private
|
||||
* @since 3.50.0
|
||||
*/
|
||||
preDestroy: function ()
|
||||
{
|
||||
this.clearModels();
|
||||
|
||||
this.camera.destroy();
|
||||
this.light.destroy();
|
||||
|
||||
this.camera = null;
|
||||
this.light = null;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
module.exports = Layer3D;
|
716
src/gameobjects/layer3d/Layer3DCamera.js
Normal file
716
src/gameobjects/layer3d/Layer3DCamera.js
Normal file
|
@ -0,0 +1,716 @@
|
|||
/**
|
||||
* @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 DegToRad = require('../../math/DegToRad');
|
||||
var GetFastValue = require('../../utils/object/GetFastValue');
|
||||
var INPUT_EVENTS = require('../../input/events');
|
||||
var Matrix4 = require('../../math/Matrix4');
|
||||
var Vector3 = require('../../math/Vector3');
|
||||
var Vector4 = require('../../math/Vector4');
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* The Layer3D Camera.
|
||||
*
|
||||
* @class Layer3DCamera
|
||||
* @memberof Phaser.GameObjects
|
||||
* @constructor
|
||||
* @since 3.50.0
|
||||
*/
|
||||
var Layer3DCamera = new Class({
|
||||
|
||||
initialize:
|
||||
|
||||
function Layer3DCamera (layer, fov, x, y, z, near, far)
|
||||
{
|
||||
/**
|
||||
* The Layer3D instance this camera belongs to.
|
||||
*
|
||||
* A camera can only belong to a single Layer3D instance.
|
||||
*
|
||||
* You should consider this property as being read-only. You cannot move a
|
||||
* camera to another Layer3D by simply changing it.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#layer
|
||||
* @type {Phaser.GameObjects.Layer3D}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.layer = layer;
|
||||
|
||||
/**
|
||||
* The Scene Input Plugin, as referenced via the Layer3D parent.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#input
|
||||
* @type {Phaser.Input.InputPlugin}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.input = layer.scene.sys.input;
|
||||
|
||||
/**
|
||||
* Internal 'dirty' flag that tells the parent Layer3D if the
|
||||
* view matrix of this camera needs recalculating at the next step.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#dirtyView
|
||||
* @type {boolean}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.dirtyView = true;
|
||||
|
||||
/**
|
||||
* Internal 'dirty' flag that tells the parent Layer3D if the
|
||||
* projection matrix of this camera needs recalculating at the next step.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#dirtyProjection
|
||||
* @type {boolean}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.dirtyProjection = true;
|
||||
|
||||
/**
|
||||
* Internal fov value.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#_fov
|
||||
* @type {number}
|
||||
* @private
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this._fov = fov;
|
||||
|
||||
/**
|
||||
* Internal near value.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#_near
|
||||
* @type {number}
|
||||
* @private
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this._near = near;
|
||||
|
||||
/**
|
||||
* Internal far value.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#_far
|
||||
* @type {number}
|
||||
* @private
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this._far = far;
|
||||
|
||||
/**
|
||||
* The aspect ratio of the camera.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#aspectRatio
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.aspectRatio = 1;
|
||||
|
||||
/**
|
||||
* The position of the camera in 3D space.
|
||||
*
|
||||
* You can modify this vector directly, or use the `x`, `y` and `z`
|
||||
* properties of this class.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#position
|
||||
* @type {Phaser.Math.Vector3}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.position = new Vector3(x, y, z);
|
||||
|
||||
/**
|
||||
* The rotation of the camera in 3D space.
|
||||
*
|
||||
* You can modify this vector directly, or use the `rotationX`, `rotationY`
|
||||
* and `rotationZ` properties of this class.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#rotation
|
||||
* @type {Phaser.Math.Vector3}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.rotation = new Vector3();
|
||||
|
||||
/**
|
||||
* The forward facing vector of the camera.
|
||||
*
|
||||
* Calculated and updated automatically when the view matrix changes.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#forward
|
||||
* @type {Phaser.Math.Vector4}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.forward = new Vector4();
|
||||
|
||||
/**
|
||||
* The upward facing vector of the camera.
|
||||
* Invert it to get the bottom vector.
|
||||
*
|
||||
* Calculated and updated automatically when the view matrix changes.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#up
|
||||
* @type {Phaser.Math.Vector4}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.up = new Vector4();
|
||||
|
||||
/**
|
||||
* The right facing vector of the camera.
|
||||
* Invert it to get the left vector.
|
||||
*
|
||||
* Calculated and updated automatically when the view matrix changes.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#right
|
||||
* @type {Phaser.Math.Vector4}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.right = new Vector4();
|
||||
|
||||
/**
|
||||
* Internal transform matrix.
|
||||
*
|
||||
* Calculated and updated automatically when the camera is dirty.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#matrix
|
||||
* @type {Phaser.Math.Matrix4}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.matrix = new Matrix4();
|
||||
|
||||
/**
|
||||
* The inverse of the transform matrix.
|
||||
*
|
||||
* Calculated and updated automatically when the camera is dirty.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#viewMatrix
|
||||
* @type {Phaser.Math.Matrix4}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.viewMatrix = new Matrix4();
|
||||
|
||||
/**
|
||||
* The perspective projection matrix.
|
||||
*
|
||||
* Calculated and updated automatically when the camera is dirty.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#projectionMatrix
|
||||
* @type {Phaser.Math.Matrix4}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.projectionMatrix = new Matrix4();
|
||||
|
||||
/**
|
||||
* The perspective projection matrix, multiplied by the view matrix.
|
||||
*
|
||||
* Calculated and updated automatically when the camera is dirty.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#viewProjectionMatrix
|
||||
* @type {Phaser.Math.Matrix4}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.viewProjectionMatrix = new Matrix4();
|
||||
|
||||
/**
|
||||
* The movement and rotation mode of this camera.
|
||||
* Either ORBIT, or FREE.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#mode
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.mode = Layer3DCamera.MODE_ORBIT;
|
||||
|
||||
/**
|
||||
* How fast to rotate the camera, in degrees per delta.
|
||||
*
|
||||
* This value is only used after calling the `enableControls` method,
|
||||
* it does not influence changing the rotation values directly.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#rotateSpeed
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.rotateSpeed = 0.5;
|
||||
|
||||
/**
|
||||
* How fast to pan the camera, in units per delta.
|
||||
*
|
||||
* This value is only used after calling the `enableControls` method,
|
||||
* it does not influence calling the pan methods directly.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#panSpeed
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.panSpeed = 4;
|
||||
|
||||
/**
|
||||
* How fast to zoom the camera.
|
||||
*
|
||||
* This value is only used after calling the `enableControls` method,
|
||||
* it does not influence calling the panZ method directly.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#zoomSpeed
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.zoomSpeed = 3;
|
||||
|
||||
this.allowPan = false;
|
||||
|
||||
this.lockXAxis = false;
|
||||
this.lockYAxis = false;
|
||||
},
|
||||
|
||||
enableOrbitControls: function (config)
|
||||
{
|
||||
this.rotateSpeed = GetFastValue(config, 'rotateSpeed', this.rotateSpeed);
|
||||
this.panSpeed = GetFastValue(config, 'panSpeed', this.panSpeed);
|
||||
this.allowPan = GetFastValue(config, 'allowPan', this.allowPan);
|
||||
this.lockXAxis = GetFastValue(config, 'lockXAxis', this.lockXAxis);
|
||||
this.lockYAxis = GetFastValue(config, 'lockYAxis', this.lockYAxis);
|
||||
|
||||
this.input.on(INPUT_EVENTS.POINTER_MOVE, this.pointerMoveHandler, this);
|
||||
},
|
||||
|
||||
disableOrbitControls: function ()
|
||||
{
|
||||
this.input.off(INPUT_EVENTS.POINTER_MOVE, this.pointerMoveHandler, this);
|
||||
},
|
||||
|
||||
enableZoom: function (zoomSpeed)
|
||||
{
|
||||
if (zoomSpeed === undefined) { zoomSpeed = 3; }
|
||||
|
||||
this.zoomSpeed = zoomSpeed;
|
||||
|
||||
this.input.on(INPUT_EVENTS.POINTER_WHEEL, this.pointerWheelHandler, this);
|
||||
},
|
||||
|
||||
disableZoom: function ()
|
||||
{
|
||||
this.input.off(INPUT_EVENTS.POINTER_WHEEL, this.pointerWheelHandler, this);
|
||||
},
|
||||
|
||||
pointerMoveHandler: function (pointer)
|
||||
{
|
||||
if (pointer.isDown)
|
||||
{
|
||||
var width = this.layer.width;
|
||||
var height = this.layer.height;
|
||||
|
||||
if (pointer.event.shiftKey && this.allowPan)
|
||||
{
|
||||
this.panX(pointer.velocity.x * (this.panSpeed / width));
|
||||
this.panY(pointer.velocity.y * (this.panSpeed / height));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!this.lockXAxis)
|
||||
{
|
||||
this.rotationX -= pointer.velocity.y * (this.rotateSpeed / height);
|
||||
}
|
||||
|
||||
if (!this.lockYAxis)
|
||||
{
|
||||
this.rotationY -= pointer.velocity.x * (this.rotateSpeed / width);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
pointerWheelHandler: function (pointer, over, deltaX, deltaY)
|
||||
{
|
||||
this.panZ(deltaY * (this.zoomSpeed / this.layer.height));
|
||||
},
|
||||
|
||||
/**
|
||||
* Pans this camera on the x axis by the given amount.
|
||||
*
|
||||
* @method Phaser.GameObjects.Layer3DCamera#panX
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {number} v - The amount to pan by.
|
||||
*/
|
||||
panX: function (v)
|
||||
{
|
||||
this.updateViewMatrix();
|
||||
|
||||
this.position.addScale(this.right, v);
|
||||
},
|
||||
|
||||
/**
|
||||
* Pans this camera on the y axis by the given amount.
|
||||
*
|
||||
* @method Phaser.GameObjects.Layer3DCamera#panY
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {number} v - The amount to pan by.
|
||||
*/
|
||||
panY: function (v)
|
||||
{
|
||||
this.updateViewMatrix();
|
||||
|
||||
this.y += this.up.y * v;
|
||||
|
||||
if (this.mode === Layer3DCamera.MODE_ORBIT)
|
||||
{
|
||||
// Can only move up and down the y axis in orbit mode
|
||||
return;
|
||||
}
|
||||
|
||||
this.x += this.up.x * v;
|
||||
this.z += this.up.z * v;
|
||||
},
|
||||
|
||||
/**
|
||||
* Pans this camera on the z axis by the given amount.
|
||||
*
|
||||
* @method Phaser.GameObjects.Layer3DCamera#panZ
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {number} v - The amount to pan by.
|
||||
*/
|
||||
panZ: function (v)
|
||||
{
|
||||
this.updateViewMatrix();
|
||||
|
||||
if (this.mode === Layer3DCamera.MODE_ORBIT)
|
||||
{
|
||||
// Orbit mode translates after rotatation, so only need to set Z. The rotation will handle the rest.
|
||||
this.z += v;
|
||||
}
|
||||
else
|
||||
{
|
||||
// In freemode to move forward, we move based on our forward, which is relative to our current rotation.
|
||||
this.position.addScale(this.forward, v);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Internal method that is called by the Layer3D instance that owns this camera
|
||||
* during its `render` step. If the view matrix is dirty, it is recalculated
|
||||
* and then applied to the view projection matrix, ready for rendering.
|
||||
*
|
||||
* @method Phaser.GameObjects.Layer3DCamera#update
|
||||
* @since 3.50.0
|
||||
*/
|
||||
update: function ()
|
||||
{
|
||||
if (this.dirtyView)
|
||||
{
|
||||
this.updateViewMatrix();
|
||||
}
|
||||
|
||||
if (this.dirtyView || this.dirtyProjection)
|
||||
{
|
||||
this.projectionMatrix.multiplyToMat4(this.viewMatrix, this.viewProjectionMatrix);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Internal method that handles the update of the view transform matrix, based on the rotation
|
||||
* and position of the camera. Called automatically when the camera is updated.
|
||||
*
|
||||
* @method Phaser.GameObjects.Layer3DCamera#updateViewMatrix
|
||||
* @since 3.50.0
|
||||
*/
|
||||
updateViewMatrix: function ()
|
||||
{
|
||||
var matView = this.matrix;
|
||||
|
||||
if (this.mode === Layer3DCamera.MODE_FREE)
|
||||
{
|
||||
matView.fromRotationXYTranslation(this.rotation, this.position, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
matView.fromRotationXYTranslation(this.rotation, this.position, false);
|
||||
}
|
||||
|
||||
this.updateDirection();
|
||||
|
||||
this.viewMatrix.copy(matView).invert();
|
||||
},
|
||||
|
||||
/**
|
||||
* Internal method that is called by the Layer3D instance that owns this camera
|
||||
* during its `preUpdate` step. If the projection matrix is dirty, or the renderer
|
||||
* width or height has changed, then a new projection matrix is calculated.
|
||||
*
|
||||
* @method Phaser.GameObjects.Layer3DCamera#updateProjectionMatrix
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {number} width - The width of the renderer.
|
||||
* @param {number} height - The height of the renderer.
|
||||
*/
|
||||
updateProjectionMatrix: function (width, height)
|
||||
{
|
||||
this.aspectRatio = width / height;
|
||||
|
||||
this.projectionMatrix.perspective(DegToRad(this._fov), this.aspectRatio, this._near, this._far);
|
||||
},
|
||||
|
||||
/**
|
||||
* Internal method that sets the forward, up and right vectors from
|
||||
* the view matrix. This is called automatically as part of the
|
||||
* `updateViewMatrix` method.
|
||||
*
|
||||
* @method Phaser.GameObjects.Layer3DCamera#updateDirection
|
||||
* @since 3.50.0
|
||||
*/
|
||||
updateDirection: function ()
|
||||
{
|
||||
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);
|
||||
},
|
||||
|
||||
/**
|
||||
* The field of view, in degrees, of this camera.
|
||||
*
|
||||
* Limited to the range of 0 to 180.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#fov
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
fov: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this._fov;
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
if (value > 0 && value < 180)
|
||||
{
|
||||
this._fov = value;
|
||||
this.dirtyProjection = true;
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* The minimum distance the camera can see from.
|
||||
*
|
||||
* It's important to consider that depth buffers are not infinite and the closer
|
||||
* a camera starts, the more you may encounter depth fighting issues.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#near
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
near: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this._near;
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
if (value > 0)
|
||||
{
|
||||
this._near = value;
|
||||
this.dirtyProjection = true;
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* The maximum distance the camera can see to.
|
||||
*
|
||||
* It's important to consider that depth buffers are not infinite and the further
|
||||
* a camera ends, the more you may encounter depth fighting issues.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#far
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
far: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this._far;
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
if (value > 0)
|
||||
{
|
||||
this._far = value;
|
||||
this.dirtyProjection = true;
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* The x position of the camera.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#x
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
x: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this.position.x;
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
this.position.x = value;
|
||||
this.dirtyView = true;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* The y position of the camera.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#y
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
y: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this.position.y;
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
this.position.y = value;
|
||||
this.dirtyView = true;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* The z position of the camera.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#z
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
z: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this.position.z;
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
this.position.z = value;
|
||||
this.dirtyView = true;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* The x axis rotation, in radians, of the camera.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#rotationX
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
rotationX: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this.rotation.x;
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
this.rotation.x = value;
|
||||
this.dirtyView = true;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* The y axis rotation, in radians, of the camera.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#rotationY
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
rotationY: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this.rotation.y;
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
this.rotation.y = value;
|
||||
this.dirtyView = true;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* The z axis rotation, in radians, of the camera.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DCamera#rotationZ
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
rotationZ: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this.rotation.z;
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
this.rotation.z = value;
|
||||
this.dirtyView = true;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Destroy handler for this camera.
|
||||
*
|
||||
* @method Phaser.GameObjects.Layer3DCamera#destroy
|
||||
* @since 3.50.0
|
||||
*/
|
||||
destroy: function ()
|
||||
{
|
||||
this.layer = null;
|
||||
this.position = null;
|
||||
this.rotation = null;
|
||||
this.forward = null;
|
||||
this.up = null;
|
||||
this.right = null;
|
||||
this.matrix = null;
|
||||
this.viewMatrix = null;
|
||||
this.projectionMatrix = null;
|
||||
this.viewProjectionMatrix = null;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Allows free movement of position and rotation
|
||||
Layer3DCamera.MODE_FREE = 0;
|
||||
|
||||
// Movement is locked to rotate around the origin
|
||||
Layer3DCamera.MODE_ORBIT = 1;
|
||||
|
||||
module.exports = Layer3DCamera;
|
22
src/gameobjects/layer3d/Layer3DCanvasRenderer.js
Normal file
22
src/gameobjects/layer3d/Layer3DCanvasRenderer.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
* @author Richard Davey <rich@photonstorm.com>
|
||||
* @copyright 2020 Photon Storm Ltd.
|
||||
* @license {@link https://opensource.org/licenses/MIT|MIT License}
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is a stub function for Layer3D.Render. There is no Canvas renderer for Layer3D objects.
|
||||
*
|
||||
* @method Phaser.GameObjects.Layer3D#renderCanvas
|
||||
* @since 3.50.0
|
||||
* @private
|
||||
*
|
||||
* @param {Phaser.Renderer.Canvas.CanvasRenderer} renderer - A reference to the current active Canvas renderer.
|
||||
* @param {Phaser.GameObjects.Layer3D} src - The Game Object being rendered in this call.
|
||||
* @param {Phaser.Cameras.Scene2D.Camera} camera - The Camera that is rendering the Game Object.
|
||||
*/
|
||||
var Layer3DCanvasRenderer = function ()
|
||||
{
|
||||
};
|
||||
|
||||
module.exports = Layer3DCanvasRenderer;
|
40
src/gameobjects/layer3d/Layer3DCreator.js
Normal file
40
src/gameobjects/layer3d/Layer3DCreator.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* @author Richard Davey <rich@photonstorm.com>
|
||||
* @copyright 2020 Photon Storm Ltd.
|
||||
* @license {@link https://opensource.org/licenses/MIT|MIT License}
|
||||
*/
|
||||
|
||||
var BuildGameObject = require('../BuildGameObject');
|
||||
var GameObjectCreator = require('../GameObjectCreator');
|
||||
var Layer3D = require('./Layer3D');
|
||||
|
||||
/**
|
||||
* Creates a new Layer3D Game Object and returns it.
|
||||
*
|
||||
* Note: This method will only be available if the Layer3D Game Object and WebGL support have been built into Phaser.
|
||||
*
|
||||
* @method Phaser.GameObjects.GameObjectCreator#layer3d
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {object} config - The configuration object this Game Object will use to create itself.
|
||||
* @param {boolean} [addToScene] - Add this Game Object to the Scene after creating it? If set this argument overrides the `add` property in the config object.
|
||||
*
|
||||
* @return {Phaser.GameObjects.Layer3D} The Game Object that was created.
|
||||
*/
|
||||
GameObjectCreator.register('layer3d', function (config, addToScene)
|
||||
{
|
||||
if (config === undefined) { config = {}; }
|
||||
|
||||
var layer = new Layer3D(this.scene, 0, 0);
|
||||
|
||||
if (addToScene !== undefined)
|
||||
{
|
||||
config.add = addToScene;
|
||||
}
|
||||
|
||||
BuildGameObject(this.scene, layer, config);
|
||||
|
||||
return layer;
|
||||
});
|
||||
|
||||
// When registering a factory function 'this' refers to the GameObjectCreator context.
|
38
src/gameobjects/layer3d/Layer3DFactory.js
Normal file
38
src/gameobjects/layer3d/Layer3DFactory.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* @author Richard Davey <rich@photonstorm.com>
|
||||
* @copyright 2020 Photon Storm Ltd.
|
||||
* @license {@link https://opensource.org/licenses/MIT|MIT License}
|
||||
*/
|
||||
|
||||
var Layer3D = require('./Layer3D');
|
||||
var GameObjectFactory = require('../GameObjectFactory');
|
||||
|
||||
/**
|
||||
* Creates a new Layer3D Game Object and adds it to the Scene.
|
||||
*
|
||||
* Note: This method will only be available if the Layer3D Game Object and WebGL support have been built into Phaser.
|
||||
*
|
||||
* @method Phaser.GameObjects.GameObjectFactory#layer3d
|
||||
* @webglOnly
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {number} [x] - The horizontal position of this Game Object in the world.
|
||||
* @param {number} [y] - The vertical position of this Game Object in the world.
|
||||
*
|
||||
* @return {Phaser.GameObjects.Layer3D} The Game Object that was created.
|
||||
*/
|
||||
if (typeof WEBGL_RENDERER)
|
||||
{
|
||||
GameObjectFactory.register('layer3d', function (x, y)
|
||||
{
|
||||
return this.displayList.add(new Layer3D(this.scene, x, y));
|
||||
});
|
||||
}
|
||||
|
||||
// When registering a factory function 'this' refers to the GameObjectFactory context.
|
||||
//
|
||||
// There are several properties available to use:
|
||||
//
|
||||
// this.scene - a reference to the Scene that owns the GameObjectFactory
|
||||
// this.displayList - a reference to the Display List the Scene owns
|
||||
// this.updateList - a reference to the Update List the Scene owns
|
295
src/gameobjects/layer3d/Layer3DLight.js
Normal file
295
src/gameobjects/layer3d/Layer3DLight.js
Normal file
|
@ -0,0 +1,295 @@
|
|||
/**
|
||||
* @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 RGB = require('../../display/RGB');
|
||||
var Vector3 = require('../../math/Vector3');
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* A Layer3D Light.
|
||||
*
|
||||
* @class Layer3DLight
|
||||
* @memberof Phaser.GameObjects
|
||||
* @constructor
|
||||
* @since 3.50.0
|
||||
*/
|
||||
var Layer3DLight = new Class({
|
||||
|
||||
initialize:
|
||||
|
||||
function Layer3DLight (layer, x, y, z)
|
||||
{
|
||||
/**
|
||||
* The Layer3D instance this light belongs to.
|
||||
*
|
||||
* A light can only belong to a single Layer3D instance.
|
||||
*
|
||||
* You should consider this property as being read-only. You cannot move a
|
||||
* light to another Layer3D by simply changing it.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DLight#layer
|
||||
* @type {Phaser.GameObjects.Layer3D}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.layer = layer;
|
||||
|
||||
/**
|
||||
* The position of the light in 3D space.
|
||||
*
|
||||
* You can modify this vector directly, or use the `x`, `y` and `z`
|
||||
* properties of this class.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DLight#position
|
||||
* @type {Phaser.Math.Vector3}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.position = new Vector3(x, y, z);
|
||||
|
||||
/**
|
||||
* The ambient color of the light.
|
||||
*
|
||||
* The default ambient color is 1, 1, 1.
|
||||
*
|
||||
* You can modify the properties of this RGB object directly, or call
|
||||
* the `setAmbient` method of this class.
|
||||
*
|
||||
* The values in this object are used by the `uLightAmbient` shader uniform.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DLight#ambient
|
||||
* @type {Phaser.Display.RGB}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.ambient = new RGB(1, 1, 1);
|
||||
|
||||
/**
|
||||
* The diffuse color of the light.
|
||||
*
|
||||
* The default diffuse color is 1, 1, 1.
|
||||
*
|
||||
* You can modify the properties of this RGB object directly, or call
|
||||
* the `setDiffuse` method of this class.
|
||||
*
|
||||
* The values in this object are used by the `uLightDiffuse` shader uniform.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DLight#diffuse
|
||||
* @type {Phaser.Display.RGB}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.diffuse = new RGB(1, 1, 1);
|
||||
|
||||
/**
|
||||
* The specular color of the light.
|
||||
*
|
||||
* The default specular color is 1, 1, 1.
|
||||
*
|
||||
* You can modify the properties of this RGB object directly, or call
|
||||
* the `setSpecular` method of this class.
|
||||
*
|
||||
* The values in this object are used by the `uLightSpecular` shader uniform.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DLight#specular
|
||||
* @type {Phaser.Display.RGB}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.specular = new RGB(1, 1, 1);
|
||||
|
||||
/**
|
||||
* Internal dirty cache array.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DLight#dirtyCache
|
||||
* @type {number[]}
|
||||
* @private
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.dirtyCache = [ 0, 0, 0 ];
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if the position of this light is dirty.
|
||||
*
|
||||
* Called internally by the Mesh Pipeline `onBind` method and if dirty
|
||||
* is used to set the `uLightPosition` uniform.
|
||||
*
|
||||
* @method Phaser.GameObjects.Layer3DLight#isDirty
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @return {boolean} `true` if this light is dirty, otherwise `false`.
|
||||
*/
|
||||
isDirty: function ()
|
||||
{
|
||||
var position = this.position;
|
||||
var dirtyCache = this.dirtyCache;
|
||||
|
||||
var x = position.x;
|
||||
var y = position.y;
|
||||
var z = position.z;
|
||||
|
||||
var xCached = dirtyCache[0];
|
||||
var yCached = dirtyCache[1];
|
||||
var zCached = dirtyCache[2];
|
||||
|
||||
dirtyCache[0] = x;
|
||||
dirtyCache[1] = y;
|
||||
dirtyCache[2] = z;
|
||||
|
||||
return (xCached !== x || yCached !== y || zCached !== z);
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the position of this light.
|
||||
*
|
||||
* @method Phaser.GameObjects.Layer3DLight#setPosition
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {number} x - The x position of this light.
|
||||
* @param {number} y - The y position of this light.
|
||||
* @param {number} z - The z position of this light.
|
||||
*
|
||||
* @return {this} This Layer3DLight instance.
|
||||
*/
|
||||
setPosition: function (x, y, z)
|
||||
{
|
||||
this.position.set(x, y, z);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the ambient color of this light.
|
||||
*
|
||||
* @method Phaser.GameObjects.Layer3DLight#setAmbient
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {number} r - The red color value. Between 0 and 1.
|
||||
* @param {number} g - The green color value. Between 0 and 1.
|
||||
* @param {number} b - The blue color value. Between 0 and 1.
|
||||
*
|
||||
* @return {this} This Layer3DLight instance.
|
||||
*/
|
||||
setAmbient: function (r, g, b)
|
||||
{
|
||||
this.ambient.set(r, g, b);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the diffuse color of this light.
|
||||
*
|
||||
* @method Phaser.GameObjects.Layer3DLight#setDiffuse
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {number} r - The red color value. Between 0 and 1.
|
||||
* @param {number} g - The green color value. Between 0 and 1.
|
||||
* @param {number} b - The blue color value. Between 0 and 1.
|
||||
*
|
||||
* @return {this} This Layer3DLight instance.
|
||||
*/
|
||||
setDiffuse: function (r, g, b)
|
||||
{
|
||||
this.diffuse.set(r, g, b);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the specular color of this light.
|
||||
*
|
||||
* @method Phaser.GameObjects.Layer3DLight#setSpecular
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {number} r - The red color value. Between 0 and 1.
|
||||
* @param {number} g - The green color value. Between 0 and 1.
|
||||
* @param {number} b - The blue color value. Between 0 and 1.
|
||||
*
|
||||
* @return {this} This Layer3DLight instance.
|
||||
*/
|
||||
setSpecular: function (r, g, b)
|
||||
{
|
||||
this.specular.set(r, g, b);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* The x position of the light.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DLight#x
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
x: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this.position.x;
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
this.position.x = value;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* The y position of the light.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DLight#y
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
y: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this.position.y;
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
this.position.y = value;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* The z position of the light.
|
||||
*
|
||||
* @name Phaser.GameObjects.Layer3DLight#z
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
z: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this.position.z;
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
this.position.z = value;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Destroy handler for this light.
|
||||
*
|
||||
* @method Phaser.GameObjects.Layer3DLight#destroy
|
||||
* @since 3.50.0
|
||||
*/
|
||||
destroy: function ()
|
||||
{
|
||||
this.layer = null;
|
||||
this.position = null;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
module.exports = Layer3DLight;
|
25
src/gameobjects/layer3d/Layer3DRender.js
Normal file
25
src/gameobjects/layer3d/Layer3DRender.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* @author Richard Davey <rich@photonstorm.com>
|
||||
* @copyright 2020 Photon Storm Ltd.
|
||||
* @license {@link https://opensource.org/licenses/MIT|MIT License}
|
||||
*/
|
||||
|
||||
var renderWebGL = require('../../utils/NOOP');
|
||||
var renderCanvas = require('../../utils/NOOP');
|
||||
|
||||
if (typeof WEBGL_RENDERER)
|
||||
{
|
||||
renderWebGL = require('./Layer3DWebGLRenderer');
|
||||
}
|
||||
|
||||
if (typeof CANVAS_RENDERER)
|
||||
{
|
||||
renderCanvas = require('./Layer3DCanvasRenderer');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
renderWebGL: renderWebGL,
|
||||
renderCanvas: renderCanvas
|
||||
|
||||
};
|
52
src/gameobjects/layer3d/Layer3DWebGLRenderer.js
Normal file
52
src/gameobjects/layer3d/Layer3DWebGLRenderer.js
Normal file
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
* @author Richard Davey <rich@photonstorm.com>
|
||||
* @copyright 2020 Photon Storm Ltd.
|
||||
* @license {@link https://opensource.org/licenses/MIT|MIT License}
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* This method should not be called directly. It is a utility function of the Render module.
|
||||
*
|
||||
* @method Phaser.GameObjects.Layer3D#renderWebGL
|
||||
* @since 3.50.0
|
||||
* @private
|
||||
*
|
||||
* @param {Phaser.Renderer.WebGL.WebGLRenderer} renderer - A reference to the current active WebGL renderer.
|
||||
* @param {Phaser.GameObjects.Layer3D} src - The Game Object being rendered in this call.
|
||||
* @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 Layer3DWebGLRenderer = function (renderer, src)
|
||||
{
|
||||
var models = src.models;
|
||||
var totalModels = models.length;
|
||||
|
||||
if (totalModels === 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
renderer.pipelines.clear();
|
||||
|
||||
src.camera.update();
|
||||
|
||||
var pipeline = renderer.pipelines.set(src.pipeline, src);
|
||||
|
||||
for (var m = 0; m < totalModels; m++)
|
||||
{
|
||||
var model = models[m];
|
||||
|
||||
if (model.visible && model.vertexCount > 0)
|
||||
{
|
||||
pipeline.drawModel(src, model);
|
||||
}
|
||||
}
|
||||
|
||||
src.resetDirtyFlags();
|
||||
|
||||
renderer.pipelines.rebind();
|
||||
};
|
||||
|
||||
module.exports = Layer3DWebGLRenderer;
|
918
src/geom/mesh/Model.js
Normal file
918
src/geom/mesh/Model.js
Normal file
|
@ -0,0 +1,918 @@
|
|||
/**
|
||||
* @author Richard Davey <rich@photonstorm.com>
|
||||
* @copyright 2020 Photon Storm Ltd.
|
||||
* @license {@link https://opensource.org/licenses/MIT|MIT License}
|
||||
*/
|
||||
|
||||
var AnimationState = require('../../animations/AnimationState');
|
||||
var Class = require('../../utils/Class');
|
||||
var Components = require('../../gameobjects/components');
|
||||
var Matrix4 = require('../../math/Matrix4');
|
||||
var Quaternion = require('../../math/Quaternion');
|
||||
var RGB = require('../../layer3d/math/RGB');
|
||||
var Vector3 = require('../../math/Vector3');
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* A 3D Model.
|
||||
*
|
||||
* @class Model
|
||||
* @memberof Phaser.Geom.Mesh
|
||||
* @constructor
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {Phaser.GameObjects.Layer3D} layer - A reference to the Layer3D instance that this model belongs to.
|
||||
* @param {number} verticesCount - The total number of vertices this model can contain.
|
||||
* @param {string|Phaser.Textures.Texture} [texture] - The key, or instance of the Texture this model will use to render with, as stored in the Texture Manager.
|
||||
* @param {string|integer} [frame] - An optional frame from the Texture this model is rendering with. Ensure your UV data also matches this frame.
|
||||
* @param {number} [x=0] - The x position of the Model.
|
||||
* @param {number} [y=0] - The y position of the Model.
|
||||
* @param {number} [z=0] - The z position of the Model.
|
||||
*/
|
||||
var Model = new Class({
|
||||
|
||||
Mixins: [
|
||||
Components.AlphaSingle,
|
||||
Components.Size,
|
||||
Components.Texture,
|
||||
Components.Visible
|
||||
],
|
||||
|
||||
initialize:
|
||||
|
||||
function Model (layer, verticesCount, texture, frame, x, y, z)
|
||||
{
|
||||
if (x === undefined) { x = 0; }
|
||||
if (y === undefined) { y = 0; }
|
||||
if (z === undefined) { z = 0; }
|
||||
|
||||
/**
|
||||
* The Layer3D instance this model belongs to.
|
||||
*
|
||||
* A model can only belong to a single Layer3D instance.
|
||||
*
|
||||
* You should consider this property as being read-only. You cannot move a
|
||||
* model to another Layer3D by simply changing it.
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Model#layer
|
||||
* @type {Phaser.GameObjects.Layer3D}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.layer = layer;
|
||||
|
||||
/**
|
||||
* A reference to the Scene to which this the Layer3D Object which owns this model belongs.
|
||||
*
|
||||
* You should consider this property as being read-only. You cannot move a
|
||||
* Game Object to another Scene by simply changing it.
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Model#scene
|
||||
* @type {Phaser.Scene}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.scene = layer.scene;
|
||||
|
||||
/**
|
||||
* The Animation State of this Model.
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Model#anims
|
||||
* @type {Phaser.Animation.AnimationState}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.anims = new AnimationState(this);
|
||||
|
||||
/**
|
||||
* The size of a single vertex, in bytes.
|
||||
*
|
||||
* The total of all 8 attributes * bytes size.
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Model#vertexSize
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.vertexSize = 32;
|
||||
|
||||
/**
|
||||
* The total number of vertices the ArrayBuffer in this model can hold.
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Model#maxVertexCount
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.maxVertexCount = verticesCount;
|
||||
|
||||
/**
|
||||
* The total number of vertices currently added to this model.
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Model#vertexCount
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.vertexCount = 0;
|
||||
|
||||
/**
|
||||
* An ArrayBuffer that contains the GPU byte data for this model.
|
||||
*
|
||||
* The size of the buffer is set to `verticesCount * vertexSize` when
|
||||
* this model is created and cannot be changed without resetting the vertices.
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Model#vertexData
|
||||
* @type {ArrayBuffer}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.vertexData;
|
||||
|
||||
/**
|
||||
* A Float32 View into the Array Buffer.
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Model#vertexViewF32
|
||||
* @type {Float32Array}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.vertexViewF32;
|
||||
|
||||
/**
|
||||
* A Vector3 containing the position of this model in 3D space.
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Model#position
|
||||
* @type {Phaser.Math.Vector3}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.position = new Vector3(x, y, z);
|
||||
|
||||
/**
|
||||
* A Vector3 containing the scale of this model in 3D space.
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Model#scale
|
||||
* @type {Phaser.Math.Vector3}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.scale = new Vector3(1, 1, 1);
|
||||
|
||||
/**
|
||||
* A Quaternion containing the rotation of this model in 3D space.
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Model#position
|
||||
* @type {Phaser.Math.Quaternion}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.rotation = new Quaternion();
|
||||
|
||||
/**
|
||||
* An RGB object containing the ambient material color of this model.
|
||||
*
|
||||
* You can adjust the ambient material color by calling the methods
|
||||
* on this object and changing its properties.
|
||||
*
|
||||
* Remember that all color values should be specified in the range
|
||||
* of 0 to 1.
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Model#ambient
|
||||
* @type {Phaser.Display.RGB}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.ambient = new RGB(1, 1, 1);
|
||||
|
||||
/**
|
||||
* An RGB object containing the diffuse material color of this model.
|
||||
*
|
||||
* You can adjust the diffuse material color by calling the methods
|
||||
* on this object and changing its properties.
|
||||
*
|
||||
* Remember that all color values should be specified in the range
|
||||
* of 0 to 1.
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Model#diffuse
|
||||
* @type {Phaser.Display.RGB}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.diffuse = new RGB(1, 1, 1);
|
||||
|
||||
/**
|
||||
* An RGB object containing the specular material color of this model.
|
||||
*
|
||||
* You can adjust the specular material color by calling the methods
|
||||
* on this object and changing its properties.
|
||||
*
|
||||
* Remember that all color values should be specified in the range
|
||||
* of 0 to 1.
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Model#specular
|
||||
* @type {Phaser.Display.RGB}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.specular = new RGB(1, 1, 1);
|
||||
|
||||
/**
|
||||
* The material shine value of this model.
|
||||
*
|
||||
* Default to 0.25. Keep this value in the range 0 to 1.
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Model#ambient
|
||||
* @type {number}
|
||||
* @default 0.25
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.shine = 0.25;
|
||||
|
||||
/**
|
||||
* A Matrix4 containing the transformed normal values for this model.
|
||||
*
|
||||
* You should consider this Matrix as being read-only. Its values are
|
||||
* repopulated during `Model.preUpdate` as required.
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Model#normalMatrix
|
||||
* @type {Phaser.Math.Matrix4}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.normalMatrix = new Matrix4();
|
||||
|
||||
/**
|
||||
* A Matrix4 containing the transform matrix for this model.
|
||||
*
|
||||
* You should consider this Matrix as being read-only. Its values are
|
||||
* repopulated during `Model.preUpdate` as required.
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Model#transformMatrix
|
||||
* @type {Phaser.Math.Matrix4}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.transformMatrix = new Matrix4();
|
||||
|
||||
/**
|
||||
* The culling mode used by this Model during rendering.
|
||||
*
|
||||
* Specifies whether front or back facing polygons are candidates
|
||||
* for culling. The default value is `gl.BACK`. Possible values are:
|
||||
*
|
||||
* `gl.FRONT` (1028)
|
||||
* `gl.BACK` (1029)
|
||||
* `gl.FRONT_AND_BACK` (1032)
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Model#cullMode
|
||||
* @type {GLenum}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.cullMode = 1029;
|
||||
|
||||
/**
|
||||
* An internal cache, used to compare position, rotation, scale and verts data
|
||||
* each frame, to avoid math calculates in `preUpdate`.
|
||||
*
|
||||
* cache structure = position | rotation | scale | verts count
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Model#dirtyCache
|
||||
* @type {number[]}
|
||||
* @private
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.dirtyCache = [ x, y, z, 0, 0, 0, 1, 1, 1, 1, 0 ];
|
||||
|
||||
if (!texture)
|
||||
{
|
||||
texture = this.scene.sys.textures.get('__WHITE');
|
||||
}
|
||||
|
||||
this.setTexture(texture, frame);
|
||||
|
||||
this.setSizeToFrame();
|
||||
|
||||
this.resetVertices(verticesCount);
|
||||
},
|
||||
|
||||
/**
|
||||
* Calls each of the listeners registered for a given event.
|
||||
*
|
||||
* This is a proxy for the Layer3D `emit` method.
|
||||
*
|
||||
* @method Phaser.Geom.Mesh.Model#emit
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {(string|symbol)} event - The event name.
|
||||
* @param {...*} [args] - Additional arguments that will be passed to the event handler.
|
||||
*
|
||||
* @return {boolean} `true` if the event had listeners, else `false`.
|
||||
*/
|
||||
emit: function ()
|
||||
{
|
||||
return this.layer.emit.call(arguments);
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks all of the current model values against the `dirtyCache` to see if the
|
||||
* normal and transform matrices need updating.
|
||||
*
|
||||
* @method Phaser.Geom.Mesh.Model#isDirty
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @return {boolean} Returns `true` if any of the model values are dirty, otherwise `false`.
|
||||
*/
|
||||
isDirty: function ()
|
||||
{
|
||||
var position = this.position;
|
||||
var rotation = this.rotation;
|
||||
var scale = this.scale;
|
||||
|
||||
var dirtyCache = this.dirtyCache;
|
||||
|
||||
var px = position.x;
|
||||
var py = position.y;
|
||||
var pz = position.z;
|
||||
|
||||
var rx = rotation.x;
|
||||
var ry = rotation.y;
|
||||
var rz = rotation.z;
|
||||
var rw = rotation.w;
|
||||
|
||||
var sx = scale.x;
|
||||
var sy = scale.y;
|
||||
var sz = scale.z;
|
||||
|
||||
var vertices = this.vertexCount;
|
||||
|
||||
var pxCached = dirtyCache[0];
|
||||
var pyCached = dirtyCache[1];
|
||||
var pzCached = dirtyCache[2];
|
||||
|
||||
var rxCached = dirtyCache[3];
|
||||
var ryCached = dirtyCache[4];
|
||||
var rzCached = dirtyCache[5];
|
||||
var rwCached = dirtyCache[6];
|
||||
|
||||
var sxCached = dirtyCache[7];
|
||||
var syCached = dirtyCache[8];
|
||||
var szCached = dirtyCache[9];
|
||||
|
||||
var vCached = dirtyCache[10];
|
||||
|
||||
dirtyCache[0] = px;
|
||||
dirtyCache[1] = py;
|
||||
dirtyCache[2] = pz;
|
||||
|
||||
dirtyCache[3] = rx;
|
||||
dirtyCache[4] = ry;
|
||||
dirtyCache[5] = rz;
|
||||
dirtyCache[6] = rw;
|
||||
|
||||
dirtyCache[7] = sx;
|
||||
dirtyCache[8] = sy;
|
||||
dirtyCache[9] = sz;
|
||||
|
||||
dirtyCache[10] = vertices;
|
||||
|
||||
return (
|
||||
pxCached !== px || pyCached !== py || pzCached !== pz ||
|
||||
rxCached !== rx || ryCached !== ry || rzCached !== rz || rwCached !== rw ||
|
||||
sxCached !== sx || syCached !== sy || szCached !== sz ||
|
||||
vCached !== vertices
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Internal update handler. Advances any animations that are set on the model and,
|
||||
* if the model data is dirty, recalculates the transform and normal matrices.
|
||||
*
|
||||
* This method is called automatically by the `Layer3D` to which this model belongs.
|
||||
*
|
||||
* @method Phaser.Geom.Mesh.Model#preUpdate
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {number} time - The current timestamp.
|
||||
* @param {number} delta - The delta time, in ms, elapsed since the last frame.
|
||||
*/
|
||||
preUpdate: function (time, delta)
|
||||
{
|
||||
this.anims.update(time, delta);
|
||||
|
||||
// If the model isn't dirty we can bail out and save lots of math
|
||||
if (this.isDirty())
|
||||
{
|
||||
var normalMatrix = this.normalMatrix;
|
||||
var transformMatrix = this.transformMatrix;
|
||||
|
||||
// TODO - Merge scale into this op
|
||||
transformMatrix.fromRotationTranslation(this.rotation, this.position);
|
||||
transformMatrix.scale(this.scale);
|
||||
|
||||
normalMatrix.copy(transformMatrix);
|
||||
normalMatrix.invert();
|
||||
normalMatrix.transpose();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the total number of Faces _currently added_ to this model.
|
||||
*
|
||||
* Models in Phaser 3 must always be triangulated, so this value is the same as
|
||||
* `vertexCount / 3`.
|
||||
*
|
||||
* @method Phaser.Geom.Mesh.Model#getFaceCount
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @return {number} The number of Faces in this Model.
|
||||
*/
|
||||
getFaceCount: function ()
|
||||
{
|
||||
return this.vertexCount / 3;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the Vertex at the given offset from this models data.
|
||||
*
|
||||
* Be aware that the returned Vertex is untranslated, so will need transforming if you wish
|
||||
* to use its coordinates in world space.
|
||||
*
|
||||
* @method Phaser.Geom.Mesh.Model#getVertex
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {number} index - The index of the vertex to get. Cannot be negative, or exceed `Model.vertexCount`.
|
||||
*
|
||||
* @return {Phaser.Types.GameObjects.Vertex} A Vertex object.
|
||||
*/
|
||||
getVertex: function (index)
|
||||
{
|
||||
var vertexViewF32 = this.vertexViewF32;
|
||||
|
||||
// 8 = attribute count (number of items added into the view below)
|
||||
var vertexOffset = (index * 8) - 1;
|
||||
|
||||
var x = vertexViewF32[++vertexOffset];
|
||||
var y = vertexViewF32[++vertexOffset];
|
||||
var z = vertexViewF32[++vertexOffset];
|
||||
var normalX = vertexViewF32[++vertexOffset];
|
||||
var normalY = vertexViewF32[++vertexOffset];
|
||||
var normalZ = vertexViewF32[++vertexOffset];
|
||||
var u = vertexViewF32[++vertexOffset];
|
||||
var v = vertexViewF32[++vertexOffset];
|
||||
|
||||
return { x: x, y: y, z: z, u: u, v: v, normalX: normalX, normalY: normalY, normalZ: normalZ, alpha: 1 };
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the Face at the given index in this model.
|
||||
*
|
||||
* A face comprises of 3 vertices.
|
||||
*
|
||||
* Be aware that the Face vertices are untranslated, so will need transforming if you wish
|
||||
* to use their coordinates in world space.
|
||||
*
|
||||
* @method Phaser.Geom.Mesh.Model#getFace
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {number} index - The index of the Face to get. Make sure the index is in range.
|
||||
*
|
||||
* @return {Phaser.Types.GameObjects.Face} The Face at the given index.
|
||||
*/
|
||||
getFace: function (index)
|
||||
{
|
||||
var offset = index * 3;
|
||||
|
||||
var v1 = this.getVertex(offset);
|
||||
var v2 = this.getVertex(offset + 1);
|
||||
var v3 = this.getVertex(offset + 2);
|
||||
var ccw = (v2.x - v1.x) * (v3.y - v1.y) - (v2.y - v1.y) * (v3.x - v1.x) >= 0;
|
||||
|
||||
return { vertex1: v1, vertex2: v2, vertex3: 3, isCounterClockwise: ccw };
|
||||
},
|
||||
|
||||
/**
|
||||
* Resets the data in this model, clearing the `vertexData` ArrayBuffer and
|
||||
* setting it to the new max count given.
|
||||
*
|
||||
* @method Phaser.Geom.Mesh.Model#resetVertices
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {number} verticesCount - The total number of vertices this model can contain.
|
||||
*/
|
||||
resetVertices: function (verticesCount)
|
||||
{
|
||||
this.vertexData = new ArrayBuffer(verticesCount * this.vertexSize);
|
||||
this.vertexViewF32 = new Float32Array(this.vertexData);
|
||||
this.vertexCount = 0;
|
||||
this.maxVertexCount = verticesCount;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates all values of the vertex at the given index.
|
||||
*
|
||||
* Ensure that the index is in range.
|
||||
*
|
||||
* @method Phaser.Geom.Mesh.Model#updateVertex
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {number} index - The index of the vertex to update.
|
||||
* @param {number} x - The x position of the vertex.
|
||||
* @param {number} y - The y position of the vertex.
|
||||
* @param {number} z - The z position of the vertex.
|
||||
* @param {number} u - The UV u coordinate of the vertex.
|
||||
* @param {number} v - The UV v coordinate of the vertex.
|
||||
* @param {number} normalX - The x normal of the vertex.
|
||||
* @param {number} normalY - The y normal of the vertex.
|
||||
* @param {number} normalZ - The z normal of the vertex.
|
||||
*/
|
||||
updateVertex: function (index, x, y, z, u, v, normalX, normalY, normalZ)
|
||||
{
|
||||
var vertexViewF32 = this.vertexViewF32;
|
||||
|
||||
// 8 = attribute count
|
||||
var vertexOffset = (index * 8) - 1;
|
||||
|
||||
vertexViewF32[++vertexOffset] = x;
|
||||
vertexViewF32[++vertexOffset] = y;
|
||||
vertexViewF32[++vertexOffset] = z;
|
||||
vertexViewF32[++vertexOffset] = normalX;
|
||||
vertexViewF32[++vertexOffset] = normalY;
|
||||
vertexViewF32[++vertexOffset] = normalZ;
|
||||
vertexViewF32[++vertexOffset] = u;
|
||||
vertexViewF32[++vertexOffset] = v;
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a new vertex to this model and increments the `vertexCount` by one.
|
||||
*
|
||||
* You cannot add more vertices to this model than the total specified when the model was created.
|
||||
* If you need to clear all vertices first, call `Model.resetVertices`.
|
||||
*
|
||||
* @method Phaser.Geom.Mesh.Model#addVertex
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {number} x - The x position of the vertex.
|
||||
* @param {number} y - The y position of the vertex.
|
||||
* @param {number} z - The z position of the vertex.
|
||||
* @param {number} u - The UV u coordinate of the vertex.
|
||||
* @param {number} v - The UV v coordinate of the vertex.
|
||||
* @param {number} normalX - The x normal of the vertex.
|
||||
* @param {number} normalY - The y normal of the vertex.
|
||||
* @param {number} normalZ - The z normal of the vertex.
|
||||
*/
|
||||
addVertex: function (x, y, z, u, v, normalX, normalY, normalZ)
|
||||
{
|
||||
if (this.vertexCount < this.maxVertexCount)
|
||||
{
|
||||
this.updateVertex(this.vertexCount, x, y, z, u, v, normalX, normalY, normalZ);
|
||||
|
||||
this.vertexCount++;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds vertices to this model by parsing the given arrays.
|
||||
*
|
||||
* This method will take vertex data in one of two formats, based on the `containsZ` parameter.
|
||||
*
|
||||
* If your vertex data are `x`, `y` pairs, then `containsZ` should be `false` (this is the default)
|
||||
*
|
||||
* If your vertex data is groups of `x`, `y` and `z` values, then the `containsZ` parameter must be true.
|
||||
*
|
||||
* The `uvs` parameter is a numeric array consisting of `u` and `v` pairs.
|
||||
* The `normals` parameter is a numeric array consisting of `x`, `y` vertex normal values and, if `containsZ` is true, `z` values as well.
|
||||
* The `indicies` parameter is an optional array that, if given, is an indexed list of vertices to be added.
|
||||
*
|
||||
* The following example will create a 256 x 256 sized quad using an index array:
|
||||
*
|
||||
* ```javascript
|
||||
* const vertices = [
|
||||
* -128, 128,
|
||||
* 128, 128,
|
||||
* -128, -128,
|
||||
* 128, -128
|
||||
* ];
|
||||
*
|
||||
* const uvs = [
|
||||
* 0, 1,
|
||||
* 1, 1,
|
||||
* 0, 0,
|
||||
* 1, 0
|
||||
* ];
|
||||
*
|
||||
* const indices = [ 0, 2, 1, 2, 3, 1 ];
|
||||
*
|
||||
* Model.addVertices(vertices, uvs, indicies);
|
||||
* ```
|
||||
*
|
||||
* You cannot add more vertices to this model than the total specified when the model was created.
|
||||
* If you need to clear all vertices first, call `Model.resetVertices`.
|
||||
*
|
||||
* @method Phaser.Geom.Mesh.Model#addVertices
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {number[]} vertices - The vertices array. Either `xy` pairs, or `xyz` if the `containsZ` parameter is `true`.
|
||||
* @param {number[]} uvs - The UVs pairs array.
|
||||
* @param {number[]} [normals] - Optional vertex normals array. If you don't have one, pass `null` or an empty array.
|
||||
* @param {number[]} [indicies] - Optional vertex indicies array. If you don't have one, pass `null` or an empty array.
|
||||
* @param {boolean} [containsZ=false] - Does the vertices data include a `z` component?
|
||||
*/
|
||||
addVertices: function (vertices, uvs, normals, indicies, containsZ)
|
||||
{
|
||||
if (containsZ === undefined) { containsZ = false; }
|
||||
|
||||
if (vertices.length !== uvs.length)
|
||||
{
|
||||
throw new Error('Model vertices and uv count not equal');
|
||||
}
|
||||
|
||||
var i;
|
||||
var x;
|
||||
var y;
|
||||
var z;
|
||||
var u;
|
||||
var v;
|
||||
var normalX;
|
||||
var normalY;
|
||||
var normalZ;
|
||||
var iInc = (containsZ) ? 3 : 2;
|
||||
|
||||
if (Array.isArray(indicies) && indicies.length > 0)
|
||||
{
|
||||
for (i = 0; i < indicies.length; i++)
|
||||
{
|
||||
var index = indicies[i] * iInc;
|
||||
|
||||
x = vertices[index];
|
||||
y = vertices[index + 1];
|
||||
z = (containsZ) ? vertices[index + 2] : 0;
|
||||
u = uvs[index];
|
||||
v = uvs[index + 1];
|
||||
normalX = 0;
|
||||
normalY = 0;
|
||||
normalZ = 0;
|
||||
|
||||
if (normals)
|
||||
{
|
||||
normalX = normals[index];
|
||||
normalY = normals[index + 1];
|
||||
normalZ = (containsZ) ? normals[index + 2] : 0;
|
||||
}
|
||||
|
||||
this.addVertex(
|
||||
x, y, z,
|
||||
u, v,
|
||||
normalX, normalY, normalZ
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < vertices.length; i += iInc)
|
||||
{
|
||||
x = vertices[i];
|
||||
y = vertices[i + 1];
|
||||
z = (containsZ) ? vertices[i + 2] : 0;
|
||||
u = uvs[i];
|
||||
v = uvs[i + 1];
|
||||
normalX = 0;
|
||||
normalY = 0;
|
||||
normalZ = 0;
|
||||
|
||||
if (normals)
|
||||
{
|
||||
normalX = normals[i];
|
||||
normalY = normals[i + 1];
|
||||
normalZ = (containsZ) ? normals[i + 2] : 0;
|
||||
}
|
||||
|
||||
this.addVertex(
|
||||
x, y, z,
|
||||
u, v,
|
||||
normalX, normalY, normalZ
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Rotates this model along the x axis by the given amount.
|
||||
*
|
||||
* This method works by calling the `rotateX` method of the `rotation` quaternion of this model.
|
||||
*
|
||||
* @method Phaser.Geom.Mesh.Model#rotateX
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {number} rad - The amount, in radians, to rotate the model by.
|
||||
*
|
||||
* @return {this} This model instance.
|
||||
*/
|
||||
rotateX: function (rad)
|
||||
{
|
||||
this.rotation.rotateX(rad);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Rotates this model along the y axis by the given amount.
|
||||
*
|
||||
* This method works by calling the `rotateY` method of the `rotation` quaternion of this model.
|
||||
*
|
||||
* @method Phaser.Geom.Mesh.Model#rotateY
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {number} rad - The amount, in radians, to rotate the model by.
|
||||
*
|
||||
* @return {this} This model instance.
|
||||
*/
|
||||
rotateY: function (rad)
|
||||
{
|
||||
this.rotation.rotateY(rad);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Rotates this model along the z axis by the given amount.
|
||||
*
|
||||
* This method works by calling the `rotateZ` method of the `rotation` quaternion of this model.
|
||||
*
|
||||
* @method Phaser.Geom.Mesh.Model#rotateZ
|
||||
* @since 3.50.0
|
||||
*
|
||||
* @param {number} rad - The amount, in radians, to rotate the model by.
|
||||
*
|
||||
* @return {this} This model instance.
|
||||
*/
|
||||
rotateZ: function (rad)
|
||||
{
|
||||
this.rotation.rotateZ(rad);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
setPosition: function (x, y, z)
|
||||
{
|
||||
this.position.set(x, y, z);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
setScale: function (x, y, z)
|
||||
{
|
||||
this.scale.set(x, y, z);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* The x position of this model in 3D space.
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Model#x
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
x: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this.position.x;
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
this.position.x = value;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* The y position of this model in 3D space.
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Model#y
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
y: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this.position.y;
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
this.position.y = value;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* The z position of this model in 3D space.
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Model#z
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
z: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this.position.z;
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
this.position.z = value;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* The x scale of this model in 3D space.
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Model#scaleX
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
scaleX: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this.scale.x;
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
this.scale.x = value;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* The y scale of this model in 3D space.
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Model#scaleY
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
scaleY: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this.scale.y;
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
this.scale.y = value;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* The z scale of this model in 3D space.
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Model#scaleZ
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
scaleZ: {
|
||||
|
||||
get: function ()
|
||||
{
|
||||
return this.scale.z;
|
||||
},
|
||||
|
||||
set: function (value)
|
||||
{
|
||||
this.scale.z = value;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Destroys this Model instance, all of its vertex data and references.
|
||||
*
|
||||
* Calling this method will not remove it from any parent Layer3D, so be sure to do that first,
|
||||
* prior to calling `destroy`.
|
||||
*
|
||||
* If a Layer3D object is destroyed, this is the method that is called on all of its models.
|
||||
*
|
||||
* @method Phaser.Geom.Mesh.Model#destroy
|
||||
* @since 3.50.0
|
||||
*/
|
||||
destroy: function ()
|
||||
{
|
||||
this.anims.destroy();
|
||||
|
||||
this.layer = null;
|
||||
this.scene = null;
|
||||
this.anims = null;
|
||||
|
||||
this.vertexData = null;
|
||||
this.vertexViewF32 = null;
|
||||
|
||||
this.position = null;
|
||||
this.scale = null;
|
||||
this.rotation = null;
|
||||
|
||||
this.ambient = null;
|
||||
this.diffuse = null;
|
||||
this.specular = null;
|
||||
|
||||
this.normalMatrix = null;
|
||||
this.transformMatrix = null;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
module.exports = Model;
|
|
@ -70,6 +70,33 @@ var Vertex = new Class({
|
|||
*/
|
||||
this.vz = 0;
|
||||
|
||||
/**
|
||||
* The projected x coordinate of this vertex.
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Vertex#vx
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.nx = 0;
|
||||
|
||||
/**
|
||||
* The projected y coordinate of this vertex.
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Vertex#vy
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.ny = 0;
|
||||
|
||||
/**
|
||||
* The projected z coordinate of this vertex.
|
||||
*
|
||||
* @name Phaser.Geom.Mesh.Vertex#vz
|
||||
* @type {number}
|
||||
* @since 3.50.0
|
||||
*/
|
||||
this.nz = 0;
|
||||
|
||||
/**
|
||||
* UV u coordinate of this vertex.
|
||||
*
|
||||
|
@ -107,6 +134,15 @@ var Vertex = new Class({
|
|||
this.alpha = alpha;
|
||||
},
|
||||
|
||||
setNormals: function (nx, ny, nz)
|
||||
{
|
||||
this.nx = nx;
|
||||
this.ny = ny;
|
||||
this.nz = nz;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Transforms this vertex by the given matrix, storing the results in `vx`, `vy` and `vz`.
|
||||
*
|
||||
|
|
|
@ -14,6 +14,7 @@ var LightPipeline = require('./pipelines/LightPipeline');
|
|||
var MultiPipeline = require('./pipelines/MultiPipeline');
|
||||
var RopePipeline = require('./pipelines/RopePipeline');
|
||||
var SinglePipeline = require('./pipelines/SinglePipeline');
|
||||
var MeshPipeline = require('./pipelines/MeshPipeline');
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
|
@ -146,6 +147,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);
|
||||
},
|
||||
|
|
288
src/renderer/webgl/pipelines/MeshPipeline.js
Normal file
288
src/renderer/webgl/pipelines/MeshPipeline.js
Normal file
|
@ -0,0 +1,288 @@
|
|||
/**
|
||||
* @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', 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
|
||||
}
|
||||
]);
|
||||
config.uniforms = GetFastValue(config, 'uniforms', [
|
||||
'uViewProjectionMatrix',
|
||||
'uLightPosition',
|
||||
'uLightAmbient',
|
||||
'uLightDiffuse',
|
||||
'uLightSpecular',
|
||||
'uCameraPosition',
|
||||
'uFogColor',
|
||||
'uFogNear',
|
||||
'uFogFar',
|
||||
'uModelMatrix',
|
||||
'uNormalMatrix',
|
||||
'uMaterialAmbient',
|
||||
'uMaterialDiffuse',
|
||||
'uMaterialSpecular',
|
||||
'uMaterialShine',
|
||||
'uTexture'
|
||||
]);
|
||||
|
||||
WebGLPipeline.call(this, config);
|
||||
|
||||
this.forceZero = true;
|
||||
|
||||
// Cache structure:
|
||||
|
||||
// 0 fog near
|
||||
// 1 fog far
|
||||
// 2, 3, 4 model material ambient
|
||||
// 5, 6, 7 model material diffuse
|
||||
// 8, 9, 10 model material specular
|
||||
// 11 model material shine
|
||||
|
||||
this.dirtyCache = [
|
||||
-1,
|
||||
-1,
|
||||
-1, -1, -1,
|
||||
-1, -1, -1,
|
||||
-1, -1, -1,
|
||||
-1
|
||||
];
|
||||
|
||||
this.cullMode = 1029;
|
||||
},
|
||||
|
||||
/**
|
||||
* 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 camera = mesh.camera;
|
||||
|
||||
if (camera.dirtyView || camera.dirtyProjection)
|
||||
{
|
||||
this.setMatrix4fv('uViewProjectionMatrix', false, camera.viewProjectionMatrix.val);
|
||||
|
||||
this.set3f('uCameraPosition', camera.x, camera.y, camera.z);
|
||||
}
|
||||
|
||||
var light = mesh.light;
|
||||
|
||||
if (light.isDirty())
|
||||
{
|
||||
this.set3f('uLightPosition', light.x, light.y, light.z);
|
||||
}
|
||||
|
||||
var ambient = light.ambient;
|
||||
var diffuse = light.diffuse;
|
||||
var specular = light.specular;
|
||||
|
||||
if (ambient.dirty)
|
||||
{
|
||||
this.set3f('uLightAmbient', ambient.r, ambient.g, ambient.b);
|
||||
}
|
||||
|
||||
if (diffuse.dirty)
|
||||
{
|
||||
this.set3f('uLightDiffuse', diffuse.r, diffuse.g, diffuse.b);
|
||||
}
|
||||
|
||||
if (specular.dirty)
|
||||
{
|
||||
this.set3f('uLightSpecular', specular.r, specular.g, specular.b);
|
||||
}
|
||||
|
||||
var fogColor = mesh.fogColor;
|
||||
|
||||
if (fogColor.dirty)
|
||||
{
|
||||
this.set3f('uFogColor', fogColor.r, fogColor.g, fogColor.b);
|
||||
}
|
||||
|
||||
var cache = this.dirtyCache;
|
||||
var fogNear = mesh.fogNear;
|
||||
var fogFar = mesh.fogFar;
|
||||
|
||||
if (cache[0] !== fogNear)
|
||||
{
|
||||
this.set1f('uFogNear', fogNear);
|
||||
|
||||
cache[0] = fogNear;
|
||||
}
|
||||
|
||||
if (cache[1] !== fogFar)
|
||||
{
|
||||
this.set1f('uFogFar', fogFar);
|
||||
|
||||
cache[1] = fogFar;
|
||||
}
|
||||
|
||||
this.set1i('uTexture', 0);
|
||||
},
|
||||
|
||||
drawModel: function (mesh, model)
|
||||
{
|
||||
var cache = this.dirtyCache;
|
||||
|
||||
this.setMatrix4fv('uModelMatrix', false, model.transformMatrix.val);
|
||||
this.setMatrix4fv('uNormalMatrix', false, model.normalMatrix.val);
|
||||
|
||||
var ambient = model.ambient;
|
||||
|
||||
if (!ambient.equals(cache[2], cache[3], cache[4]))
|
||||
{
|
||||
this.set3f('uMaterialAmbient', ambient.r, ambient.g, ambient.b);
|
||||
|
||||
cache[2] = ambient.r;
|
||||
cache[3] = ambient.g;
|
||||
cache[4] = ambient.b;
|
||||
}
|
||||
|
||||
var diffuse = model.diffuse;
|
||||
|
||||
if (!diffuse.equals(cache[5], cache[6], cache[7]))
|
||||
{
|
||||
this.set3f('uMaterialDiffuse', diffuse.r, diffuse.g, diffuse.b);
|
||||
|
||||
cache[5] = diffuse.r;
|
||||
cache[6] = diffuse.g;
|
||||
cache[7] = diffuse.b;
|
||||
}
|
||||
|
||||
var specular = model.specular;
|
||||
|
||||
if (!specular.equals(cache[8], cache[9], cache[10]))
|
||||
{
|
||||
this.set3f('uMaterialSpecular', specular.r, specular.g, specular.b);
|
||||
|
||||
cache[8] = specular.r;
|
||||
cache[9] = specular.g;
|
||||
cache[10] = specular.b;
|
||||
}
|
||||
|
||||
var shine = model.shine;
|
||||
|
||||
if (!shine !== cache[11])
|
||||
{
|
||||
this.set1f('uMaterialShine', shine);
|
||||
|
||||
cache[11] = specular.b;
|
||||
}
|
||||
|
||||
this.renderer.setTextureZero(model.frame.glTexture);
|
||||
|
||||
// All the uniforms are finally bound, so let's buffer our data
|
||||
var gl = this.gl;
|
||||
|
||||
var cullMode = model.cullMode;
|
||||
|
||||
if (cullMode !== this.cullMode)
|
||||
{
|
||||
this.cullMode = cullMode;
|
||||
|
||||
gl.cullFace(cullMode);
|
||||
}
|
||||
|
||||
// STATIC because the buffer data doesn't change, the uniforms do
|
||||
gl.bufferData(gl.ARRAY_BUFFER, model.vertexData, gl.STATIC_DRAW);
|
||||
|
||||
gl.drawArrays(this.topology, 0, model.vertexCount);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
module.exports = MeshPipeline;
|
|
@ -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'
|
||||
|
||||
};
|
||||
|
||||
|
|
54
src/renderer/webgl/shaders/Mesh-frag.js
Normal file
54
src/renderer/webgl/shaders/Mesh-frag.js
Normal file
|
@ -0,0 +1,54 @@
|
|||
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 uFogColor;',
|
||||
'uniform float uFogNear;',
|
||||
'uniform float uFogFar;',
|
||||
'',
|
||||
'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;',
|
||||
'',
|
||||
' float depth = gl_FragCoord.z / gl_FragCoord.w;',
|
||||
'',
|
||||
' float fogFactor = smoothstep(uFogNear, uFogFar, depth);',
|
||||
'',
|
||||
' gl_FragColor.rgb = mix(result.rgb, uFogColor, fogFactor);',
|
||||
' gl_FragColor.a = color.a;',
|
||||
'}',
|
||||
''
|
||||
].join('\n');
|
29
src/renderer/webgl/shaders/Mesh-vert.js
Normal file
29
src/renderer/webgl/shaders/Mesh-vert.js
Normal 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');
|
51
src/renderer/webgl/shaders/src/Mesh.frag
Normal file
51
src/renderer/webgl/shaders/src/Mesh.frag
Normal file
|
@ -0,0 +1,51 @@
|
|||
#define SHADER_NAME PHASER_MESH_FS
|
||||
|
||||
precision mediump float;
|
||||
|
||||
uniform vec3 uLightPosition;
|
||||
uniform vec3 uLightAmbient;
|
||||
uniform vec3 uLightDiffuse;
|
||||
uniform vec3 uLightSpecular;
|
||||
|
||||
uniform vec3 uFogColor;
|
||||
uniform float uFogNear;
|
||||
uniform float uFogFar;
|
||||
|
||||
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;
|
||||
|
||||
float depth = gl_FragCoord.z / gl_FragCoord.w;
|
||||
|
||||
float fogFactor = smoothstep(uFogNear, uFogFar, depth);
|
||||
|
||||
gl_FragColor.rgb = mix(result.rgb, uFogColor, fogFactor);
|
||||
gl_FragColor.a = color.a;
|
||||
}
|
26
src/renderer/webgl/shaders/src/Mesh.vert
Normal file
26
src/renderer/webgl/shaders/src/Mesh.vert
Normal 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);
|
||||
}
|
Loading…
Reference in a new issue