Add option for self-shadowing through bent normal approximation.

This commit is contained in:
Ben Richards 2024-07-08 18:28:23 +12:00
parent c8c7a65ab0
commit f937267331
6 changed files with 152 additions and 0 deletions

View file

@ -395,6 +395,11 @@ var Config = new Class({
*/
this.roundPixels = GetValue(renderConfig, 'roundPixels', true, config);
/**
* @const {boolean} Phaser.Core.Config#selfShadow - On textured objects with lighting, this enables self-shadowing based on the diffuse map.
*/
this.selfShadow = GetValue(renderConfig, 'selfShadow', false, config);
/**
* @const {number} Phaser.Core.Config#pathDetailThreshold - Threshold for combining points into a single path in the WebGL renderer for Graphics objects. This can be overridden at the Graphics object level.
*/

View file

@ -7,6 +7,7 @@
* @property {boolean} [desynchronized=false] - When set to `true` it will create a desynchronized context for both 2D and WebGL. See https://developers.google.com/web/updates/2019/05/desynchronized for details.
* @property {boolean} [pixelArt=false] - Sets `antialias` to false and `roundPixels` to true. This is the best setting for pixel-art games.
* @property {boolean} [roundPixels=true] - Draw texture-based Game Objects at only whole-integer positions. Game Objects without textures, like Graphics, ignore this property.
* @property {boolean} [selfShadow=false] - On textured objects with lighting, this enables self-shadowing based on the diffuse map.
* @property {number} [pathDetailThreshold=1] - Threshold for combining points into a single path in the WebGL renderer for Graphics objects. This can be overridden at the Graphics object level.
* @property {boolean} [transparent=false] - Whether the game canvas will be transparent. Boolean that indicates if the canvas contains an alpha channel. If set to false, the browser now knows that the backdrop is always opaque, which can speed up drawing of transparent content and images.
* @property {boolean} [clearBeforeRender=true] - Whether the game canvas will be cleared between each rendering frame.

View file

@ -0,0 +1,138 @@
/**
* @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/LightShadow-frag');
var ShaderSourceVS = require('../shaders/Multi-vert');
var BatchHandlerQuadLight = require('./BatchHandlerQuadLight');
/**
* @classdesc
* The BatchHandlerQuadLightShadow is a special type of BatchHandlerQuadLight
* that supports self-shadowing based on the diffuse map.
*
* The shader uses the diffuse map to determine the concavity of the surface.
* Darker areas are assumed to be more concave, thus they can only receive light
* from a smaller range of angles. Light outside that range is cut off,
* creating a shadow.
*
* Because most game art wasn't created with these characteristics in mind,
* you may need to adjust the `diffuseFlatThreshold` and `penumbra` values
* to get the desired effect.
*
* To use this RenderNode in your game, you must set the option
* `render.selfShadow` to `true` in your game configuration.
* It will affect all textured objects with lighting enabled
* (technically, all objects that use the `BatchHandlerQuadLight` RenderNode).
*
* @class BatchHandlerQuadLightShadow
* @extends Phaser.Renderer.WebGL.RenderNodes.BatchHandlerQuadLight
* @memberof Phaser.Renderer.WebGL.RenderNodes
* @constructor
* @since 3.90.0
* @param {Phaser.Renderer.WebGL.WebGLRenderer} manager - The WebGLRenderer instance that owns this handler.
* @param {Phaser.Types.Renderer.WebGL.RenderNodes.BatchHandlerConfig} config - The configuration object for this handler.
*/
var BatchHandlerQuadLightShadow = new Class({
Extends: BatchHandlerQuadLight,
initialize: function BatchHandlerQuadLightShadow (manager, config)
{
BatchHandlerQuadLight.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.BatchHandlerQuadLightShadow#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.BatchHandlerQuadLightShadow#penumbra
* @type {number}
* @default 0.5
* @since 3.90.0
*/
this.penumbra = 0.5;
},
/**
* The default configuration settings for BatchHandlerQuadLightShadow.
*
* @name Phaser.Renderer.WebGL.RenderNodes.BatchHandlerQuadLightShadow#defaultConfig
* @type {Phaser.Types.Renderer.WebGL.RenderNodes.BatchHandlerConfig}
* @since 3.90.0
* @readonly
*/
defaultConfig: {
name: 'BatchHandlerQuadLight',
verticesPerInstance: 4,
indicesPerInstance: 6,
vertexSource: ShaderSourceVS,
fragmentSource: LightShaderSourceFS,
vertexBufferLayout: {
usage: 'DYNAMIC_DRAW',
layout: [
{
name: 'inPosition',
size: 2
},
{
name: 'inTexCoord',
size: 2
},
{
name: 'inTintEffect'
},
{
name: 'inTint',
size: 4,
type: 'UNSIGNED_BYTE',
normalized: true
}
]
}
},
/**
* Called at the start of the run loop.
*
* @method Phaser.Renderer.WebGL.RenderNodes.BatchHandlerQuadLightShadow#onRunBegin
* @since 3.90.0
* @param {Phaser.Renderer.WebGL.WebGLPipeline} drawingContext - The drawing context.
*/
onRunBegin: function (drawingContext)
{
BatchHandlerQuadLight.prototype.onRunBegin.call(this, drawingContext);
var program = this.program;
program.setUniform(
'uDiffuseFlatThreshold',
this.diffuseFlatThreshold * 3
);
program.setUniform(
'uPenumbra',
this.penumbra
);
}
});
module.exports = BatchHandlerQuadLightShadow;

View file

@ -19,6 +19,7 @@ var DefaultPointLightNodes = require('./defaults/DefaultPointLightNodes');
var BatchHandlerPointLight = require('./BatchHandlerPointLight');
var BatchHandlerQuad = require('./BatchHandlerQuad');
var BatchHandlerQuadLight = require('./BatchHandlerQuadLight');
var BatchHandlerQuadLightShadow = require('./BatchHandlerQuadLightShadow');
var BatchHandlerTriFlat = require('./BatchHandlerTriFlat');
var BatchHandlerTriFlatLight = require('./BatchHandlerTriFlatLight');
var Camera = require('./Camera');
@ -159,6 +160,11 @@ var RenderNodeManager = new Class({
YieldContext: YieldContext
};
if (game.config.selfShadow)
{
this._nodeConstructors.BatchHandlerQuadLight = BatchHandlerQuadLightShadow;
}
/**
* The RenderNode which is currently being filled.
* This is stored so that it can be completed when another type of

View file

@ -13,6 +13,7 @@ var RenderNodes = {
BatchHandlerPointLight: require('./BatchHandlerPointLight'),
BatchHandlerQuad: require('./BatchHandlerQuad'),
BatchHandlerQuadLight: require('./BatchHandlerQuadLight'),
BatchHandlerQuadLightShadow: require('./BatchHandlerQuadLightShadow'),
BatchHandlerTriFlat: require('./BatchHandlerTriFlat'),
BatchHandlerTriFlatLight: require('./BatchHandlerTriFlatLight'),
Camera: require('./Camera'),

View file

@ -36,6 +36,7 @@ module.exports = {
FlatVert: require('./Flat-vert.js'),
FlatLightFrag: require('./FlatLight-frag.js'),
LightFrag: require('./Light-frag.js'),
LightShadowFrag: require('./LightShadow-frag.js'),
LinearBlendFrag: require('./LinearBlend-frag.js'),
MeshFrag: require('./Mesh-frag.js'),
MeshVert: require('./Mesh-vert.js'),