mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-04-11 15:47:06 +08:00
着色器特效第二层
This commit is contained in:
parent
37a18c87c0
commit
38e24dd9bc
@ -44,7 +44,7 @@ main.floors.MT8=
|
||||
],
|
||||
"10,9": [
|
||||
"这里是第二个特效展示木牌。",
|
||||
"下面我将对事件层和勇士层进行处理,任何不透明的像素都将变成完全黑色,否则完全透明。它的着色器脚本:\n\r[yellow]void main() {\n float alpha = texture2D(uSampler, vTextureCoord).a;\n gl_FragColor = vec4(0.0, 0.0, 0.0, alpha == 0 ? 0 : 1);\n}\r",
|
||||
"下面我将对事件层和勇士层进行处理,任何不透明的像素都将变成完全黑色,否则完全透明。它的着色器脚本:\n\r[yellow]void main() {\n float alpha = texture2D(uSampler, vTextureCoord).a;\n gl_FragColor = vec4(0.0, 0.0, 0.0, alpha == 0.0 ? 0.0 : 1.0);\n}\r",
|
||||
{
|
||||
"type": "function",
|
||||
"function": "function(){\nflags.lastShaderSample?.end();\nflags.lastShaderSample = core.shaderSample2();\n}"
|
||||
@ -67,7 +67,12 @@ main.floors.MT8=
|
||||
}
|
||||
],
|
||||
"4,9": [
|
||||
"不过我们发现到目前为止特效都不会动,只能保持为一定的状态,怎么让特效也能动呢?那就期待插件的下一次更新吧!"
|
||||
"不过我们发现到目前为止特效都不会动,只能保持为一定的状态,怎么让特效也能动呢?那就期待插件的下一次更新吧!",
|
||||
"下面将清除着色器特效。",
|
||||
{
|
||||
"type": "function",
|
||||
"function": "function(){\nflags.lastShaderSample?.end();\n}"
|
||||
}
|
||||
]
|
||||
},
|
||||
"changeFloor": {
|
||||
|
@ -1,45 +1,134 @@
|
||||
main.floors.MT9=
|
||||
{
|
||||
"floorId": "MT9",
|
||||
"title": "主塔 9 层",
|
||||
"name": "9",
|
||||
"width": 15,
|
||||
"height": 15,
|
||||
"canFlyTo": true,
|
||||
"canFlyFrom": true,
|
||||
"canUseQuickShop": true,
|
||||
"cannotViewMap": false,
|
||||
"images": [],
|
||||
"ratio": 1,
|
||||
"defaultGround": "ground",
|
||||
"bgm": "cave.mp3",
|
||||
"firstArrive": [],
|
||||
"eachArrive": [],
|
||||
"parallelDo": "",
|
||||
"events": {},
|
||||
"changeFloor": {},
|
||||
"beforeBattle": {},
|
||||
"afterBattle": {},
|
||||
"afterGetItem": {},
|
||||
"afterOpenDoor": {},
|
||||
"autoEvent": {},
|
||||
"cannotMove": {},
|
||||
"cannotMoveIn": {},
|
||||
"map": [
|
||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
"floorId": "MT9",
|
||||
"title": "主塔 9 层",
|
||||
"name": "9",
|
||||
"width": 15,
|
||||
"height": 15,
|
||||
"canFlyTo": true,
|
||||
"canFlyFrom": true,
|
||||
"canUseQuickShop": true,
|
||||
"cannotViewMap": false,
|
||||
"images": [],
|
||||
"ratio": 1,
|
||||
"defaultGround": "ground",
|
||||
"bgm": "cave.mp3",
|
||||
"firstArrive": [],
|
||||
"eachArrive": [],
|
||||
"parallelDo": "",
|
||||
"events": {
|
||||
"5,1": [
|
||||
"本层将展示着色器特效的动画效果。",
|
||||
"动画效果的核心依然是高级动画插件,使用它来让一个值动态变化,从而达到动画的效果。本层将展示若干个示例。"
|
||||
],
|
||||
"3,1": [
|
||||
"这里是第一个实例。",
|
||||
"本实例将做出一个画面逐渐变黑白的特效(虽然使用css更为方便,但是为了教学插件怎么用,就使用着色器插件进行制作)",
|
||||
" 首先我们要知道,要让画面变黑白,应该让它的rgb变成相同的,一般来说为了让效果更真实,会有特殊的算法进行优化,不过这里方便起见直接取平均值。\n 那么要有一个动画效果,我们应当声明一个可以变化的值来表示灰度百分比,表现在着色器中就是\r[gold]uniform(全局变量)\r声明。",
|
||||
" 那么片元着色器的代码就是:\n\r[yellow]uniform float uGrayscale;\n\nvoid main() {\n vec4 rgb = texture2D(uSampler, vTextureCoord);\n float avr = (rgb.r + rgb.g + rgb.b) / 3.0;\n float dr = (rgb.r - avr) * (1.0 - uGrayscale);\n float dg = (rgb.g - avr) * (1.0 - uGrayscale);\n float db = (rgb.b - avr) * (1.0 - uGrayscale);\n\n gl_FragColor = vec4(avr + dr, avr + dg, avr + db, rgb.a);\n}\r",
|
||||
" 稍微解析一下这段代码。这段代码首先声明了一个浮点型的\r[yellow]uGrayscale\r全局变量,然后在\r[yellow]main\r函数里面获取了当前像素的rgba值,计算平均值和差值,然后最后的rgba值就是平均值加上差值了。",
|
||||
" 那么前面的代码我们可以很轻松地写出来了,跟上一层的一样,不同的是我们还需要引入高级动画插件:\n\r[yellow]const { ShaderEffect, setTickerFor, replaceGameCanvas } = core.plugin.shaderEffect;\nconst { Animation, hyper } = core.plugin.animate;\nconst canvas = ['bg', 'bg2', 'event', 'fg', 'fg2', 'hero'];\neffect.baseImage(...canvas.map(v => core.canvas[v].canvas));\neffect.vs(ShaderEffect.defaultVs);\neffect.fs(/* 上面那一段着色器脚本 */);\r",
|
||||
" 在这后面就出现与之前不一样的地方了,之前我们直接使用\r[yellow]update\r函数进行渲染,但是这里不一样,需要使用\r[yellow]compile\r函数先进行编译:\n\r[yellow]effect.compile();\r",
|
||||
" 编译完成之后,我们就可以对\r[gold]uniform\r进行操作了,我们需要创建一个全局变量绑定器:\n\r[yellow]const binder = effect.createUniformBinder('uGrayscale', 1, 'f', '');\r\n 这一句话的信息量很大,我们来解析一下。\n 这个方法的第一个参数是全局变量的名称,着色器中我们使用了\r[gold]uGrayScale\r,这里也填它。\n 第二个参数是变量的元素数量,由于是一个浮点型数字,因此只有一个元素,所以填\r[gold]1\r。\n 第三个参数是元素的数值类似,是浮点数,所以填\r[gold]'f'\r,整型的话应该填\r[gold]'i'\r。\n 第四个参数是这个变量是否是向量,浮点数不是向量,因此填\r[gold]''\r,注意不能不填,应当填空字符串。",
|
||||
" 下一步我们需要对这个全局变量进行初始化操作,使用\r[gold]set\r方法进行赋值即可初始化:\n\r[yellow]binder.set(0);\r",
|
||||
" 下面,我们就可以使用js来操作这个\r[gold]uniform\r了,也就是说,我们可以使用高级动画插件操作这个全局变量来实现动画效果了。下面我们直接创建高级动画实例进行动画操作:\n\r[yellow]const ani = new Animation();\nani.register('grayscale', 0);\nani.time(5000).mode(hyper('sin', 'in-out')).absolute().apply('grayscale', 1);\r\n 这样,我们就创建了一个动画属性,下面我们要将它与全局变量绑定器联系起来。这里的高级动画的意思是:动画时间5000毫秒,速率曲线为hyper sin(双曲正弦)函数,in-out(慢-快-慢)变化方式,绝对变化,最终grayscale变为1",
|
||||
" 联系起来的方式很简单,直接使用内置方法每帧赋值即可:\n\r[yellow]ani.ticker.add(() => binder.set(ani.value.grayscale));\r",
|
||||
" 这样动画也配置完毕了,后面便可以直接渲染特效,然后在页面上展示了,唯一不同的点是不能再向\r[gold]update\r的第一个参数传入true了,这会重新编译着色器,导致绑定器失效。下面是后面的代码:\n\r[yellow]effect.update();\nconst ticker = setTickerFor(effect);\nconst manager = replaceGameCanvas(effect, canvas);\r\n 由于全部源码较长,这里就不放完整源码了。",
|
||||
"下面是最终效果。",
|
||||
{
|
||||
"type": "function",
|
||||
"function": "function(){\nflags.lastShaderSample?.end();\nflags.lastShaderSample = core.shaderSample5();\n}"
|
||||
}
|
||||
],
|
||||
"1,1": [
|
||||
"这里是第二个特效实例。",
|
||||
"这个实例将模拟老实电视的显示不稳定",
|
||||
"这个特效本质上是对颜色进行一定程度的噪声处理,因此我们只需要创建一个噪声偏移量的全局变量,然后让它一直以恒定的速率增加就行了,这甚至不需要高级动画实例的参与。",
|
||||
" 它的片元着色器脚本:\n\r[yellow]uniform float uOffset;\n\nfloat noise(float x) {\n float y = fract(sin(x) * 100000.0);\n return y;\n}\n \nvoid main() {\n vec4 rgba = texture2D(uSampler, vTextureCoord);\n float n = noise(rgba.r + rgba.g + rgba.b + uOffset) / 10.0;\n \n gl_FragColor = vec4(rgba.rgb + n, rgba.a);\n}\r",
|
||||
"它在动画部分的脚本(注意从高级动画插件引入Ticker):\n\r[yellow]const ticker = new Ticker();\nticker.add(() => binder.set(binder.get() + 0.01));\r",
|
||||
{
|
||||
"type": "function",
|
||||
"function": "function(){\nflags.lastShaderSample?.end();\nflags.lastShaderSample = core.shaderSample6();\n}"
|
||||
}
|
||||
],
|
||||
"9,1": [
|
||||
"这里是第三个特效实例。",
|
||||
"这个实例将让上一层的第四个实例动起来",
|
||||
"实际伤这与本层的第三实例类似,依然是加一个offset在噪声上。",
|
||||
" 它的片元着色器脚本:\n\r[yellow]uniform float uOffset;\n\nfloat noise(float x) {\n float y = fract(sin(x) * 100000.0);\n return y;\n}\n\nvoid main() {\n float brigtness = -0.1 + noise(uOffset) / 50.0;\n vec2 xy = vTextureCoord;\n float x = xy.x + noise(xy.y + uOffset) / 100.0;\n float y = xy.y;\n vec4 color = texture2D(uSampler, vec2(x, y));\n vec4 color1 = vec4(color.rgb + vec3(brigtness), color.a);\n\n gl_FragColor = color1;\n}\r",
|
||||
"它在动画部分的脚本(注意从高级动画插件引入Ticker):\n\r[yellow]const ticker = new Ticker();\nticker.add(() => binder.set(binder.get() + 0.01));\r",
|
||||
{
|
||||
"type": "function",
|
||||
"function": "function(){\nflags.lastShaderSample?.end();\nflags.lastShaderSample = core.shaderSample7();\n}"
|
||||
}
|
||||
],
|
||||
"11,1": [
|
||||
"这里是第四个特效实例。",
|
||||
"这个实例将做一个四周边缘周期性变黑的特效",
|
||||
" 它需要用到当前像素的位置,因此需要从顶点着色器中用\r[gold]varying\r变量传递至片元着色器中,那么它的顶点着色器:\n\r[yellow]varying vec4 vpos;\n\nvoid main() {\n vTextureCoord = aTextureCoord;\n vpos = aVertexPosition;\n gl_Position = aVertexPosition;\n}\r",
|
||||
" 它的片元着色器脚本:\n\r[yellow]uniform float uStrength;\nvarying vec4 vpos;\n\nvoid main() {\n float alpha = clamp(distance(vec2(0, 0), vpos.xy) - 0.6, 0.0, 1.0) * uStrength;\n vec4 tex = texture2D(uSampler, vTextureCoord);\n gl_FragColor = vec4(tex.rgb * (1.0 - alpha), 1.0);\n}\r",
|
||||
"它在动画部分的脚本(注意从高级动画插件引入Ticker):\n\r[yellow]const ticker = new Ticker();\nticker.add(time => binder.set((Math.sin(time / 2000 - Math.PI / 2) + 1) / 2);\r",
|
||||
{
|
||||
"type": "function",
|
||||
"function": "function(){\nflags.lastShaderSample?.end();\nflags.lastShaderSample = core.shaderSample8();\n}"
|
||||
}
|
||||
],
|
||||
"13,1": [
|
||||
"这里是第五个特效实例。",
|
||||
"这个实例将吧前两个特效结合起来,粗略实现泰拉瑞亚中月球领主来临前的特效。",
|
||||
" 顶点着色器与第四个特效相同:\n\r[yellow]varying vec4 vpos;\n\nvoid main() {\n vTextureCoord = aTextureCoord;\n vpos = aVertexPosition;\n gl_Position = aVertexPosition;\n}\r",
|
||||
" 它的片元着色器脚本:\n\r[yellow]uniform float uStrength;\nvarying vec4 vpos;\n\nfloat noise(float x) {\n float y = fract(sin(x) * 100000.0);\n return y;\n}\n\nvoid main() {\n float brigtness = -uStrength / 10.0;\n vec2 xy = vTextureCoord;\n float x = xy.x + noise(xy.y + uStrength) / 300.0 * uStrength;\n float y = xy.y;\n vec4 color = texture2D(uSampler, vec2(x, y));\n vec4 color1 = vec4(color.rgb + vec3(brigtness), color.a);\n float alpha = clamp(distance(vec2(0, 0), vpos.xy) - 0.6, 0.0, 1.0) * uStrength;\n gl_FragColor = vec4(color1.rgb * (1.0 - alpha), 1.0);\n}\r",
|
||||
"它在动画部分的脚本(注意从高级动画插件引入Ticker):\n\r[yellow]const ticker = new Ticker();\nticker.add(time => binder.set((Math.sin(time / 2000 - Math.PI / 2) + 1) / 2);\r",
|
||||
{
|
||||
"type": "function",
|
||||
"function": "function(){\nflags.lastShaderSample?.end();\nflags.lastShaderSample = core.shaderSample9();\n}"
|
||||
}
|
||||
]
|
||||
},
|
||||
"changeFloor": {
|
||||
"7,1": {
|
||||
"floorId": ":before",
|
||||
"stair": "upFloor"
|
||||
},
|
||||
"7,13": {
|
||||
"floorId": ":next",
|
||||
"stair": "downFloor"
|
||||
}
|
||||
},
|
||||
"beforeBattle": {},
|
||||
"afterBattle": {},
|
||||
"afterGetItem": {},
|
||||
"afterOpenDoor": {},
|
||||
"autoEvent": {},
|
||||
"cannotMove": {},
|
||||
"cannotMoveIn": {},
|
||||
"map": [
|
||||
[ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
[ 1,129, 0,129, 0,129, 0, 88, 0,129, 0,129, 0,129, 1],
|
||||
[ 1,10187, 0,10186, 0,10185, 0, 0, 0,10188, 0,10189, 0,10193, 1],
|
||||
[ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
|
||||
[ 1,201, 0,202, 0,203, 0,204, 0,205, 0,206, 0,207, 1],
|
||||
[ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
|
||||
[ 1,333, 0,336, 0,340, 0,345, 0,351, 0,358, 0,366, 1],
|
||||
[ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
|
||||
[ 1,376, 0,378, 0,381, 0,385, 0, 35, 0, 37, 0, 39, 1],
|
||||
[ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
|
||||
[ 1, 31, 0, 32, 0, 33, 0, 34, 0, 36, 0, 38, 0, 40, 1],
|
||||
[ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
|
||||
[ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
|
||||
[ 1, 0, 0, 0, 0, 0, 0, 87, 0, 0, 0, 0, 0, 0, 1],
|
||||
[ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
|
||||
],
|
||||
"bgmap": [
|
||||
|
||||
],
|
||||
"fgmap": [
|
||||
|
||||
],
|
||||
"bg2map": [
|
||||
|
||||
],
|
||||
"fg2map": [
|
||||
|
||||
]
|
||||
}
|
@ -572,6 +572,16 @@ var maps_90f36752_8815_4be8_b32b_d7fad1d0542e =
|
||||
"641": {"cls":"items","id":"I641"},
|
||||
"642": {"cls":"items","id":"I642"},
|
||||
"643": {"cls":"enemys","id":"E643"},
|
||||
"10185": {"cls":"tileset","id":"X10185","canPass":true},
|
||||
"10186": {"cls":"tileset","id":"X10186","canPass":true},
|
||||
"10187": {"cls":"tileset","id":"X10187","canPass":true},
|
||||
"10188": {"cls":"tileset","id":"X10188","canPass":true},
|
||||
"10189": {"cls":"tileset","id":"X10189","canPass":true},
|
||||
"10193": {"cls":"tileset","id":"X10193","canPass":true},
|
||||
"10194": {"cls":"tileset","id":"X10194","canPass":true},
|
||||
"10195": {"cls":"tileset","id":"X10195","canPass":true},
|
||||
"10196": {"cls":"tileset","id":"X10196","canPass":true},
|
||||
"10197": {"cls":"tileset","id":"X10197","canPass":true},
|
||||
"20032": {"cls":"tileset","id":"X20032","cannotOut":["up","left"],"cannotIn":["up","left"]},
|
||||
"20033": {"cls":"tileset","id":"X20033","cannotOut":["up"],"cannotIn":["up"]},
|
||||
"20034": {"cls":"tileset","id":"X20034","cannotOut":["up","right"],"cannotIn":["up","right"]},
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { Ticker } from 'mutate-animate';
|
||||
import { Animation, Ticker, hyper } from 'mutate-animate';
|
||||
import { ensureArray } from '../utils';
|
||||
|
||||
const isWebGLSupported = (() => {
|
||||
return !!document.createElement('canvas').getContext('webgl');
|
||||
@ -29,6 +30,32 @@ interface MixedImage {
|
||||
update(): void;
|
||||
}
|
||||
|
||||
type UniformBinderNum = 1 | 2 | 3 | 4;
|
||||
type UniformBinderType = 'f' | 'i';
|
||||
type UniformFunc<
|
||||
N extends UniformBinderNum,
|
||||
T extends UniformBinderType,
|
||||
V extends 'v' | ''
|
||||
> = `uniform${N}${T}${V}`;
|
||||
|
||||
type UniformBinderValue<N extends UniformBinderNum> = N extends 1
|
||||
? number
|
||||
: N extends 2
|
||||
? [number, number]
|
||||
: N extends 3
|
||||
? [number, number, number]
|
||||
: [number, number, number, number];
|
||||
|
||||
interface UniformBinder<
|
||||
N extends UniformBinderNum,
|
||||
T extends UniformBinderType,
|
||||
V extends 'v' | ''
|
||||
> {
|
||||
value: UniformBinderValue<N>;
|
||||
set(value: UniformBinderValue<N>): void;
|
||||
get(): UniformBinderValue<N>;
|
||||
}
|
||||
|
||||
export default function init() {
|
||||
return {
|
||||
ShaderEffect,
|
||||
@ -37,7 +64,12 @@ export default function init() {
|
||||
shaderSample1: sample1,
|
||||
shaderSample2: sample2,
|
||||
shaderSample3: sample3,
|
||||
shaderSample4: sample4
|
||||
shaderSample4: sample4,
|
||||
shaderSample5: sample5,
|
||||
shaderSample6: sample6,
|
||||
shaderSample7: sample7,
|
||||
shaderSample8: sample8,
|
||||
shaderSample9: sample9
|
||||
};
|
||||
}
|
||||
|
||||
@ -97,6 +129,170 @@ const sample4 = buildSample(
|
||||
`
|
||||
);
|
||||
|
||||
const sample5 = buildAnimtedSample(
|
||||
['bg', 'bg2', 'event', 'fg', 'fg2', 'hero'],
|
||||
`
|
||||
uniform float uGrayscale;
|
||||
|
||||
void main() {
|
||||
vec4 rgba = texture2D(uSampler, vTextureCoord);
|
||||
float avr = (rgba.r + rgba.g + rgba.b) / 3.0;
|
||||
float dr = (rgba.r - avr) * (1.0 - uGrayscale);
|
||||
float dg = (rgba.g - avr) * (1.0 - uGrayscale);
|
||||
float db = (rgba.b - avr) * (1.0 - uGrayscale);
|
||||
|
||||
gl_FragColor = vec4(avr + dr, avr + dg, avr + db, rgba.a);
|
||||
}`,
|
||||
effect => {
|
||||
const binder = effect.createUniformBinder('uGrayscale', 1, 'f', '');
|
||||
binder.set(0);
|
||||
const ani = new Animation();
|
||||
ani.register('grayscale', 0);
|
||||
ani.time(5000)
|
||||
.mode(hyper('sin', 'in-out'))
|
||||
.absolute()
|
||||
.apply('grayscale', 1);
|
||||
ani.ticker.add(() => binder.set(ani.value.grayscale));
|
||||
|
||||
return [ani];
|
||||
}
|
||||
);
|
||||
|
||||
const sample6 = buildAnimtedSample(
|
||||
['bg', 'bg2', 'event', 'fg', 'fg2', 'hero'],
|
||||
`
|
||||
uniform float uOffset;
|
||||
|
||||
float noise(float x) {
|
||||
float y = fract(sin(x) * 100000.0);
|
||||
return y;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 rgba = texture2D(uSampler, vTextureCoord);
|
||||
float n = noise(rgba.r + rgba.g + rgba.b + uOffset) / 10.0;
|
||||
|
||||
gl_FragColor = vec4(rgba.rgb + n, rgba.a);
|
||||
}
|
||||
`,
|
||||
effect => {
|
||||
const binder = effect.createUniformBinder('uOffset', 1, 'f', '');
|
||||
binder.set(0);
|
||||
const ani = new Animation();
|
||||
ani.ticker.add(() => binder.set(binder.get() + 0.001));
|
||||
|
||||
return [ani];
|
||||
}
|
||||
);
|
||||
|
||||
const sample7 = buildAnimtedSample(
|
||||
['bg', 'bg2', 'event', 'fg', 'fg2', 'hero'],
|
||||
`
|
||||
uniform float uOffset;
|
||||
|
||||
float noise(float x) {
|
||||
float y = fract(sin(x) * 100000.0);
|
||||
return y;
|
||||
}
|
||||
|
||||
void main() {
|
||||
float brigtness = -0.1 + noise(uOffset) / 50.0;
|
||||
vec2 xy = vTextureCoord;
|
||||
float x = xy.x + noise(xy.y + uOffset) / 100.0;
|
||||
float y = xy.y;
|
||||
vec4 color = texture2D(uSampler, vec2(x, y));
|
||||
vec4 color1 = vec4(color.rgb + vec3(brigtness), color.a);
|
||||
|
||||
gl_FragColor = color1;
|
||||
}
|
||||
`,
|
||||
effect => {
|
||||
const binder = effect.createUniformBinder('uOffset', 1, 'f', '');
|
||||
binder.set(0);
|
||||
const ani = new Animation();
|
||||
ani.ticker.add(() => binder.set(binder.get() + 0.001));
|
||||
|
||||
return [ani];
|
||||
}
|
||||
);
|
||||
|
||||
const sample8 = buildAnimtedSample(
|
||||
['bg', 'bg2', 'event', 'fg', 'fg2', 'hero'],
|
||||
`
|
||||
uniform float uStrength;
|
||||
varying vec4 vpos;
|
||||
|
||||
void main() {
|
||||
float alpha = clamp(distance(vec2(0, 0), vpos.xy) - 0.6, 0.0, 1.0) * uStrength;
|
||||
vec4 tex = texture2D(uSampler, vTextureCoord);
|
||||
gl_FragColor = vec4(color1.rgb * (1.0 - alpha), 1.0);
|
||||
}
|
||||
`,
|
||||
effect => {
|
||||
const binder = effect.createUniformBinder('uStrength', 1, 'f', '');
|
||||
binder.set(0);
|
||||
const ani = new Animation();
|
||||
ani.ticker.add(time => {
|
||||
binder.set((Math.sin(time / 2000 - Math.PI / 2) + 1) / 2);
|
||||
});
|
||||
|
||||
return [ani];
|
||||
},
|
||||
`
|
||||
varying vec4 vpos;
|
||||
|
||||
void main() {
|
||||
vTextureCoord = aTextureCoord;
|
||||
vpos = aVertexPosition;
|
||||
gl_Position = aVertexPosition;
|
||||
}
|
||||
`
|
||||
);
|
||||
|
||||
const sample9 = buildAnimtedSample(
|
||||
['bg', 'bg2', 'event', 'fg', 'fg2', 'hero'],
|
||||
`
|
||||
uniform float uStrength;
|
||||
varying vec4 vpos;
|
||||
|
||||
float noise(float x) {
|
||||
float y = fract(sin(x) * 100000.0);
|
||||
return y;
|
||||
}
|
||||
|
||||
void main() {
|
||||
float brigtness = -uStrength / 10.0;
|
||||
vec2 xy = vTextureCoord;
|
||||
float x = xy.x + noise(xy.y + uStrength + 1.0) / 300.0 * uStrength;
|
||||
float y = xy.y;
|
||||
vec4 color = texture2D(uSampler, vec2(x, y));
|
||||
vec4 color1 = vec4(color.rgb + vec3(brigtness), color.a);
|
||||
|
||||
float alpha = clamp(distance(vec2(0, 0), vpos.xy) - 0.6, 0.0, 1.0) * uStrength;
|
||||
gl_FragColor = vec4(color1.rgb * (1.0 - alpha), 1.0);
|
||||
}
|
||||
`,
|
||||
effect => {
|
||||
const binder = effect.createUniformBinder('uStrength', 1, 'f', '');
|
||||
binder.set(0);
|
||||
const ani = new Animation();
|
||||
ani.ticker.add(time => {
|
||||
binder.set((Math.sin(time / 2000 - Math.PI / 2) + 1) / 2);
|
||||
});
|
||||
|
||||
return [ani];
|
||||
},
|
||||
`
|
||||
varying vec4 vpos;
|
||||
|
||||
void main() {
|
||||
vTextureCoord = aTextureCoord;
|
||||
vpos = aVertexPosition;
|
||||
gl_Position = aVertexPosition;
|
||||
}
|
||||
`
|
||||
);
|
||||
|
||||
function buildSample(canvas: string[], fs: string) {
|
||||
return () => {
|
||||
const effect = new ShaderEffect([0, 0, 0, 0]);
|
||||
@ -117,6 +313,35 @@ function buildSample(canvas: string[], fs: string) {
|
||||
};
|
||||
}
|
||||
|
||||
function buildAnimtedSample(
|
||||
canvas: string[],
|
||||
fs: string,
|
||||
bind: (effect: ShaderEffect) => Animation[],
|
||||
vs?: string
|
||||
) {
|
||||
return () => {
|
||||
const effect = new ShaderEffect([0, 0, 0, 0]);
|
||||
effect.baseImage(...canvas.map(v => core.canvas[v].canvas));
|
||||
effect.vs(vs ?? ShaderEffect.defaultVs);
|
||||
effect.fs(fs);
|
||||
effect.compile();
|
||||
|
||||
const anis = bind(effect);
|
||||
|
||||
effect.update();
|
||||
const ticker = setTickerFor(effect);
|
||||
const manager = replaceGameCanvas(effect, canvas);
|
||||
|
||||
return {
|
||||
end() {
|
||||
ticker.destroy();
|
||||
manager.remove();
|
||||
anis.forEach(v => v.ticker.destroy());
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const builtinVs = `
|
||||
#ifdef GL_ES
|
||||
precision highp float;
|
||||
@ -189,25 +414,31 @@ export class ShaderEffect {
|
||||
* @param compile 是否重新编译着色器脚本,并重新创建纹理
|
||||
*/
|
||||
update(compile: boolean = false) {
|
||||
const gl = this.gl;
|
||||
if (compile) {
|
||||
gl.deleteProgram(this.program);
|
||||
gl.deleteTexture(this.texture);
|
||||
gl.deleteBuffer(this.buffer?.position ?? null);
|
||||
gl.deleteBuffer(this.buffer?.texture ?? null);
|
||||
gl.deleteShader(this.shader?.vertex ?? null);
|
||||
gl.deleteShader(this.shader?.fragment ?? null);
|
||||
|
||||
this.program = this.createProgram();
|
||||
this.programInfo = this.getProgramInfo();
|
||||
this.buffer = this.initBuffers();
|
||||
this.texture = this.createTexture();
|
||||
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
|
||||
}
|
||||
if (compile) this.compile();
|
||||
this.textureCanvas?.update();
|
||||
this.drawScene();
|
||||
}
|
||||
|
||||
/**
|
||||
* 仅重新编译着色器,不进行纹理创建和特效渲染
|
||||
*/
|
||||
compile() {
|
||||
const gl = this.gl;
|
||||
gl.deleteProgram(this.program);
|
||||
gl.deleteTexture(this.texture);
|
||||
gl.deleteBuffer(this.buffer?.position ?? null);
|
||||
gl.deleteBuffer(this.buffer?.texture ?? null);
|
||||
gl.deleteShader(this.shader?.vertex ?? null);
|
||||
gl.deleteShader(this.shader?.fragment ?? null);
|
||||
|
||||
this.program = this.createProgram();
|
||||
this.programInfo = this.getProgramInfo();
|
||||
this.buffer = this.initBuffers();
|
||||
this.texture = this.createTexture();
|
||||
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
|
||||
gl.useProgram(this.program);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置顶点着色器,使用 glsl 编写,插件提供了一些新的 api
|
||||
* 着色器中必须包含 main 函数,同时为 gl_Position 赋值
|
||||
@ -265,6 +496,64 @@ export class ShaderEffect {
|
||||
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个全局变量绑定器,用于操作全局变量
|
||||
* @param uniform 全局变量的变量名
|
||||
* @param num 变量的元素数量,float和int视为1,vec2 vec3 vec4分别视为 2 3 4
|
||||
* @param type 数据类型,可以填'f',表示浮点型,或者填'i',表示整型
|
||||
* @param vector 是否为向量,可以填'v',表示是向量,或者填'',表示不是向量
|
||||
* @returns 一个uniform绑定器,用于操作全局变量uniform
|
||||
*/
|
||||
createUniformBinder<
|
||||
N extends UniformBinderNum,
|
||||
T extends UniformBinderType,
|
||||
V extends 'v' | ''
|
||||
>(uniform: string, num: N, type: T, vector: V): UniformBinder<N, T, V> {
|
||||
if (!this.program) {
|
||||
throw new Error(
|
||||
`Uniform binder should be use when the program initialized.`
|
||||
);
|
||||
}
|
||||
|
||||
const suffix = `${num}${type}${vector ? 'v' : ''}`;
|
||||
const func = `uniform${suffix}` as UniformFunc<N, T, V>;
|
||||
const value = (
|
||||
num === 1 ? 0 : Array(num).fill(0)
|
||||
) as UniformBinderValue<N>;
|
||||
|
||||
const loc = this.gl.getUniformLocation(this.program, uniform);
|
||||
const gl = this.gl;
|
||||
|
||||
return {
|
||||
value,
|
||||
set(value) {
|
||||
this.value = value;
|
||||
let v;
|
||||
if (vector === 'v') {
|
||||
let _v = ensureArray(value);
|
||||
if (type === 'f') {
|
||||
v = new Float32Array(_v);
|
||||
} else {
|
||||
v = new Int32Array(_v);
|
||||
}
|
||||
} else {
|
||||
v = ensureArray(value);
|
||||
}
|
||||
// 对uniform赋值
|
||||
if (vector === 'v') {
|
||||
// @ts-ignore
|
||||
gl[func](loc, v);
|
||||
} else {
|
||||
// @ts-ignore
|
||||
gl[func](loc, ...v);
|
||||
}
|
||||
},
|
||||
get() {
|
||||
return this.value;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private createProgram() {
|
||||
const gl = this.gl;
|
||||
const vs = this.loadShader(gl.VERTEX_SHADER, this.vsSource);
|
||||
|
@ -228,3 +228,10 @@ export function changeLocalStorage<T>(
|
||||
const to = fn(now);
|
||||
core.setLocalStorage(name, to);
|
||||
}
|
||||
|
||||
export function ensureArray<T extends any>(
|
||||
value: T
|
||||
): T extends any[] ? T : T[] {
|
||||
// @ts-ignore
|
||||
return value instanceof Array ? value : [value];
|
||||
}
|
||||
|
10
src/source/cls.d.ts
vendored
10
src/source/cls.d.ts
vendored
@ -571,6 +571,16 @@ interface IdToCls {
|
||||
I641: 'items';
|
||||
I642: 'items';
|
||||
E643: 'enemys';
|
||||
X10185: 'tileset';
|
||||
X10186: 'tileset';
|
||||
X10187: 'tileset';
|
||||
X10188: 'tileset';
|
||||
X10189: 'tileset';
|
||||
X10193: 'tileset';
|
||||
X10194: 'tileset';
|
||||
X10195: 'tileset';
|
||||
X10196: 'tileset';
|
||||
X10197: 'tileset';
|
||||
X20032: 'tileset';
|
||||
X20033: 'tileset';
|
||||
X20034: 'tileset';
|
||||
|
20
src/source/maps.d.ts
vendored
20
src/source/maps.d.ts
vendored
@ -571,6 +571,16 @@ interface IdToNumber {
|
||||
I641: 641;
|
||||
I642: 642;
|
||||
E643: 643;
|
||||
X10185: 10185;
|
||||
X10186: 10186;
|
||||
X10187: 10187;
|
||||
X10188: 10188;
|
||||
X10189: 10189;
|
||||
X10193: 10193;
|
||||
X10194: 10194;
|
||||
X10195: 10195;
|
||||
X10196: 10196;
|
||||
X10197: 10197;
|
||||
X20032: 20032;
|
||||
X20033: 20033;
|
||||
X20034: 20034;
|
||||
@ -1225,6 +1235,16 @@ interface NumberToId {
|
||||
641: 'I641';
|
||||
642: 'I642';
|
||||
643: 'E643';
|
||||
10185: 'X10185';
|
||||
10186: 'X10186';
|
||||
10187: 'X10187';
|
||||
10188: 'X10188';
|
||||
10189: 'X10189';
|
||||
10193: 'X10193';
|
||||
10194: 'X10194';
|
||||
10195: 'X10195';
|
||||
10196: 'X10196';
|
||||
10197: 'X10197';
|
||||
20032: 'X20032';
|
||||
20033: 'X20033';
|
||||
20034: 'X20034';
|
||||
|
Loading…
Reference in New Issue
Block a user