Do matrix transforms in vertex shader.

This commit is contained in:
Ben Richards 2024-04-23 21:07:34 +12:00
parent cc78cf9480
commit a26972d77e
9 changed files with 317 additions and 118 deletions

View file

@ -110,42 +110,49 @@ var BatchTexturedTintedRawQuads = new Class({
type: gl.UNSIGNED_BYTE,
normalized: true
},
{
name: 'inMatrix',
name: 'inObjectMatrixABCD',
location: -1,
size: 4,
columns: 4,
type: gl.FLOAT,
normalized: false
},
{
name: 'inObjectMatrixXY',
location: -1,
size: 2,
type: gl.FLOAT,
normalized: false
},
{
name: 'inWorldMatrixABCD',
location: -1,
size: 4,
type: gl.FLOAT,
normalized: false
},
{
name: 'inWorldMatrixXY',
location: -1,
size: 2,
type: gl.FLOAT,
normalized: false
},
{
name: 'inViewMatrixABCD',
location: -1,
size: 4,
type: gl.FLOAT,
normalized: false
},
{
name: 'inViewMatrixXY',
location: -1,
size: 2,
type: gl.FLOAT,
normalized: false
}
// {
// name: 'inObjectMatrix',
// location: -1,
// size: 4,
// columns: 4,
// type: gl.FLOAT,
// normalized: false,
// offset: 10 * bytesPerElement
// },
// {
// name: 'inWorldMatrix',
// location: -1,
// size: 4,
// columns: 4,
// type: gl.FLOAT,
// normalized: false,
// offset: 26 * bytesPerElement
// },
// {
// name: 'inViewMatrix',
// location: -1,
// size: 4,
// columns: 4,
// type: gl.FLOAT,
// normalized: false,
// offset: 42 * bytesPerElement
// }
]
};
@ -358,7 +365,9 @@ var BatchTexturedTintedRawQuads = new Class({
* @param {Phaser.Cameras.Scene2D.Camera} camera - The camera to render to.
* @param {Phaser.Textures.Frame} frame - The texture frame to render.
* @param {boolean} tintFill - Whether to tint the fill color.
* @param {Float32Array} matrix - The matrix to transform the quad.
* @param {Phaser.GameObjects.Components.TransformMatrix} objectMatrix - The matrix to transform the base quad into the object space.
* @param {Phaser.GameObjects.Components.TransformMatrix} worldMatrix - The matrix to transform the object space quad into the world space.
* @param {Phaser.GameObjects.Components.TransformMatrix} viewMatrix - The matrix to transform the world space quad into the view space.
* @param {number} texX - The left u coordinate (0-1).
* @param {number} texY - The top v coordinate (0-1).
* @param {number} texWidth - The width of the texture (0-1).
@ -368,7 +377,7 @@ var BatchTexturedTintedRawQuads = new Class({
* @param {number} tintTR - The top-right tint color.
* @param {number} tintBR - The bottom-right tint color.
*/
batch: function (currentContext, camera, frame, tintFill, matrix, texX, texY, texWidth, texHeight, tintTL, tintBL, tintTR, tintBR)
batch: function (currentContext, camera, frame, tintFill, objectMatrix, worldMatrix, viewMatrix, texX, texY, texWidth, texHeight, tintTL, tintBL, tintTR, tintBR)
{
this.manager.setCurrentBatchNode(this, currentContext, camera);
@ -377,12 +386,6 @@ var BatchTexturedTintedRawQuads = new Class({
var quadViewU32 = this._quadViewU32;
// TODO: Simplify matrix handling.
var mat4 = [
matrix[0], matrix[1], 0, 0,
matrix[2], matrix[3], 0, 0,
0, 0, 1, 0,
matrix[4], matrix[5], 0, 1
];
// Texture
var glTexture = frame.glTexture;
@ -404,7 +407,9 @@ var BatchTexturedTintedRawQuads = new Class({
quadViewU32[quadOffset32 + 7] = tintBL;
quadViewU32[quadOffset32 + 8] = tintTR;
quadViewU32[quadOffset32 + 9] = tintBR;
quadViewF32.set(mat4, quadOffset32 + 10);
quadViewF32.set(objectMatrix.matrix.subarray(0, 6), quadOffset32 + 10);
quadViewF32.set(worldMatrix.matrix.subarray(0, 6), quadOffset32 + 16);
quadViewF32.set(viewMatrix.matrix.subarray(0, 6), quadOffset32 + 22);
// Increment the instance count.
this.instanceCount++;

View file

@ -0,0 +1,203 @@
/**
* @author Benjamin D. Richards <benjamindrichards@gmail.com>
* @copyright 2013-2024 Phaser Studio Inc.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
var TransformMatrix = require('../../../gameobjects/components/TransformMatrix.js');
var Class = require('../../../utils/Class.js');
var RenderNode = require('./RenderNode.js');
/**
* @classdesc
* A RenderNode which computes 2D matrix transforms for a quad.
*
* The three matrices returned are:
*
* - objectMatrix: The matrix used to transform the object from a 1x1 quad to its screen region.
* - worldMatrix: The matrix used to transform the object from its local space to world space.
* - viewMatrix: The matrix used to transform the object from world space to camera space.
*
* @class GetSBRQuadMatrices
* @memberof Phaser.Renderer.WebGL.RenderNodes
* @constructor
* @since 3.90.0
* @extends Phaser.Renderer.WebGL.RenderNodes.RenderNode
* @param {Phaser.Renderer.WebGL.RenderNodes.RenderNodeManager} manager - The manager that owns this RenderNode.
* @param {Phaser.Renderer.WebGL.WebGLRenderer} renderer - The renderer that owns this RenderNode.
*/
var GetSBRQuadMatrices = new Class({
Extends: RenderNode,
initialize: function GetSBRQuadMatrices (manager, renderer)
{
RenderNode.call(this, 'GetSBRQuadMatrices', manager, renderer);
/**
* The matrix used internally to compute camera transforms.
*
* @name Phaser.Renderer.WebGL.RenderNodes.Single#_camMatrix
* @type {Phaser.GameObjects.Components.TransformMatrix}
* @since 3.90.0
* @private
*/
this._camMatrix = new TransformMatrix();
/**
* The matrix used internally to compute sprite transforms.
*
* @name Phaser.Renderer.WebGL.RenderNodes.Single#_objectMatrix
* @type {Phaser.GameObjects.Components.TransformMatrix}
* @since 3.90.0
* @private
*/
this._objectMatrix = new TransformMatrix();
/**
* The matrix used internally to compute the final transform.
*
* @name Phaser.Renderer.WebGL.RenderNodes.Single#_worldMatrix
* @type {Phaser.GameObjects.Components.TransformMatrix}
* @since 3.90.0
* @private
*/
this._worldMatrix = new TransformMatrix();
/**
* The matrices computed by this node. This is a reference to
* the internal matrices. It is the return value of the run method.
*
* @name Phaser.Renderer.WebGL.RenderNodes.Single#_matrices
* @type {{
* objectMatrix: Phaser.GameObjects.Components.TransformMatrix,
* worldMatrix: Phaser.GameObjects.Components.TransformMatrix,
* camMatrix: Phaser.GameObjects.Components.TransformMatrix
* }}
* @since 3.90.0
* @private
*/
this._matrices = {
objectMatrix: this._objectMatrix,
worldMatrix: this._worldMatrix,
camMatrix: this._camMatrix
};
},
/**
* Compute the 2D matrix transforms for a quad.
*
* The return value is an object held by this node,
* so be sure to copy it if you need it later.
*
* @method Phaser.Renderer.WebGL.RenderNodes.GetSBRQuadMatrices#run
* @since 3.90.0
* @param {Phaser.Cameras.Scene2D.Camera} camera - The camera to use for the transformation.
* @param {Phaser.GameObjects.GameObject} gameObject - The game object to transform.
* @param {Phaser.GameObjects.Components.TransformMatrix} [parentTransformMatrix] - The parent matrix to apply, if any.
* @return {{
* objectMatrix: Phaser.GameObjects.Components.TransformMatrix,
* worldMatrix: Phaser.GameObjects.Components.TransformMatrix,
* camMatrix: Phaser.GameObjects.Components.TransformMatrix
* }} The computed transform matrices.
*/
run: function (gameObject, camera, parentTransformMatrix)
{
var camMatrix = this._camMatrix;
var objectMatrix = this._objectMatrix;
var worldMatrix = this._worldMatrix;
var frame = gameObject.frame;
var frameX = frame.x;
var frameY = frame.y;
var frameWidth = frame.cutWidth;
var frameHeight = frame.cutHeight;
var customPivot = frame.customPivot;
var displayOriginX = gameObject.displayOriginX;
var displayOriginY = gameObject.displayOriginY;
if (gameObject.isCropped)
{
var crop = gameObject._crop;
frameWidth = crop.width;
frameHeight = crop.height;
frameX = crop.x;
frameY = crop.y;
}
var x = -displayOriginX + frameX;
var y = -displayOriginY + frameY;
var flipX = 1;
var flipY = 1;
if (gameObject.flipX)
{
if (!customPivot)
{
x += (-frame.realWidth + (displayOriginX * 2));
}
flipX = -1;
}
if (gameObject.flipY)
{
if (!customPivot)
{
y += (-frame.realHeight + (displayOriginY * 2));
}
flipY = -1;
}
var gx = gameObject.x;
var gy = gameObject.y;
objectMatrix.applyITRS(
x,
y,
0,
frameWidth,
frameHeight
);
worldMatrix.applyITRS(
gx,
gy,
gameObject.rotation,
gameObject.scaleX * flipX,
gameObject.scaleY * flipY
);
if (parentTransformMatrix)
{
// Multiply the camera by the parent matrix
camMatrix.copyFrom(camera.matrix);
camMatrix.multiplyWithOffset(parentTransformMatrix, -camera.scrollX * gameObject.scrollFactorX, -camera.scrollY * gameObject.scrollFactorY);
// Undo the camera scroll
worldMatrix.e = gx;
worldMatrix.f = gy;
return this._matrices;
}
else
{
// camMatrix will not be mutated after this point, so we just take a reference.
camMatrix = camera.matrix;
worldMatrix.e -= camera.scrollX * gameObject.scrollFactorX;
worldMatrix.f -= camera.scrollY * gameObject.scrollFactorY;
return {
objectMatrix: objectMatrix,
worldMatrix: worldMatrix,
camMatrix: camMatrix
};
}
}
});
module.exports = GetSBRQuadMatrices;

View file

@ -44,16 +44,18 @@ var ImageQuadrangulateBatch = new Class({
var tintBL = Utils.getTintAppendFloatAlpha(gameObject.tintBottomLeft, camera.alpha * gameObject._alphaBL);
var tintBR = Utils.getTintAppendFloatAlpha(gameObject.tintBottomRight, camera.alpha * gameObject._alphaBR);
// Render with matrix
// Render with separate matrices.
var matrix = this.manager.nodes.GetQuadTransform.run(gameObject, camera, parentMatrix);
var matrices = this.manager.nodes.GetSBRQuadMatrices.run(gameObject, camera, parentMatrix);
this.manager.nodes.BatchTexturedTintedRawQuads.batch(
drawingContext,
camera,
frame,
gameObject.tintFill,
matrix.matrix,
matrices.objectMatrix,
matrices.worldMatrix,
matrices.camMatrix,
// Texture coordinates in X, Y, Width, Height:
u0, v0, u1 - u0, v1 - v0,
@ -62,26 +64,6 @@ var ImageQuadrangulateBatch = new Class({
tintTL, tintTR, tintBL, tintBR
);
// // Render with separate matrices.
// var matrices = this.manager.nodes.GetSBRQuadMatrices.run(gameObject, camera, parentMatrix);
// this.manager.nodes.BatchTexturedTintedRawQuads.batch(
// drawingContext,
// camera,
// frame,
// gameObject.tintFill,
// matrices.objectMatrix,
// matrices.worldMatrix,
// matrices.camMatrix,
// // Texture coordinates in X, Y, Width, Height:
// u0, v0, u1 - u0, v1 - v0,
// // Tint colors in TRIANGLE_STRIP order:
// tintTL, tintTR, tintBL, tintBR
// );
return;
}
});

View file

@ -8,6 +8,7 @@ var Class = require('../../../utils/Class');
var BatchTexturedTintedRawQuads = require('./BatchTexturedTintedRawQuads');
var Camera = require('./Camera');
var GetQuadTransform = require('./GetQuadTransform');
var GetSBRQuadMatrices = require('./GetSBRQuadMatrices');
var ImageQuadrangulateBatch = require('./ImageQuadrangulateBatch');
var ListCompositor = require('./ListCompositor');
@ -50,6 +51,7 @@ var RenderNodeManager = new Class({
BatchTexturedTintedRawQuads: new BatchTexturedTintedRawQuads(this, renderer),
Camera: new Camera(this, renderer),
GetQuadTransform: new GetQuadTransform(this, renderer),
GetSBRQuadMatrices: new GetSBRQuadMatrices(this, renderer),
ImageQuadrangulateBatch: new ImageQuadrangulateBatch(this, renderer),
ListCompositor: new ListCompositor(this, renderer),
};

View file

@ -1,41 +1,29 @@
module.exports = [
'#define SHADER_NAME PHASER_BATCH_QUAD_FS',
'',
'#ifdef GL_FRAGMENT_PRECISION_HIGH',
'precision highp float;',
'#else',
'precision mediump float;',
'#endif',
'',
'uniform sampler2D uMainSampler[%count%];',
'',
'varying vec2 outTexCoord;',
'varying float outTexId;',
'varying float outTintEffect;',
'varying vec4 outTint;',
'',
'void main ()',
'{',
' vec4 texture;',
'',
' %forloop%',
'',
' vec4 texel = vec4(outTint.bgr * outTint.a, outTint.a);',
'',
' // Multiply texture tint',
' vec4 color = texture * texel;',
'',
' if (outTintEffect == 1.0)',
' {',
' // Solid color + texture alpha',
' color.rgb = mix(texture.rgb, outTint.bgr * outTint.a, texture.a);',
' }',
' else if (outTintEffect == 2.0)',
' {',
' // Solid color, no texture',
' color = texel;',
' }',
'',
' gl_FragColor = color;',
'}',
'#define SHADER_NAME PHASER_BATCH_QUAD_FS',
'#ifdef GL_FRAGMENT_PRECISION_HIGH',
'precision highp float;',
'#else',
'precision mediump float;',
'#endif',
'uniform sampler2D uMainSampler[%count%];',
'varying vec2 outTexCoord;',
'varying float outTexId;',
'varying float outTintEffect;',
'varying vec4 outTint;',
'void main ()',
'{',
' vec4 texture;',
' %forloop%',
' vec4 texel = vec4(outTint.bgr * outTint.a, outTint.a);',
' vec4 color = texture * texel;',
' if (outTintEffect == 1.0)',
' {',
' color.rgb = mix(texture.rgb, outTint.bgr * outTint.a, texture.a);',
' }',
' else if (outTintEffect == 2.0)',
' {',
' color = texel;',
' }',
' gl_FragColor = color;',
'}',
].join('\n');

View file

@ -1,42 +1,45 @@
module.exports = [
'#define SHADER_NAME PHASER_BATCH_QUAD_VS',
'',
'precision mediump float;',
'',
'uniform mat4 uProjectionMatrix;',
'uniform int uRoundPixels;',
'uniform vec2 uResolution;',
'',
'attribute vec2 inTexIdAndTintEffect;',
'attribute vec4 inTextureBox;',
'attribute vec4 inTintTL;',
'attribute vec4 inTintBL;',
'attribute vec4 inTintTR;',
'attribute vec4 inTintBR;',
'attribute mat4 inMatrix;',
'attribute vec4 inObjectMatrixABCD;',
'attribute vec2 inObjectMatrixXY;',
'attribute vec4 inWorldMatrixABCD;',
'attribute vec2 inWorldMatrixXY;',
'attribute vec4 inViewMatrixABCD;',
'attribute vec2 inViewMatrixXY;',
'attribute vec3 inPositionAndIndex;',
'',
'varying vec2 outTexCoord;',
'varying float outTexId;',
'varying float outTintEffect;',
'varying vec4 outTint;',
'',
'mat4 assembleMatrix4 (vec4 abcd, vec2 xy)',
'{',
' return mat4(abcd.xy, 0, 0, abcd.zw, 0, 0, 0, 0, 1, 0, xy.xy, 0, 1);',
'}',
'void main ()',
'{',
' vec2 position = inPositionAndIndex.xy;',
' float index = inPositionAndIndex.z;',
'',
' gl_Position = uProjectionMatrix * inMatrix * vec4(position, 1.0, 1.0);',
' mat4 objectMatrix = assembleMatrix4(inObjectMatrixABCD, inObjectMatrixXY);',
' mat4 worldMatrix = assembleMatrix4(inWorldMatrixABCD, inWorldMatrixXY);',
' mat4 viewMatrix = assembleMatrix4(inViewMatrixABCD, inViewMatrixXY);',
' gl_Position = uProjectionMatrix * viewMatrix * worldMatrix * objectMatrix * vec4(position, 1.0, 1.0);',
' if (uRoundPixels == 1)',
' {',
' gl_Position.xy = floor(((gl_Position.xy + 1.0) * 0.5 * uResolution) + 0.5) / uResolution * 2.0 - 1.0;',
' }',
'',
' outTexCoord = position * inTextureBox.pq + inTextureBox.st;',
' outTexId = inTexIdAndTintEffect.x;',
' outTintEffect = inTexIdAndTintEffect.y;',
'',
' // Which corner are we?',
' if (index == 0.0)',
' {',
' outTint = inTintTL;',
@ -53,5 +56,5 @@ module.exports = [
' {',
' outTint = inTintBR;',
' }',
' }',
'}',
].join('\n');

View file

@ -1,6 +1,6 @@
/**
* @author Richard Davey <rich@phaser.io>
* @copyright 2013-2024 Phaser Studio Inc.
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2013-2023 Photon Storm Ltd.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
@ -11,6 +11,8 @@
module.exports = {
AddBlendFrag: require('./AddBlend-frag.js'),
BatchQuadFrag: require('./BatchQuad-frag.js'),
BatchQuadVert: require('./BatchQuad-vert.js'),
BitmapMaskFrag: require('./BitmapMask-frag.js'),
BitmapMaskVert: require('./BitmapMask-vert.js'),
ColorMatrixFrag: require('./ColorMatrix-frag.js'),

View file

@ -1,4 +1,4 @@
#define SHADER_NAME PHASER_MULTI_FS
#define SHADER_NAME PHASER_BATCH_QUAD_FS
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;

View file

@ -12,7 +12,12 @@ attribute vec4 inTintTL;
attribute vec4 inTintBL;
attribute vec4 inTintTR;
attribute vec4 inTintBR;
attribute mat4 inMatrix;
attribute vec4 inObjectMatrixABCD;
attribute vec2 inObjectMatrixXY;
attribute vec4 inWorldMatrixABCD;
attribute vec2 inWorldMatrixXY;
attribute vec4 inViewMatrixABCD;
attribute vec2 inViewMatrixXY;
attribute vec3 inPositionAndIndex;
varying vec2 outTexCoord;
@ -20,12 +25,21 @@ varying float outTexId;
varying float outTintEffect;
varying vec4 outTint;
mat4 assembleMatrix4 (vec4 abcd, vec2 xy)
{
return mat4(abcd.xy, 0, 0, abcd.zw, 0, 0, 0, 0, 1, 0, xy.xy, 0, 1);
}
void main ()
{
vec2 position = inPositionAndIndex.xy;
float index = inPositionAndIndex.z;
gl_Position = uProjectionMatrix * inMatrix * vec4(position, 1.0, 1.0);
mat4 objectMatrix = assembleMatrix4(inObjectMatrixABCD, inObjectMatrixXY);
mat4 worldMatrix = assembleMatrix4(inWorldMatrixABCD, inWorldMatrixXY);
mat4 viewMatrix = assembleMatrix4(inViewMatrixABCD, inViewMatrixXY);
gl_Position = uProjectionMatrix * viewMatrix * worldMatrix * objectMatrix * vec4(position, 1.0, 1.0);
if (uRoundPixels == 1)
{