mirror of
https://github.com/photonstorm/phaser
synced 2024-11-10 07:04:31 +00:00
Add lighting and self-shadowing to TileSprite.
This commit is contained in:
parent
cf7e46eff7
commit
de036b999f
16 changed files with 1007 additions and 4 deletions
|
@ -49,6 +49,7 @@ var _FLAG = 8; // 1000
|
|||
* @extends Phaser.GameObjects.Components.Depth
|
||||
* @extends Phaser.GameObjects.Components.Flip
|
||||
* @extends Phaser.GameObjects.Components.GetBounds
|
||||
* @extends Phaser.GameObjects.Components.Lighting
|
||||
* @extends Phaser.GameObjects.Components.Mask
|
||||
* @extends Phaser.GameObjects.Components.Origin
|
||||
* @extends Phaser.GameObjects.Components.PostPipeline
|
||||
|
@ -79,6 +80,7 @@ var TileSprite = new Class({
|
|||
Components.Depth,
|
||||
Components.Flip,
|
||||
Components.GetBounds,
|
||||
Components.Lighting,
|
||||
Components.Mask,
|
||||
Components.Origin,
|
||||
Components.PostPipeline,
|
||||
|
|
|
@ -83,7 +83,7 @@ var BatchHandlerQuadLightShadow = new Class({
|
|||
* @readonly
|
||||
*/
|
||||
defaultConfig: {
|
||||
name: 'BatchHandlerQuadLight',
|
||||
name: 'BatchHandlerQuadLightShadow',
|
||||
verticesPerInstance: 4,
|
||||
indicesPerInstance: 6,
|
||||
vertexSource: ShaderSourceVS,
|
||||
|
|
|
@ -71,6 +71,33 @@ var BatchHandlerTileSprite = new Class({
|
|||
*
|
||||
* @method Phaser.Renderer.WebGL.RenderNodes.BatchHandlerTileSprite#batch
|
||||
* @since 3.90.0
|
||||
* @param {Phaser.Renderer.WebGL.DrawingContext} currentContext - The current drawing context.
|
||||
* @param {Phaser.Renderer.WebGL.WebGLTextureWrapper} glTexture - The texture to render.
|
||||
* @param {number} x0 - The x-coordinate of the top-left corner.
|
||||
* @param {number} y0 - The y-coordinate of the top-left corner.
|
||||
* @param {number} x1 - The x-coordinate of the bottom-left corner.
|
||||
* @param {number} y1 - The y-coordinate of the bottom-left corner.
|
||||
* @param {number} x2 - The x-coordinate of the top-right corner.
|
||||
* @param {number} y2 - The y-coordinate of the top-right corner.
|
||||
* @param {number} x3 - The x-coordinate of the bottom-right corner.
|
||||
* @param {number} y3 - The y-coordinate of the bottom-right corner.
|
||||
* @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).
|
||||
* @param {number} texHeight - The height of the texture (0-1).
|
||||
* @param {number} u0 - The u coordinate of the distorted top-left corner.
|
||||
* @param {number} v0 - The v coordinate of the distorted top-left corner.
|
||||
* @param {number} u1 - The u coordinate of the distorted bottom-left corner.
|
||||
* @param {number} v1 - The v coordinate of the distorted bottom-left corner.
|
||||
* @param {number} u2 - The u coordinate of the distorted top-right corner.
|
||||
* @param {number} v2 - The v coordinate of the distorted top-right corner.
|
||||
* @param {number} u3 - The u coordinate of the distorted bottom-right corner.
|
||||
* @param {number} v3 - The v coordinate of the distorted bottom-right corner.
|
||||
* @param {number} tintFill - Whether to tint the fill color.
|
||||
* @param {number} tintTL - The tint color for the top-left corner.
|
||||
* @param {number} tintBL - The tint color for the bottom-left corner.
|
||||
* @param {number} tintTR - The tint color for the top-right corner.
|
||||
* @param {number} tintBR - The tint color for the bottom-right corner.
|
||||
*/
|
||||
batch: function (
|
||||
currentContext,
|
||||
|
|
322
src/renderer/webgl/renderNodes/BatchHandlerTileSpriteLight.js
Normal file
322
src/renderer/webgl/renderNodes/BatchHandlerTileSpriteLight.js
Normal file
|
@ -0,0 +1,322 @@
|
|||
/**
|
||||
* @author Benjamin D. Richards <benjamindrichards@gmail.com>
|
||||
* @copyright 2013-2024 Phaser Studio Inc.
|
||||
* @license {@link https://opensource.org/licenses/MIT|MIT License}
|
||||
*/
|
||||
|
||||
var Vector2 = require('../../../math/Vector2');
|
||||
var Class = require('../../../utils/Class');
|
||||
var LightShaderSourceFS = require('../shaders/TileSpriteLight-frag');
|
||||
var ShaderSourceVS = require('../shaders/MultiTileSprite-vert');
|
||||
var BatchHandlerQuadLight = require('./BatchHandlerQuadLight');
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* This RenderNode draws Standard Batch Render Quads with a Light Shader
|
||||
* in batches.
|
||||
*
|
||||
* The fragment shader used by this RenderNode will be compiled
|
||||
* with a maximum light count defined by the renderer configuration.
|
||||
* The string `%LIGHT_COUNT%` in the fragment shader source will be
|
||||
* replaced with this value.
|
||||
*
|
||||
* @class BatchHandlerTileSpriteLight
|
||||
* @memberof Phaser.Renderer.WebGL.RenderNodes
|
||||
* @constructor
|
||||
* @since 3.90.0
|
||||
* @extends Phaser.Renderer.WebGL.RenderNodes.BatchHandlerQuadLight
|
||||
* @param {Phaser.Renderer.WebGL.RenderNodes.RenderNodeManager} manager - The manager that owns this RenderNode.
|
||||
* @param {Phaser.Types.Renderer.WebGL.RenderNodes.BatchHandlerConfig} config - The configuration object for this RenderNode.
|
||||
*/
|
||||
var BatchHandlerTileSpriteLight = new Class({
|
||||
Extends: BatchHandlerQuadLight,
|
||||
|
||||
initialize: function BatchHandlerTileSpriteLight (manager, config)
|
||||
{
|
||||
BatchHandlerQuadLight.call(this, manager, config);
|
||||
|
||||
this.program.setUniform('uMainSampler', 0);
|
||||
this.program.setUniform('uNormSampler', 1);
|
||||
|
||||
/**
|
||||
* Inverse rotation matrix for normal map rotations.
|
||||
*
|
||||
* @name Phaser.Renderer.WebGL.RenderNodes.BatchHandlerTileSpriteLight#inverseRotationMatrix
|
||||
* @type {Float32Array}
|
||||
* @private
|
||||
* @since 3.90.0
|
||||
*/
|
||||
this.inverseRotationMatrix = new Float32Array([
|
||||
1, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 1
|
||||
]);
|
||||
|
||||
/**
|
||||
* A persistent calculation vector used when processing the lights.
|
||||
*
|
||||
* @name Phaser.Renderer.WebGL.RenderNodes.BatchHandlerTileSpriteLight#_lightVector
|
||||
* @type {Phaser.Math.Vector2}
|
||||
* @private
|
||||
* @since 3.90.0
|
||||
*/
|
||||
this._lightVector = new Vector2();
|
||||
|
||||
/**
|
||||
* The rotation of the normal map texture.
|
||||
*
|
||||
* @name Phaser.Renderer.WebGL.RenderNodes.BatchHandlerTileSpriteLight#_normalMapRotation
|
||||
* @type {number}
|
||||
* @private
|
||||
* @since 3.90.0
|
||||
*/
|
||||
this._normalMapRotation = 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* The default configuration settings for BatchHandlerTileSpriteLight.
|
||||
*
|
||||
* These are very similar to standard settings,
|
||||
* but because the textures are always set in units 0 and 1,
|
||||
* there's no need to have an attribute for the texture unit.
|
||||
* While the vertex shader still reads `inTexId`, it is not used,
|
||||
* and the default value of 0 is fine.
|
||||
*
|
||||
* @name Phaser.Renderer.WebGL.RenderNodes.BatchHandlerTileSpriteLight#defaultConfig
|
||||
* @type {Phaser.Types.Renderer.WebGL.RenderNodes.BatchHandlerConfig}
|
||||
* @since 3.90.0
|
||||
* @readonly
|
||||
*/
|
||||
defaultConfig: {
|
||||
name: 'BatchHandlerTileSpriteLight',
|
||||
verticesPerInstance: 4,
|
||||
indicesPerInstance: 6,
|
||||
vertexSource: ShaderSourceVS,
|
||||
fragmentSource: LightShaderSourceFS,
|
||||
vertexBufferLayout: {
|
||||
usage: 'DYNAMIC_DRAW',
|
||||
layout: [
|
||||
{
|
||||
name: 'inPosition',
|
||||
size: 2
|
||||
},
|
||||
{
|
||||
name: 'inTexCoord',
|
||||
size: 2
|
||||
},
|
||||
{
|
||||
name: 'inFrame',
|
||||
size: 4
|
||||
},
|
||||
{
|
||||
name: 'inTintEffect'
|
||||
},
|
||||
{
|
||||
name: 'inTint',
|
||||
size: 4,
|
||||
type: 'UNSIGNED_BYTE',
|
||||
normalized: true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a new quad to the batch.
|
||||
*
|
||||
* For compatibility with TRIANGLE_STRIP rendering,
|
||||
* the vertices are added in the order:
|
||||
*
|
||||
* - Top-left
|
||||
* - Bottom-left
|
||||
* - Top-right
|
||||
* - Bottom-right
|
||||
*
|
||||
* @method Phaser.Renderer.WebGL.RenderNodes.BatchHandlerTileSpriteLight#batch
|
||||
* @since 3.90.0
|
||||
* @param {Phaser.Types.Renderer.WebGL.DrawingContext} currentContext - The current drawing context.
|
||||
* @param {Phaser.Renderer.WebGL.WebGLTextureWrapper} glTexture - The texture to render.
|
||||
* @param {Phaser.Renderer.WebGL.WebGLTextureWrapper} normalGLTexture - The normal map texture to render.
|
||||
* @param {number} normalMapRotation - The rotation of the normal map texture.
|
||||
* @param {number} x0 - The x coordinate of the top-left corner.
|
||||
* @param {number} y0 - The y coordinate of the top-left corner.
|
||||
* @param {number} x1 - The x coordinate of the bottom-left corner.
|
||||
* @param {number} y1 - The y coordinate of the bottom-left corner.
|
||||
* @param {number} x2 - The x coordinate of the top-right corner.
|
||||
* @param {number} y2 - The y coordinate of the top-right corner.
|
||||
* @param {number} x3 - The x coordinate of the bottom-right corner.
|
||||
* @param {number} y3 - The y coordinate of the bottom-right corner.
|
||||
* @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).
|
||||
* @param {number} texHeight - The height of the texture (0-1).
|
||||
* @param {number} u0 - The u coordinate of the distorted top-left corner.
|
||||
* @param {number} v0 - The v coordinate of the distorted top-left corner.
|
||||
* @param {number} u1 - The u coordinate of the distorted bottom-left corner.
|
||||
* @param {number} v1 - The v coordinate of the distorted bottom-left corner.
|
||||
* @param {number} u2 - The u coordinate of the distorted top-right corner.
|
||||
* @param {number} v2 - The v coordinate of the distorted top-right corner.
|
||||
* @param {number} u3 - The u coordinate of the distorted bottom-right corner.
|
||||
* @param {number} v3 - The v coordinate of the distorted bottom-right corner.
|
||||
* @param {number} tintFill - Whether to tint the fill color.
|
||||
* @param {number} tintTL - The top-left tint color.
|
||||
* @param {number} tintBL - The bottom-left tint color.
|
||||
* @param {number} tintTR - The top-right tint color.
|
||||
* @param {number} tintBR - The bottom-right tint color.
|
||||
*/
|
||||
batch: function (
|
||||
currentContext,
|
||||
glTexture,
|
||||
normalGLTexture,
|
||||
normalMapRotation,
|
||||
x0, y0,
|
||||
x1, y1,
|
||||
x2, y2,
|
||||
x3, y3,
|
||||
texX, texY,
|
||||
texWidth, texHeight,
|
||||
u0, v0,
|
||||
u1, v1,
|
||||
u2, v2,
|
||||
u3, v3,
|
||||
tintFill,
|
||||
tintTL, tintBL, tintTR, tintBR
|
||||
)
|
||||
{
|
||||
if (this.instanceCount === 0)
|
||||
{
|
||||
this.manager.setCurrentBatchNode(this, currentContext);
|
||||
}
|
||||
|
||||
// Texture
|
||||
|
||||
var currentBatchEntry = this.currentBatchEntry;
|
||||
if (
|
||||
currentBatchEntry.texture[0] !== glTexture ||
|
||||
currentBatchEntry.texture[1] !== normalGLTexture
|
||||
)
|
||||
{
|
||||
// Complete the entire batch if the texture changes.
|
||||
this.run(currentContext);
|
||||
}
|
||||
|
||||
// Current batch entry has been redefined.
|
||||
currentBatchEntry = this.currentBatchEntry;
|
||||
glTexture.batchUnit = 0;
|
||||
normalGLTexture.batchUnit = 1;
|
||||
currentBatchEntry.texture[0] = glTexture;
|
||||
currentBatchEntry.texture[1] = normalGLTexture;
|
||||
currentBatchEntry.unit = 2;
|
||||
|
||||
// Normal map rotation
|
||||
if (this._normalMapRotation !== normalMapRotation)
|
||||
{
|
||||
// Complete the entire batch if the normal map rotation changes.
|
||||
this.run(currentContext);
|
||||
|
||||
this._normalMapRotation = normalMapRotation;
|
||||
var inverseRotationMatrix = this.inverseRotationMatrix;
|
||||
|
||||
if (normalMapRotation)
|
||||
{
|
||||
var rot = -normalMapRotation;
|
||||
var c = Math.cos(rot);
|
||||
var s = Math.sin(rot);
|
||||
|
||||
inverseRotationMatrix[1] = s;
|
||||
inverseRotationMatrix[3] = -s;
|
||||
inverseRotationMatrix[0] = inverseRotationMatrix[4] = c;
|
||||
}
|
||||
else
|
||||
{
|
||||
inverseRotationMatrix[0] = inverseRotationMatrix[4] = 1;
|
||||
inverseRotationMatrix[1] = inverseRotationMatrix[3] = 0;
|
||||
}
|
||||
|
||||
// This matrix will definitely be used by the next render.
|
||||
this.program.setUniform('uInverseRotationMatrix', inverseRotationMatrix);
|
||||
}
|
||||
|
||||
// Update the vertex buffer.
|
||||
var vertexOffset32 = this.instanceCount * this.floatsPerInstance;
|
||||
var vertexBuffer = this.vertexBufferLayout.buffer;
|
||||
var vertexViewF32 = vertexBuffer.viewF32;
|
||||
var vertexViewU32 = vertexBuffer.viewU32;
|
||||
|
||||
// Bottom-left
|
||||
vertexViewF32[vertexOffset32++] = x1;
|
||||
vertexViewF32[vertexOffset32++] = y1;
|
||||
vertexViewF32[vertexOffset32++] = u1;
|
||||
vertexViewF32[vertexOffset32++] = v1;
|
||||
vertexViewF32[vertexOffset32++] = texX;
|
||||
vertexViewF32[vertexOffset32++] = texY;
|
||||
vertexViewF32[vertexOffset32++] = texWidth;
|
||||
vertexViewF32[vertexOffset32++] = texHeight;
|
||||
vertexViewF32[vertexOffset32++] = tintFill;
|
||||
vertexViewU32[vertexOffset32++] = tintBL;
|
||||
|
||||
// Top-left
|
||||
vertexViewF32[vertexOffset32++] = x0;
|
||||
vertexViewF32[vertexOffset32++] = y0;
|
||||
vertexViewF32[vertexOffset32++] = u0;
|
||||
vertexViewF32[vertexOffset32++] = v0;
|
||||
vertexViewF32[vertexOffset32++] = texX;
|
||||
vertexViewF32[vertexOffset32++] = texY;
|
||||
vertexViewF32[vertexOffset32++] = texWidth;
|
||||
vertexViewF32[vertexOffset32++] = texHeight;
|
||||
vertexViewF32[vertexOffset32++] = tintFill;
|
||||
vertexViewU32[vertexOffset32++] = tintTL;
|
||||
|
||||
// Bottom-right
|
||||
vertexViewF32[vertexOffset32++] = x3;
|
||||
vertexViewF32[vertexOffset32++] = y3;
|
||||
vertexViewF32[vertexOffset32++] = u3;
|
||||
vertexViewF32[vertexOffset32++] = v3;
|
||||
vertexViewF32[vertexOffset32++] = texX;
|
||||
vertexViewF32[vertexOffset32++] = texY;
|
||||
vertexViewF32[vertexOffset32++] = texWidth;
|
||||
vertexViewF32[vertexOffset32++] = texHeight;
|
||||
vertexViewF32[vertexOffset32++] = tintFill;
|
||||
vertexViewU32[vertexOffset32++] = tintBR;
|
||||
|
||||
// Top-right
|
||||
vertexViewF32[vertexOffset32++] = x2;
|
||||
vertexViewF32[vertexOffset32++] = y2;
|
||||
vertexViewF32[vertexOffset32++] = u2;
|
||||
vertexViewF32[vertexOffset32++] = v2;
|
||||
vertexViewF32[vertexOffset32++] = texX;
|
||||
vertexViewF32[vertexOffset32++] = texY;
|
||||
vertexViewF32[vertexOffset32++] = texWidth;
|
||||
vertexViewF32[vertexOffset32++] = texHeight;
|
||||
vertexViewF32[vertexOffset32++] = tintFill;
|
||||
vertexViewU32[vertexOffset32++] = tintTR;
|
||||
|
||||
// Increment the instance count.
|
||||
this.instanceCount++;
|
||||
this.currentBatchEntry.count++;
|
||||
|
||||
// Check whether the batch should be rendered immediately.
|
||||
// This guarantees that none of the arrays are full above.
|
||||
if (this.instanceCount === this.instancesPerBatch)
|
||||
{
|
||||
this.run(currentContext);
|
||||
|
||||
// Now the batch is empty.
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Called by the render node manager when the advised texture unit count changes.
|
||||
* In `BatchHandlerTileSpriteLight`, this does nothing, because it only ever uses two texture units.
|
||||
*
|
||||
* As this extends `BatchHandlerQuad`, it would otherwise rebuild the shader
|
||||
* program.
|
||||
*
|
||||
* @method Phaser.Renderer.WebGL.RenderNodes.BatchHandlerTileSpriteLight#updateTextureCount
|
||||
* @since 3.90.0
|
||||
* @param {number} count - The new advised texture unit count.
|
||||
*/
|
||||
updateTextureCount: function (count) {}
|
||||
});
|
||||
|
||||
module.exports = BatchHandlerTileSpriteLight;
|
|
@ -0,0 +1,129 @@
|
|||
/**
|
||||
* @author Benjamin D. Richards <benjamindrichards@gmail.com>
|
||||
* @copyright 2013-2024 Phaser Studio Inc.
|
||||
* @license {@link https://opensource.org/licenses/MIT|MIT License}
|
||||
*/
|
||||
|
||||
var Class = require('../../../utils/Class');
|
||||
var LightShaderSourceFS = require('../shaders/TileSpriteLightShadow-frag');
|
||||
var ShaderSourceVS = require('../shaders/MultiTileSprite-vert');
|
||||
var BatchHandlerTileSpriteLight = require('./BatchHandlerTileSpriteLight');
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* The BatchHandlerTileSpriteLightShadow works like
|
||||
* @see Phaser.Renderer.WebGL.RenderNodes.BatchHandlerTileSpriteLight
|
||||
* to render TileSprite GameObjects with self-shadowing lighting.
|
||||
*
|
||||
* @class BatchHandlerTileSpriteLightShadow
|
||||
* @extends Phaser.Renderer.WebGL.RenderNodes.BatchHandlerQuadLight
|
||||
* @memberof Phaser.Renderer.WebGL.RenderNodes
|
||||
* @constructor
|
||||
* @since 3.90.0
|
||||
* @param {Phaser.Renderer.WebGL.RenderNodes.RenderNodeManager} manager - The manager that owns this RenderNode.
|
||||
* @param {Phaser.Types.Renderer.WebGL.RenderNodes.BatchHandlerConfig} [config] - The configuration object for this handler.
|
||||
*/
|
||||
var BatchHandlerTileSpriteLightShadow = new Class({
|
||||
Extends: BatchHandlerTileSpriteLight,
|
||||
|
||||
initialize: function BatchHandlerTileSpriteLightShadow (manager, config)
|
||||
{
|
||||
BatchHandlerTileSpriteLight.call(this, manager, config);
|
||||
|
||||
/**
|
||||
* The threshold at which the diffuse lighting will be considered flat.
|
||||
* This is used to derive self-shadowing from the diffuse map.
|
||||
*
|
||||
* This is a brightness value in the range 0-1.
|
||||
* Because art is usually not pure white, the default is 1/3,
|
||||
* a darker value, which is more likely to be considered flat.
|
||||
* You should adjust this value based on the art in your game.
|
||||
*
|
||||
* @name Phaser.Renderer.WebGL.RenderNodes.BatchHandlerTileSpriteLightShadow#diffuseFlatThreshold
|
||||
* @type {number}
|
||||
* @default 1
|
||||
* @since 3.90.0
|
||||
*/
|
||||
this.diffuseFlatThreshold = 1 / 3;
|
||||
|
||||
/**
|
||||
* The penumbra value for the shadow.
|
||||
* This smooths the edge of self-shadowing.
|
||||
* A lower value will create a sharper but more jagged shadow.
|
||||
*
|
||||
* @name Phaser.Renderer.WebGL.RenderNodes.BatchHandlerTileSpriteLightShadow#penumbra
|
||||
* @type {number}
|
||||
* @default 0.5
|
||||
* @since 3.90.0
|
||||
*/
|
||||
this.penumbra = 0.5;
|
||||
},
|
||||
|
||||
/**
|
||||
* The default configuration settings for BatchHandlerTileSpriteLightShadow.
|
||||
*
|
||||
* @name Phaser.Renderer.WebGL.RenderNodes.BatchHandlerTileSpriteLightShadow#defaultConfig
|
||||
* @type {Phaser.Types.Renderer.WebGL.RenderNodes.BatchHandlerConfig}
|
||||
* @since 3.90.0
|
||||
* @readonly
|
||||
*/
|
||||
defaultConfig: {
|
||||
name: 'BatchHandlerTileSpriteLightShadow',
|
||||
verticesPerInstance: 4,
|
||||
indicesPerInstance: 6,
|
||||
vertexSource: ShaderSourceVS,
|
||||
fragmentSource: LightShaderSourceFS,
|
||||
vertexBufferLayout: {
|
||||
usage: 'DYNAMIC_DRAW',
|
||||
layout: [
|
||||
{
|
||||
name: 'inPosition',
|
||||
size: 2
|
||||
},
|
||||
{
|
||||
name: 'inTexCoord',
|
||||
size: 2
|
||||
},
|
||||
{
|
||||
name: 'inFrame',
|
||||
size: 4
|
||||
},
|
||||
{
|
||||
name: 'inTintEffect'
|
||||
},
|
||||
{
|
||||
name: 'inTint',
|
||||
size: 4,
|
||||
type: 'UNSIGNED_BYTE',
|
||||
normalized: true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Called at the start of the run loop.
|
||||
*
|
||||
* @method Phaser.Renderer.WebGL.RenderNodes.BatchHandlerTileSpriteLightShadow#onRunBegin
|
||||
* @since 3.90.0
|
||||
* @param {Phaser.Renderer.WebGL.WebGLPipeline} drawingContext - The drawing context.
|
||||
*/
|
||||
onRunBegin: function (drawingContext)
|
||||
{
|
||||
BatchHandlerTileSpriteLight.prototype.onRunBegin.call(this, drawingContext);
|
||||
|
||||
var program = this.program;
|
||||
|
||||
program.setUniform(
|
||||
'uDiffuseFlatThreshold',
|
||||
this.diffuseFlatThreshold * 3
|
||||
);
|
||||
|
||||
program.setUniform(
|
||||
'uPenumbra',
|
||||
this.penumbra
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = BatchHandlerTileSpriteLightShadow;
|
|
@ -25,6 +25,8 @@ var BatchHandlerQuadLight = require('./BatchHandlerQuadLight');
|
|||
var BatchHandlerQuadLightShadow = require('./BatchHandlerQuadLightShadow');
|
||||
var BatchHandlerStrip = require('./BatchHandlerStrip');
|
||||
var BatchHandlerTileSprite = require('./BatchHandlerTileSprite');
|
||||
var BatchHandlerTileSpriteLight = require('./BatchHandlerTileSpriteLight');
|
||||
var BatchHandlerTileSpriteLightShadow = require('./BatchHandlerTileSpriteLightShadow');
|
||||
var BatchHandlerTriFlat = require('./BatchHandlerTriFlat');
|
||||
var BatchHandlerTriFlatLight = require('./BatchHandlerTriFlatLight');
|
||||
var Camera = require('./Camera');
|
||||
|
@ -39,6 +41,7 @@ var StrokePath = require('./StrokePath');
|
|||
var SubmitterQuad = require('./submitter/SubmitterQuad');
|
||||
var SubmitterQuadLight = require('./submitter/SubmitterQuadLight');
|
||||
var SubmitterTileSprite = require('./submitter/SubmitterTileSprite');
|
||||
var SubmitterTileSpriteLight = require('./submitter/SubmitterTileSpriteLight');
|
||||
var TexturerImage = require('./texturer/TexturerImage');
|
||||
var TexturerTileSprite = require('./texturer/TexturerTileSprite');
|
||||
var TransformerImage = require('./transformer/TransformerImage');
|
||||
|
@ -154,8 +157,11 @@ var RenderNodeManager = new Class({
|
|||
BatchHandlerPointLight: BatchHandlerPointLight,
|
||||
BatchHandlerQuad: BatchHandlerQuad,
|
||||
BatchHandlerQuadLight: BatchHandlerQuadLight,
|
||||
BatchHandlerQuadLightShadow: BatchHandlerQuadLightShadow,
|
||||
BatchHandlerStrip: BatchHandlerStrip,
|
||||
BatchHandlerTileSprite: BatchHandlerTileSprite,
|
||||
BatchHandlerTileSpriteLight: BatchHandlerTileSpriteLight,
|
||||
BatchHandlerTileSpriteLightShadow: BatchHandlerTileSpriteLightShadow,
|
||||
BatchHandlerTriFlat: BatchHandlerTriFlat,
|
||||
BatchHandlerTriFlatLight: BatchHandlerTriFlatLight,
|
||||
Camera: Camera,
|
||||
|
@ -170,6 +176,7 @@ var RenderNodeManager = new Class({
|
|||
SubmitterQuad: SubmitterQuad,
|
||||
SubmitterQuadLight: SubmitterQuadLight,
|
||||
SubmitterTileSprite: SubmitterTileSprite,
|
||||
SubmitterTileSpriteLight: SubmitterTileSpriteLight,
|
||||
TexturerImage: TexturerImage,
|
||||
TexturerTileSprite: TexturerTileSprite,
|
||||
TransformerImage: TransformerImage,
|
||||
|
@ -181,6 +188,7 @@ var RenderNodeManager = new Class({
|
|||
if (game.config.selfShadow)
|
||||
{
|
||||
this._nodeConstructors.BatchHandlerQuadLight = BatchHandlerQuadLightShadow;
|
||||
this._nodeConstructors.BatchHandlerTileSpriteLight = BatchHandlerTileSpriteLightShadow;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,7 +8,9 @@ var Map = require('../../../../structs/Map');
|
|||
|
||||
var DefaultTileSpriteNodes = new Map([
|
||||
[ 'Submitter', 'SubmitterTileSprite' ],
|
||||
[ 'SubmitterLight', 'SubmitterTileSpriteLight' ],
|
||||
[ 'BatchHandler', 'BatchHandlerTileSprite' ],
|
||||
[ 'BatchHandlerLight', 'BatchHandlerTileSpriteLight' ],
|
||||
[ 'Transformer', 'TransformerTileSprite' ],
|
||||
[ 'Texturer', 'TexturerTileSprite' ]
|
||||
]);
|
||||
|
|
|
@ -16,6 +16,7 @@ var RenderNodes = {
|
|||
BatchHandlerQuadLightShadow: require('./BatchHandlerQuadLightShadow'),
|
||||
BatchHandlerStrip: require('./BatchHandlerStrip'),
|
||||
BatchHandlerTileSprite: require('./BatchHandlerTileSprite'),
|
||||
BatchHandlerTileSpriteLight: require('./BatchHandlerTileSpriteLight'),
|
||||
BatchHandlerTriFlat: require('./BatchHandlerTriFlat'),
|
||||
BatchHandlerTriFlatLight: require('./BatchHandlerTriFlatLight'),
|
||||
Camera: require('./Camera'),
|
||||
|
@ -31,6 +32,7 @@ var RenderNodes = {
|
|||
SubmitterQuad: require('./submitter/SubmitterQuad'),
|
||||
SubmitterQuadLight: require('./submitter/SubmitterQuadLight'),
|
||||
SubmitterTileSprite: require('./submitter/SubmitterTileSprite'),
|
||||
SubmitterTileSpriteLight: require('./submitter/SubmitterTileSpriteLight'),
|
||||
TexturerImage: require('./texturer/TexturerImage'),
|
||||
TexturerTileSprite: require('./texturer/TexturerTileSprite'),
|
||||
TransformerImage: require('./transformer/TransformerImage'),
|
||||
|
|
|
@ -15,8 +15,7 @@ var getTint = Utils.getTintAppendFloatAlpha;
|
|||
* @classdesc
|
||||
* The SubmitterQuadLight RenderNode submits data for rendering
|
||||
* a single Image-like GameObject with lighting information.
|
||||
*
|
||||
* It uses a BatchHandlerQuadLight to render the image as part of a batch.
|
||||
* It uses a BatchHandler to render the image as part of a batch.
|
||||
*
|
||||
* @class SubmitterQuadLight
|
||||
* @memberof Phaser.Renderer.WebGL.RenderNodes
|
||||
|
|
|
@ -10,6 +10,29 @@ var SubmitterQuad = require('./SubmitterQuad.js');
|
|||
|
||||
var getTint = Utils.getTintAppendFloatAlpha;
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* The SubmitterTileSprite RenderNode submits data for rendering a single TileSprite GameObject.
|
||||
* It uses a BatchHandler to render the TileSprite as part of a batch.
|
||||
*
|
||||
* This node receives the drawing context, game object, and parent matrix.
|
||||
* It also receives the texturer, tinter, and transformer nodes
|
||||
* from the node that invoked it.
|
||||
* This allows the behavior to be configured by setting the appropriate nodes
|
||||
* on the GameObject for individual tweaks, or on the invoking Renderer node
|
||||
* for global changes.
|
||||
*
|
||||
* @class SubmitterTileSprite
|
||||
* @memberof Phaser.Renderer.WebGL.RenderNodes
|
||||
* @constructor
|
||||
* @since 3.90.0
|
||||
* @extends Phaser.Renderer.WebGL.RenderNodes.SubmitterQuad
|
||||
* @param {Phaser.Renderer.WebGL.RenderNodes.RenderNodeManager} manager - The manager that owns this RenderNode.
|
||||
* @param {object} [config] - The configuration object for this RenderNode.
|
||||
* @param {string} [config.name='SubmitterTileSprite'] - The name of this RenderNode.
|
||||
* @param {string} [config.role='Submitter'] - The expected role of this RenderNode.
|
||||
* @param {string} [config.batchHandler='BatchHandler'] - The key of the default batch handler node to use for this RenderNode. This should correspond to a node which extends `BatchHandlerTileSprite`. It will be derived from the game object whenever the node runs.
|
||||
*/
|
||||
var SubmitterTileSprite = new Class({
|
||||
Extends: SubmitterQuad,
|
||||
|
||||
|
|
|
@ -0,0 +1,206 @@
|
|||
/**
|
||||
* @author Benjamin D. Richards <benjamindrichards@gmail.com>
|
||||
* @copyright 2013-2024 Phaser Studio Inc.
|
||||
* @license {@link https://opensource.org/licenses/MIT|MIT License}
|
||||
*/
|
||||
|
||||
var Class = require('../../../../utils/Class');
|
||||
var Merge = require('../../../../utils/object/Merge');
|
||||
var Utils = require('../../Utils.js');
|
||||
var SubmitterQuad = require('./SubmitterQuad');
|
||||
|
||||
var getTint = Utils.getTintAppendFloatAlpha;
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* The SubmitterTileSpriteLight RenderNode submits data for rendering
|
||||
* a single TileSprite GameObject with lighting information.
|
||||
*
|
||||
* @class SubmitterTileSpriteLight
|
||||
* @memberof Phaser.Renderer.WebGL.RenderNodes
|
||||
* @constructor
|
||||
* @since 3.90.0
|
||||
* @extends Phaser.Renderer.WebGL.RenderNodes.SubmitterQuad
|
||||
* @param {Phaser.Renderer.WebGL.RenderNodes.RenderNodeManager} manager - The manager that owns this RenderNode.
|
||||
* @param {object} [config] - The configuration object for this RenderNode.
|
||||
* @param {string} [config.name='SubmitterTileSpriteLight'] - The name of this RenderNode.
|
||||
* @param {string} [config.role='Submitter'] - The expected role of this RenderNode.
|
||||
* @param {string} [config.batchHandler='BatchHandlerLight'] - The key of the default batch handler node to use for this RenderNode. This should correspond to a node which extends `BatchHandlerQuadLight`. It will be derived from the game object whenever the node runs.
|
||||
*/
|
||||
var SubmitterTileSpriteLight = new Class({
|
||||
Extends: SubmitterQuad,
|
||||
|
||||
initialize: function SubmitterTileSpriteLight (manager, config)
|
||||
{
|
||||
config = Merge(config || {}, this.defaultConfig);
|
||||
|
||||
SubmitterQuad.call(this, manager, config);
|
||||
},
|
||||
|
||||
defaultConfig: {
|
||||
name: 'SubmitterTileSpriteLight',
|
||||
role: 'Submitter',
|
||||
batchHandler: 'BatchHandlerLight'
|
||||
},
|
||||
|
||||
/**
|
||||
* Submit data for rendering.
|
||||
*
|
||||
* @method Phaser.Renderer.WebGL.RenderNodes.SubmitterTileSpriteLight#run
|
||||
* @since 3.90.0
|
||||
* @param {Phaser.Renderer.WebGL.DrawingContext} drawingContext - The current drawing context.
|
||||
* @param {Phaser.GameObjects.GameObject} gameObject - The GameObject being rendered.
|
||||
* @param {Phaser.GameObjects.Components.TransformMatrix} parentMatrix - The parent matrix of the GameObject.
|
||||
* @param {number} [elementIndex] - The index of the element within the game object. This is used for objects that consist of multiple quads.
|
||||
* @param {Phaser.Renderer.WebGL.RenderNodes.RenderNode|Omit<Phaser.Renderer.WebGL.RenderNodes.TexturerImage, 'run'>} texturerNode - The texturer node used to texture the GameObject. You may pass a texturer node or an object containing equivalent data without a `run` method.
|
||||
* @param {Phaser.Renderer.WebGL.RenderNodes.RenderNode|{ quad: Float32Array }} transformerNode - The transformer node used to transform the GameObject. You may pass a transformer node or an object with a `quad` property.
|
||||
* @param {Phaser.Renderer.WebGL.RenderNodes.RenderNode|Omit<Phaser.Renderer.WebGL.RenderNodes.RenderNode, 'run'>} [tinterNode] - The tinter node used to tint the GameObject. You may pass a tinter node or an object containing equivalent data without a `run` method. If omitted, Image-style tinting will be used.
|
||||
* @param {Phaser.Renderer.WebGL.Wrappers.WebGLTextureWrapper} [normalMap] - The normal map texture to use for lighting. If omitted, the normal map texture of the GameObject will be used, or the default normal map texture of the renderer.
|
||||
* @param {number} [normalMapRotation] - The rotation of the normal map texture. If omitted, the rotation of the GameObject will be used.
|
||||
*/
|
||||
run: function (
|
||||
drawingContext,
|
||||
gameObject,
|
||||
parentMatrix,
|
||||
elementIndex,
|
||||
texturerNode,
|
||||
transformerNode,
|
||||
tinterNode,
|
||||
normalMap,
|
||||
normalMapRotation
|
||||
)
|
||||
{
|
||||
var lightManager = drawingContext.camera.scene.sys.lights;
|
||||
if (!lightManager || !lightManager.active)
|
||||
{
|
||||
// Skip rendering if the light manager is not active.
|
||||
return;
|
||||
}
|
||||
|
||||
this.onRunBegin(drawingContext);
|
||||
|
||||
var cameraAlpha = drawingContext.camera.alpha;
|
||||
var tintFill, tintTopLeft, tintBottomLeft, tintTopRight, tintBottomRight;
|
||||
|
||||
if (texturerNode.run)
|
||||
{
|
||||
texturerNode.run(drawingContext, gameObject, elementIndex);
|
||||
}
|
||||
if (transformerNode.run)
|
||||
{
|
||||
transformerNode.run(drawingContext, gameObject, parentMatrix, elementIndex, texturerNode);
|
||||
}
|
||||
if (tinterNode)
|
||||
{
|
||||
if (tinterNode.run)
|
||||
{
|
||||
tinterNode.run(drawingContext, gameObject, elementIndex);
|
||||
}
|
||||
tintFill = tinterNode.tintFill;
|
||||
tintTopLeft = tinterNode.tintTopLeft;
|
||||
tintBottomLeft = tinterNode.tintBottomLeft;
|
||||
tintTopRight = tinterNode.tintTopRight;
|
||||
tintBottomRight = tinterNode.tintBottomRight;
|
||||
}
|
||||
else
|
||||
{
|
||||
tintFill = gameObject.tintFill;
|
||||
tintTopLeft = getTint(gameObject.tintTopLeft, cameraAlpha * gameObject._alphaTL);
|
||||
tintBottomLeft = getTint(gameObject.tintBottomLeft, cameraAlpha * gameObject._alphaBL);
|
||||
tintTopRight = getTint(gameObject.tintTopRight, cameraAlpha * gameObject._alphaTR);
|
||||
tintBottomRight = getTint(gameObject.tintBottomRight, cameraAlpha * gameObject._alphaBR);
|
||||
}
|
||||
|
||||
var frame = texturerNode.frame;
|
||||
var quad = transformerNode.quad;
|
||||
var uvSource = frame;
|
||||
var u0 = uvSource.u0;
|
||||
var v0 = uvSource.v0;
|
||||
var u1 = uvSource.u1;
|
||||
var v1 = uvSource.v1;
|
||||
var uvQuad = texturerNode.uvMatrix.quad;
|
||||
|
||||
// Get normal map.
|
||||
if (!normalMap)
|
||||
{
|
||||
if (gameObject.displayTexture)
|
||||
{
|
||||
normalMap = gameObject.displayTexture.dataSource[gameObject.displayFrame.sourceIndex];
|
||||
}
|
||||
else if (gameObject.texture)
|
||||
{
|
||||
normalMap = gameObject.texture.dataSource[gameObject.frame.sourceIndex];
|
||||
}
|
||||
else if (gameObject.tileset)
|
||||
{
|
||||
if (Array.isArray(gameObject.tileset))
|
||||
{
|
||||
normalMap = gameObject.tileset[0].image.dataSource[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
normalMap = gameObject.tileset.image.dataSource[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!normalMap)
|
||||
{
|
||||
normalMap = this.manager.renderer.normalTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
normalMap = normalMap.glTexture;
|
||||
}
|
||||
|
||||
// Get normal map rotation.
|
||||
if (isNaN(normalMapRotation))
|
||||
{
|
||||
normalMapRotation = gameObject.rotation;
|
||||
if (gameObject.parentContainer)
|
||||
{
|
||||
var matrix = gameObject.getWorldTransformMatrix(this._tempMatrix, this._tempMatrix2);
|
||||
normalMapRotation = matrix.rotationNormalized;
|
||||
}
|
||||
}
|
||||
|
||||
// Batch the quad.
|
||||
(
|
||||
gameObject.customRenderNodes[this.batchHandler] ||
|
||||
gameObject.defaultRenderNodes[this.batchHandler]
|
||||
).batch(
|
||||
drawingContext,
|
||||
|
||||
// Use `frame.source.glTexture` instead of `frame.glTexture`
|
||||
// to avoid unnecessary getter function calls.
|
||||
frame.source.glTexture,
|
||||
normalMap,
|
||||
|
||||
// Normal map rotation
|
||||
normalMapRotation,
|
||||
|
||||
// Transformed quad in order TL, BL, TR, BR:
|
||||
quad[0], quad[1],
|
||||
quad[2], quad[3],
|
||||
quad[6], quad[7],
|
||||
quad[4], quad[5],
|
||||
|
||||
// Texture coordinates in X, Y, Width, Height:
|
||||
u0, v0, u1 - u0, v1 - v0,
|
||||
|
||||
// Dynamic UV coordinates in order TL, BL, TR, BR:
|
||||
uvQuad[0], uvQuad[1],
|
||||
uvQuad[2], uvQuad[3],
|
||||
uvQuad[6], uvQuad[7],
|
||||
uvQuad[4], uvQuad[5],
|
||||
|
||||
tintFill,
|
||||
|
||||
// Tint colors in order TL, BL, TR, BR:
|
||||
tintTopLeft, tintBottomLeft, tintTopRight, tintBottomRight
|
||||
);
|
||||
|
||||
this.onRunEnd(drawingContext);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = SubmitterTileSpriteLight;
|
60
src/renderer/webgl/shaders/TileSpriteLight-frag.js
Normal file
60
src/renderer/webgl/shaders/TileSpriteLight-frag.js
Normal file
|
@ -0,0 +1,60 @@
|
|||
module.exports = [
|
||||
'#define SHADER_NAME PHASER_TILE_SPRITE_LIGHT_FS',
|
||||
'precision mediump float;',
|
||||
'struct Light',
|
||||
'{',
|
||||
' vec3 position;',
|
||||
' vec3 color;',
|
||||
' float intensity;',
|
||||
' float radius;',
|
||||
'};',
|
||||
'const int kMaxLights = %LIGHT_COUNT%;',
|
||||
'uniform vec4 uCamera; /* x, y, rotation, zoom */',
|
||||
'uniform vec2 uResolution;',
|
||||
'uniform sampler2D uMainSampler;',
|
||||
'uniform sampler2D uNormSampler;',
|
||||
'uniform vec3 uAmbientLightColor;',
|
||||
'uniform Light uLights[kMaxLights];',
|
||||
'uniform mat3 uInverseRotationMatrix;',
|
||||
'uniform int uLightCount;',
|
||||
'varying vec2 outTexCoord;',
|
||||
'varying vec4 outFrame;',
|
||||
'varying float outTintEffect;',
|
||||
'varying vec4 outTint;',
|
||||
'void main ()',
|
||||
'{',
|
||||
' vec3 finalColor = vec3(0.0, 0.0, 0.0);',
|
||||
' vec2 texCoord = mod(outTexCoord, 1.0) * outFrame.zw + outFrame.xy;',
|
||||
' vec4 texel = vec4(outTint.bgr * outTint.a, outTint.a);',
|
||||
' vec4 texture = texture2D(uMainSampler, texCoord);',
|
||||
' 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;',
|
||||
' }',
|
||||
' vec3 normalMap = texture2D(uNormSampler, texCoord).rgb;',
|
||||
' vec3 normal = normalize(uInverseRotationMatrix * vec3(normalMap * 2.0 - 1.0));',
|
||||
' vec2 res = vec2(min(uResolution.x, uResolution.y)) * uCamera.w;',
|
||||
' for (int index = 0; index < kMaxLights; ++index)',
|
||||
' {',
|
||||
' if (index < uLightCount)',
|
||||
' {',
|
||||
' Light light = uLights[index];',
|
||||
' vec3 lightDir = vec3((light.position.xy / res) - (gl_FragCoord.xy / res), light.position.z / res.x);',
|
||||
' vec3 lightNormal = normalize(lightDir);',
|
||||
' float distToSurf = length(lightDir) * uCamera.w;',
|
||||
' float diffuseFactor = max(dot(normal, lightNormal), 0.0);',
|
||||
' float radius = (light.radius / res.x * uCamera.w) * uCamera.w;',
|
||||
' float attenuation = clamp(1.0 - distToSurf * distToSurf / (radius * radius), 0.0, 1.0);',
|
||||
' vec3 diffuse = light.color * diffuseFactor;',
|
||||
' finalColor += (attenuation * diffuse) * light.intensity;',
|
||||
' }',
|
||||
' }',
|
||||
' vec4 colorOutput = vec4(uAmbientLightColor + finalColor, 1.0);',
|
||||
' gl_FragColor = color * vec4(colorOutput.rgb * colorOutput.a, colorOutput.a);',
|
||||
'}',
|
||||
].join('\n');
|
65
src/renderer/webgl/shaders/TileSpriteLightShadow-frag.js
Normal file
65
src/renderer/webgl/shaders/TileSpriteLightShadow-frag.js
Normal file
|
@ -0,0 +1,65 @@
|
|||
module.exports = [
|
||||
'#define SHADER_NAME PHASER_TILE_SPRITE_LIGHT_FS',
|
||||
'precision mediump float;',
|
||||
'struct Light',
|
||||
'{',
|
||||
' vec3 position;',
|
||||
' vec3 color;',
|
||||
' float intensity;',
|
||||
' float radius;',
|
||||
'};',
|
||||
'const int kMaxLights = %LIGHT_COUNT%;',
|
||||
'uniform vec4 uCamera; /* x, y, rotation, zoom */',
|
||||
'uniform vec2 uResolution;',
|
||||
'uniform sampler2D uMainSampler;',
|
||||
'uniform sampler2D uNormSampler;',
|
||||
'uniform vec3 uAmbientLightColor;',
|
||||
'uniform Light uLights[kMaxLights];',
|
||||
'uniform mat3 uInverseRotationMatrix;',
|
||||
'uniform int uLightCount;',
|
||||
'uniform float uDiffuseFlatThreshold;',
|
||||
'uniform float uPenumbra;',
|
||||
'varying vec2 outTexCoord;',
|
||||
'varying vec4 outFrame;',
|
||||
'varying float outTintEffect;',
|
||||
'varying vec4 outTint;',
|
||||
'void main ()',
|
||||
'{',
|
||||
' vec3 finalColor = vec3(0.0, 0.0, 0.0);',
|
||||
' vec2 texCoord = mod(outTexCoord, 1.0) * outFrame.zw + outFrame.xy;',
|
||||
' vec4 texel = vec4(outTint.bgr * outTint.a, outTint.a);',
|
||||
' vec4 texture = texture2D(uMainSampler, texCoord);',
|
||||
' 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;',
|
||||
' }',
|
||||
' vec3 normalMap = texture2D(uNormSampler, texCoord).rgb;',
|
||||
' vec3 normal = normalize(uInverseRotationMatrix * vec3(normalMap * 2.0 - 1.0));',
|
||||
' vec2 res = vec2(min(uResolution.x, uResolution.y)) * uCamera.w;',
|
||||
' vec3 unpremultipliedColor = color.rgb / color.a;',
|
||||
' float occlusionThreshold = 1.0 - ((unpremultipliedColor.r + unpremultipliedColor.g + unpremultipliedColor.b) / uDiffuseFlatThreshold);',
|
||||
' for (int index = 0; index < kMaxLights; ++index)',
|
||||
' {',
|
||||
' if (index < uLightCount)',
|
||||
' {',
|
||||
' Light light = uLights[index];',
|
||||
' vec3 lightDir = vec3((light.position.xy / res) - (gl_FragCoord.xy / res), light.position.z / res.x);',
|
||||
' vec3 lightNormal = normalize(lightDir);',
|
||||
' float distToSurf = length(lightDir) * uCamera.w;',
|
||||
' float diffuseFactor = max(dot(normal, lightNormal), 0.0);',
|
||||
' float radius = (light.radius / res.x * uCamera.w) * uCamera.w;',
|
||||
' float attenuation = clamp(1.0 - distToSurf * distToSurf / (radius * radius), 0.0, 1.0);',
|
||||
' float occluded = smoothstep(0.0, 1.0, (diffuseFactor - occlusionThreshold) / uPenumbra);',
|
||||
' vec3 diffuse = light.color * diffuseFactor * occluded;',
|
||||
' finalColor += (attenuation * diffuse) * light.intensity;',
|
||||
' }',
|
||||
' }',
|
||||
' vec4 colorOutput = vec4(uAmbientLightColor + finalColor, 1.0);',
|
||||
' gl_FragColor = color * vec4(colorOutput.rgb * colorOutput.a, colorOutput.a);',
|
||||
'}',
|
||||
].join('\n');
|
|
@ -51,6 +51,8 @@ module.exports = {
|
|||
PostFXFrag: require('./PostFX-frag.js'),
|
||||
QuadVert: require('./Quad-vert.js'),
|
||||
SingleFrag: require('./Single-frag.js'),
|
||||
SingleVert: require('./Single-vert.js')
|
||||
SingleVert: require('./Single-vert.js'),
|
||||
TileSpriteLightFrag: require('./TileSpriteLight-frag.js'),
|
||||
TileSpriteLightShadowFrag: require('./TileSpriteLightShadow-frag.js')
|
||||
|
||||
};
|
||||
|
|
75
src/renderer/webgl/shaders/src/TileSpriteLight.frag
Normal file
75
src/renderer/webgl/shaders/src/TileSpriteLight.frag
Normal file
|
@ -0,0 +1,75 @@
|
|||
#define SHADER_NAME PHASER_TILE_SPRITE_LIGHT_FS
|
||||
|
||||
precision mediump float;
|
||||
|
||||
struct Light
|
||||
{
|
||||
vec3 position;
|
||||
vec3 color;
|
||||
float intensity;
|
||||
float radius;
|
||||
};
|
||||
|
||||
const int kMaxLights = %LIGHT_COUNT%;
|
||||
|
||||
uniform vec4 uCamera; /* x, y, rotation, zoom */
|
||||
uniform vec2 uResolution;
|
||||
uniform sampler2D uMainSampler;
|
||||
uniform sampler2D uNormSampler;
|
||||
uniform vec3 uAmbientLightColor;
|
||||
uniform Light uLights[kMaxLights];
|
||||
uniform mat3 uInverseRotationMatrix;
|
||||
uniform int uLightCount;
|
||||
|
||||
varying vec2 outTexCoord;
|
||||
varying vec4 outFrame;
|
||||
varying float outTintEffect;
|
||||
varying vec4 outTint;
|
||||
|
||||
void main ()
|
||||
{
|
||||
vec3 finalColor = vec3(0.0, 0.0, 0.0);
|
||||
|
||||
// Wrap texture coordinate into the UV space of the texture frame.
|
||||
vec2 texCoord = mod(outTexCoord, 1.0) * outFrame.zw + outFrame.xy;
|
||||
|
||||
vec4 texel = vec4(outTint.bgr * outTint.a, outTint.a);
|
||||
vec4 texture = texture2D(uMainSampler, texCoord);
|
||||
// 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;
|
||||
}
|
||||
|
||||
vec3 normalMap = texture2D(uNormSampler, texCoord).rgb;
|
||||
vec3 normal = normalize(uInverseRotationMatrix * vec3(normalMap * 2.0 - 1.0));
|
||||
vec2 res = vec2(min(uResolution.x, uResolution.y)) * uCamera.w;
|
||||
|
||||
for (int index = 0; index < kMaxLights; ++index)
|
||||
{
|
||||
if (index < uLightCount)
|
||||
{
|
||||
Light light = uLights[index];
|
||||
vec3 lightDir = vec3((light.position.xy / res) - (gl_FragCoord.xy / res), light.position.z / res.x);
|
||||
vec3 lightNormal = normalize(lightDir);
|
||||
float distToSurf = length(lightDir) * uCamera.w;
|
||||
float diffuseFactor = max(dot(normal, lightNormal), 0.0);
|
||||
float radius = (light.radius / res.x * uCamera.w) * uCamera.w;
|
||||
float attenuation = clamp(1.0 - distToSurf * distToSurf / (radius * radius), 0.0, 1.0);
|
||||
vec3 diffuse = light.color * diffuseFactor;
|
||||
finalColor += (attenuation * diffuse) * light.intensity;
|
||||
}
|
||||
}
|
||||
|
||||
vec4 colorOutput = vec4(uAmbientLightColor + finalColor, 1.0);
|
||||
|
||||
gl_FragColor = color * vec4(colorOutput.rgb * colorOutput.a, colorOutput.a);
|
||||
}
|
81
src/renderer/webgl/shaders/src/TileSpriteLightShadow.frag
Normal file
81
src/renderer/webgl/shaders/src/TileSpriteLightShadow.frag
Normal file
|
@ -0,0 +1,81 @@
|
|||
#define SHADER_NAME PHASER_TILE_SPRITE_LIGHT_FS
|
||||
|
||||
precision mediump float;
|
||||
|
||||
struct Light
|
||||
{
|
||||
vec3 position;
|
||||
vec3 color;
|
||||
float intensity;
|
||||
float radius;
|
||||
};
|
||||
|
||||
const int kMaxLights = %LIGHT_COUNT%;
|
||||
|
||||
uniform vec4 uCamera; /* x, y, rotation, zoom */
|
||||
uniform vec2 uResolution;
|
||||
uniform sampler2D uMainSampler;
|
||||
uniform sampler2D uNormSampler;
|
||||
uniform vec3 uAmbientLightColor;
|
||||
uniform Light uLights[kMaxLights];
|
||||
uniform mat3 uInverseRotationMatrix;
|
||||
uniform int uLightCount;
|
||||
uniform float uDiffuseFlatThreshold;
|
||||
uniform float uPenumbra;
|
||||
|
||||
varying vec2 outTexCoord;
|
||||
varying vec4 outFrame;
|
||||
varying float outTintEffect;
|
||||
varying vec4 outTint;
|
||||
|
||||
void main ()
|
||||
{
|
||||
vec3 finalColor = vec3(0.0, 0.0, 0.0);
|
||||
|
||||
// Wrap texture coordinate into the UV space of the texture frame.
|
||||
vec2 texCoord = mod(outTexCoord, 1.0) * outFrame.zw + outFrame.xy;
|
||||
|
||||
vec4 texel = vec4(outTint.bgr * outTint.a, outTint.a);
|
||||
vec4 texture = texture2D(uMainSampler, texCoord);
|
||||
// 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;
|
||||
}
|
||||
|
||||
vec3 normalMap = texture2D(uNormSampler, texCoord).rgb;
|
||||
vec3 normal = normalize(uInverseRotationMatrix * vec3(normalMap * 2.0 - 1.0));
|
||||
vec2 res = vec2(min(uResolution.x, uResolution.y)) * uCamera.w;
|
||||
|
||||
vec3 unpremultipliedColor = color.rgb / color.a;
|
||||
float occlusionThreshold = 1.0 - ((unpremultipliedColor.r + unpremultipliedColor.g + unpremultipliedColor.b) / uDiffuseFlatThreshold);
|
||||
|
||||
for (int index = 0; index < kMaxLights; ++index)
|
||||
{
|
||||
if (index < uLightCount)
|
||||
{
|
||||
Light light = uLights[index];
|
||||
vec3 lightDir = vec3((light.position.xy / res) - (gl_FragCoord.xy / res), light.position.z / res.x);
|
||||
vec3 lightNormal = normalize(lightDir);
|
||||
float distToSurf = length(lightDir) * uCamera.w;
|
||||
float diffuseFactor = max(dot(normal, lightNormal), 0.0);
|
||||
float radius = (light.radius / res.x * uCamera.w) * uCamera.w;
|
||||
float attenuation = clamp(1.0 - distToSurf * distToSurf / (radius * radius), 0.0, 1.0);
|
||||
float occluded = smoothstep(0.0, 1.0, (diffuseFactor - occlusionThreshold) / uPenumbra);
|
||||
vec3 diffuse = light.color * diffuseFactor * occluded;
|
||||
finalColor += (attenuation * diffuse) * light.intensity;
|
||||
}
|
||||
}
|
||||
|
||||
vec4 colorOutput = vec4(uAmbientLightColor + finalColor, 1.0);
|
||||
|
||||
gl_FragColor = color * vec4(colorOutput.rgb * colorOutput.a, colorOutput.a);
|
||||
}
|
Loading…
Reference in a new issue