Yes Yes Yes and Yes
I can confirm, it is working greatly now!
That seems I wonβt be able to do this with shaders. Letβs see who else kick-in with their experience
1 Like
After getting more into Shaders, I was able to solve it:
Fog of War Shader is for WebGL2 only.
Also I wanted to share my old Shader (only WebGL1) for i.e. RTS/RPG Entity Selection Circles:
1 Like
Just for anyone wanting to use a plugin instead I have made one here:
type RevealerData = {
position:Vector2;
range:float;
}
export class FogOfWarPluginMaterial extends MaterialPluginBase {
static maxRevealers = 1000;
static revealerData:RevealerData[] = [];
static maxRevealerRange = 0;
static resetRevealers() {
this.revealerData = [];
this.maxRevealerRange = 0;
}
static addRevealer(newRevealer:Vector2, range:number) {
if(this.revealerData.length > this.maxRevealers) {
console.error("Too many revealers added!");
}
if(range > this.maxRevealerRange) {
this.maxRevealerRange = range;
}
this.revealerData.push({range:range,position:newRevealer});
}
static getRevealerData():{revealerPositions:number[],revealerRanges:number[]} {
this.revealerData.sort((a, b) => a.position.x - b.position.x);
const revealerPositions:number[] = new Array(FogOfWarPluginMaterial.maxRevealers*2).fill(0);;
const revealerRanges:number[] = new Array(FogOfWarPluginMaterial.maxRevealers).fill(0);;
for(var i = 0; i < this.revealerData.length;i++){
const data = this.revealerData[i];
const revealerId = i*2;
revealerPositions[revealerId] = data.position.x;
revealerPositions[revealerId + 1] = data.position.y;
revealerRanges[i] = data.range;
}
return {
revealerPositions:revealerPositions,
revealerRanges:revealerRanges
}
}
_isEnabled = false;
constructor(material:Material) {
// last parameter is a priority, which lets you define the order multiple plugins are run.
super(material, "FogOfWar", 200, { "FogOfWar": false });
this.isEnabled = true;
}
get isEnabled() {
return this._isEnabled;
}
set isEnabled(enabled) {
if (this._isEnabled === enabled) {
return;
}
this._isEnabled = enabled;
this.markAllDefinesAsDirty();
this._enable(this._isEnabled);
}
prepareDefines(defines:any, scene:Scene, mesh:Mesh) {
defines["FogOfWar"] = this._isEnabled;
}
getClassName() {
return "FogOfWarPluginMaterial";
}
getUniforms() {
return {
"ubo": [
{ name: "revealers", size: 1, type: "float", arraySize: 2 * FogOfWarPluginMaterial.maxRevealers },
{ name: "ranges", size: 1, type: "float", arraySize: FogOfWarPluginMaterial.maxRevealers },
{ name: "maxRevealerRange", size: 1, type: "float" },
{ name: "revealersCount", size: 1, type: "highp int" }
],
"fragment":
`#ifdef FogOfWar
uniform float revealers[${FogOfWarPluginMaterial.maxRevealers}];
uniform float ranges[${FogOfWarPluginMaterial.maxRevealers}];
uniform highp int revealersCount;
uniform float maxRevealerRange;
#endif`,
};
}
bindForSubMesh(uniformBuffer:any, scene:any, engine:any, subMesh:any) {
if (this._isEnabled) {
const revealerData = FogOfWarPluginMaterial.getRevealerData();
uniformBuffer.updateFloat("maxRevealerRange", FogOfWarPluginMaterial.maxRevealerRange);
uniformBuffer.updateArray("revealers", revealerData.revealerPositions);
uniformBuffer.updateArray("ranges", revealerData.revealerRanges);
uniformBuffer.updateInt("revealersCount", FogOfWarPluginMaterial.revealerData.length);
}
}
getCustomCode(shaderType:any) {
if (shaderType === "vertex") {
return {
CUSTOM_VERTEX_DEFINITIONS: `
varying vec3 vWorldPos;
`,
CUSTOM_VERTEX_MAIN_END: `
vWorldPos = worldPos.xyz;
`
}
}
if (shaderType === "fragment") {
return {
CUSTOM_FRAGMENT_DEFINITIONS: `
varying vec3 vWorldPos;
`,
CUSTOM_FRAGMENT_MAIN_END: `
float fogless = 0.4;
for(int i = 0; i < revealersCount; i++) {
int revealersId = i*2;
//Preprocess efficiency step
float xDist = vWorldPos.x - revealers[revealersId];
//Break if dist too great as positions ordered by X value
if(xDist < -maxRevealerRange) {
break;
}
//x dist too large?
float maxRange = ranges[i];
if(xDist > maxRange || xDist < -maxRange) {
continue;
}
float distance = length(vWorldPos.xz - vec2(revealers[revealersId],revealers[revealersId+1]));
float tmpFogless = (maxRange - distance) / ranges[i];
tmpFogless = clamp(tmpFogless, 0.0, 1.0);
if(tmpFogless > 0.1) {
tmpFogless = 1.0;
} else if(tmpFogless > 0.0) {
tmpFogless = tmpFogless/0.1;
}
if(tmpFogless > fogless) {
fogless = tmpFogless;
}
}
gl_FragColor.rgb *= vec3(fogless);
`
};
}
return null;
}
}
4 Likes