@babylonjs/core
Version:
Getting started? Play directly with the Babylon.js API using our [playground](https://playground.babylonjs.com/). It also contains a lot of samples to learn how to use it.
200 lines (189 loc) • 8.07 kB
JavaScript
import { __decorate } from "../../../tslib.es6.js";
import { NodeMaterialBlock } from "../nodeMaterialBlock.js";
import { NodeMaterialBlockConnectionPointTypes } from "../Enums/nodeMaterialBlockConnectionPointTypes.js";
import { NodeMaterialBlockTargets } from "../Enums/nodeMaterialBlockTargets.js";
import { RegisterClass } from "../../../Misc/typeStore.js";
import { editableInPropertyPage } from "../../../Decorators/nodeDecorator.js";
/**
* block used to Generate Fractal Brownian Motion Clouds
*/
export class CloudBlock extends NodeMaterialBlock {
/**
* Creates a new CloudBlock
* @param name defines the block name
*/
constructor(name) {
super(name, NodeMaterialBlockTargets.Neutral);
/** Gets or sets the number of octaves */
this.octaves = 6.0;
this.registerInput("seed", NodeMaterialBlockConnectionPointTypes.AutoDetect);
this.registerInput("chaos", NodeMaterialBlockConnectionPointTypes.AutoDetect, true);
this.registerInput("offsetX", NodeMaterialBlockConnectionPointTypes.Float, true);
this.registerInput("offsetY", NodeMaterialBlockConnectionPointTypes.Float, true);
this.registerInput("offsetZ", NodeMaterialBlockConnectionPointTypes.Float, true);
this.registerOutput("output", NodeMaterialBlockConnectionPointTypes.Float);
this._inputs[0].acceptedConnectionPointTypes.push(NodeMaterialBlockConnectionPointTypes.Vector2);
this._inputs[0].acceptedConnectionPointTypes.push(NodeMaterialBlockConnectionPointTypes.Vector3);
this._linkConnectionTypes(0, 1);
}
/**
* Gets the current class name
* @returns the class name
*/
getClassName() {
return "CloudBlock";
}
/**
* Gets the seed input component
*/
get seed() {
return this._inputs[0];
}
/**
* Gets the chaos input component
*/
get chaos() {
return this._inputs[1];
}
/**
* Gets the offset X input component
*/
get offsetX() {
return this._inputs[2];
}
/**
* Gets the offset Y input component
*/
get offsetY() {
return this._inputs[3];
}
/**
* Gets the offset Z input component
*/
get offsetZ() {
return this._inputs[4];
}
/**
* Gets the output component
*/
get output() {
return this._outputs[0];
}
_buildBlock(state) {
super._buildBlock(state);
if (!this.seed.isConnected) {
return;
}
if (!this._outputs[0].hasEndpoints) {
return;
}
let functionString = `
float cloudRandom(float p) {
float temp = fract(p * 0.011);
temp *= temp + 7.5;
temp *= temp + temp;
return fract(temp);
}
// Based on Morgan McGuire @morgan3d
// https://www.shadertoy.com/view/4dS3Wd
float cloudNoise2(vec2 x, vec2 chaos) {
vec2 step = chaos * vec2(75., 120.) + vec2(75., 120.);
vec2 i = floor(x);
vec2 f = fract(x);
float n = dot(i, step);
vec2 u = f * f * (3.0 - 2.0 * f);
return mix(
mix(cloudRandom(n + dot(step, vec2(0, 0))), cloudRandom(n + dot(step, vec2(1, 0))), u.x),
mix(cloudRandom(n + dot(step, vec2(0, 1))), cloudRandom(n + dot(step, vec2(1, 1))), u.x),
u.y
);
}
float cloudNoise3(vec3 x, vec3 chaos) {
vec3 step = chaos * vec3(60., 120., 75.) + vec3(60., 120., 75.);
vec3 i = floor(x);
vec3 f = fract(x);
float n = dot(i, step);
vec3 u = f * f * (3.0 - 2.0 * f);
return mix(mix(mix( cloudRandom(n + dot(step, vec3(0, 0, 0))), cloudRandom(n + dot(step, vec3(1, 0, 0))), u.x),
mix( cloudRandom(n + dot(step, vec3(0, 1, 0))), cloudRandom(n + dot(step, vec3(1, 1, 0))), u.x), u.y),
mix(mix( cloudRandom(n + dot(step, vec3(0, 0, 1))), cloudRandom(n + dot(step, vec3(1, 0, 1))), u.x),
mix( cloudRandom(n + dot(step, vec3(0, 1, 1))), cloudRandom(n + dot(step, vec3(1, 1, 1))), u.x), u.y), u.z);
}`;
let fractalBrownianString = `
float fbm2(vec2 st, vec2 chaos) {
// Initial values
float value = 0.0;
float amplitude = .5;
float frequency = 0.;
// Loop of octaves
vec2 tempST = st;
for (int i = 0; i < OCTAVES; i++) {
value += amplitude * cloudNoise2(tempST, chaos);
tempST *= 2.0;
amplitude *= 0.5;
}
return value;
}
float fbm3(vec3 x, vec3 chaos) {
// Initial values
float value = 0.0;
float amplitude = 0.5;
vec3 tempX = x;
for (int i = 0; i < OCTAVES; i++) {
value += amplitude * cloudNoise3(tempX, chaos);
tempX = tempX * 2.0;
amplitude *= 0.5;
}
return value;
}`;
if (state.shaderLanguage === 1 /* ShaderLanguage.WGSL */) {
functionString = state._babylonSLtoWGSL(functionString);
fractalBrownianString = state._babylonSLtoWGSL(fractalBrownianString);
}
const fbmNewName = `fbm${this.octaves}`;
state._emitFunction("CloudBlockCode", functionString, "// CloudBlockCode");
state._emitFunction("CloudBlockCodeFBM" + this.octaves, fractalBrownianString.replace(/fbm/gi, fbmNewName).replace(/OCTAVES/gi, (this.octaves | 0).toString()), "// CloudBlockCode FBM");
const localVariable = state._getFreeVariableName("st");
const seedType = this.seed.connectedPoint?.type || NodeMaterialBlockConnectionPointTypes.Vector3;
state.compilationString += `${state._declareLocalVar(localVariable, seedType)} = ${this.seed.associatedVariableName};\n`;
if (this.offsetX.isConnected) {
state.compilationString += `${localVariable}.x += 0.1 * ${this.offsetX.associatedVariableName};\n`;
}
if (this.offsetY.isConnected) {
state.compilationString += `${localVariable}.y += 0.1 * ${this.offsetY.associatedVariableName};\n`;
}
if (this.offsetZ.isConnected && seedType === NodeMaterialBlockConnectionPointTypes.Vector3) {
state.compilationString += `${localVariable}.z += 0.1 * ${this.offsetZ.associatedVariableName};\n`;
}
let chaosValue = "";
if (this.chaos.isConnected) {
chaosValue = this.chaos.associatedVariableName;
}
else {
const addF = state.fSuffix;
chaosValue = this.seed.connectedPoint?.type === NodeMaterialBlockConnectionPointTypes.Vector2 ? `vec2${addF}(0., 0.)` : `vec3${addF}(0., 0., 0.)`;
}
state.compilationString +=
state._declareOutput(this._outputs[0]) +
` = ${fbmNewName}${this.seed.connectedPoint?.type === NodeMaterialBlockConnectionPointTypes.Vector2 ? "2" : "3"}(${localVariable}, ${chaosValue});\n`;
return this;
}
_dumpPropertiesCode() {
const codeString = super._dumpPropertiesCode() + `${this._codeVariableName}.octaves = ${this.octaves};\n`;
return codeString;
}
serialize() {
const serializationObject = super.serialize();
serializationObject.octaves = this.octaves;
return serializationObject;
}
_deserialize(serializationObject, scene, rootUrl) {
super._deserialize(serializationObject, scene, rootUrl);
this.octaves = serializationObject.octaves;
}
}
__decorate([
editableInPropertyPage("Octaves", 2 /* PropertyTypeForEdition.Int */, undefined, { embedded: true })
], CloudBlock.prototype, "octaves", void 0);
RegisterClass("BABYLON.CloudBlock", CloudBlock);
//# sourceMappingURL=cloudBlock.js.map