///
module BABYLON {
class GridMaterialDefines extends MaterialDefines {
public OPACITY = false;
public TRANSPARENT = false;
public FOG = false;
public PREMULTIPLYALPHA = false;
public UV1 = false;
public UV2 = false;
constructor() {
super();
this.rebuild();
}
}
/**
* The grid materials allows you to wrap any shape with a grid.
* Colors are customizable.
*/
export class GridMaterial extends BABYLON.PushMaterial {
/**
* Main color of the grid (e.g. between lines)
*/
@serializeAsColor3()
public mainColor = Color3.Black();
/**
* Color of the grid lines.
*/
@serializeAsColor3()
public lineColor = Color3.Teal();
/**
* The scale of the grid compared to unit.
*/
@serialize()
public gridRatio = 1.0;
/**
* Allows setting an offset for the grid lines.
*/
@serializeAsColor3()
public gridOffset = Vector3.Zero();
/**
* The frequency of thicker lines.
*/
@serialize()
public majorUnitFrequency = 10;
/**
* The visibility of minor units in the grid.
*/
@serialize()
public minorUnitVisibility = 0.33;
/**
* The grid opacity outside of the lines.
*/
@serialize()
public opacity = 1.0;
/**
* Determine RBG output is premultiplied by alpha value.
*/
@serialize()
public preMultiplyAlpha = false;
@serializeAsTexture("opacityTexture")
private _opacityTexture: BaseTexture;
@expandToProperty("_markAllSubMeshesAsTexturesDirty")
public opacityTexture: BaseTexture;
private _gridControl: Vector4 = new Vector4(this.gridRatio, this.majorUnitFrequency, this.minorUnitVisibility, this.opacity);
private _renderId: number;
/**
* constructor
* @param name The name given to the material in order to identify it afterwards.
* @param scene The scene the material is used in.
*/
constructor(name: string, scene: Scene) {
super(name, scene);
}
/**
* Returns wehter or not the grid requires alpha blending.
*/
public needAlphaBlending(): boolean {
return this.opacity < 1.0 || this._opacityTexture && this._opacityTexture.isReady();
}
public needAlphaBlendingForMesh(mesh: AbstractMesh): boolean {
return this.needAlphaBlending();
}
public isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances?: boolean): boolean {
if (this.isFrozen) {
if (this._wasPreviouslyReady && subMesh.effect) {
return true;
}
}
if (!subMesh._materialDefines) {
subMesh._materialDefines = new GridMaterialDefines();
}
var defines = subMesh._materialDefines;
var scene = this.getScene();
if (!this.checkReadyOnEveryCall && subMesh.effect) {
if (this._renderId === scene.getRenderId()) {
return true;
}
}
if (defines.TRANSPARENT !== (this.opacity < 1.0)) {
defines.TRANSPARENT = !defines.TRANSPARENT;
defines.markAsUnprocessed();
}
if (defines.PREMULTIPLYALPHA != this.preMultiplyAlpha) {
defines.PREMULTIPLYALPHA = !defines.PREMULTIPLYALPHA;
defines.markAsUnprocessed();
}
// Textures
if (defines._areTexturesDirty) {
defines._needUVs = false;
if (scene.texturesEnabled) {
if (this._opacityTexture && StandardMaterial.OpacityTextureEnabled) {
if (!this._opacityTexture.isReady()) {
return false;
} else {
defines._needUVs = true;
defines.OPACITY = true;
}
}
}
}
MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, false, this.fogEnabled, false, defines);
// Get correct effect
if (defines.isDirty) {
defines.markAsProcessed();
scene.resetCachedMaterial();
// Attribs
MaterialHelper.PrepareDefinesForAttributes(mesh, defines, false, false);
//Attributes
var attribs = [VertexBuffer.PositionKind, VertexBuffer.NormalKind];
if (defines.UV1) {
attribs.push(VertexBuffer.UVKind);
}
if (defines.UV2) {
attribs.push(VertexBuffer.UV2Kind);
}
// Defines
var join = defines.toString();
subMesh.setEffect(scene.getEngine().createEffect("grid",
attribs,
["projection", "worldView", "mainColor", "lineColor", "gridControl", "gridOffset", "vFogInfos", "vFogColor", "world", "view",
"opacityMatrix", "vOpacityInfos"],
["opacitySampler"],
join,
undefined,
this.onCompiled,
this.onError), defines);
}
if (!subMesh.effect || !subMesh.effect.isReady()) {
return false;
}
this._renderId = scene.getRenderId();
this._wasPreviouslyReady = true;
return true;
}
public bindForSubMesh(world: Matrix, mesh: Mesh, subMesh: SubMesh): void {
var scene = this.getScene();
var defines = subMesh._materialDefines;
if (!defines) {
return;
}
var effect = subMesh.effect;
if (!effect) {
return;
}
this._activeEffect = effect;
// Matrices
this.bindOnlyWorldMatrix(world);
this._activeEffect.setMatrix("worldView", world.multiply(scene.getViewMatrix()));
this._activeEffect.setMatrix("view", scene.getViewMatrix());
this._activeEffect.setMatrix("projection", scene.getProjectionMatrix());
// Uniforms
if (this._mustRebind(scene, effect)) {
this._activeEffect.setColor3("mainColor", this.mainColor);
this._activeEffect.setColor3("lineColor", this.lineColor);
this._activeEffect.setVector3("gridOffset", this.gridOffset);
this._gridControl.x = this.gridRatio;
this._gridControl.y = Math.round(this.majorUnitFrequency);
this._gridControl.z = this.minorUnitVisibility;
this._gridControl.w = this.opacity;
this._activeEffect.setVector4("gridControl", this._gridControl);
if (this._opacityTexture && StandardMaterial.OpacityTextureEnabled) {
this._activeEffect.setTexture("opacitySampler", this._opacityTexture);
this._activeEffect.setFloat2("vOpacityInfos", this._opacityTexture.coordinatesIndex, this._opacityTexture.level);
this._activeEffect.setMatrix("opacityMatrix", this._opacityTexture.getTextureMatrix());
}
}
// Fog
MaterialHelper.BindFogParameters(scene, mesh, this._activeEffect);
this._afterBind(mesh, this._activeEffect);
}
public dispose(forceDisposeEffect?: boolean): void {
super.dispose(forceDisposeEffect);
}
public clone(name: string): GridMaterial {
return SerializationHelper.Clone(() => new GridMaterial(name, this.getScene()), this);
}
public serialize(): any {
var serializationObject = SerializationHelper.Serialize(this);
serializationObject.customType = "BABYLON.GridMaterial";
return serializationObject;
}
public getClassName(): string {
return "GridMaterial";
}
public static Parse(source: any, scene: Scene, rootUrl: string): GridMaterial {
return SerializationHelper.Parse(() => new GridMaterial(source.name, scene), source, scene, rootUrl);
}
}
}