Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
487 lines (425 sloc) 10.7 KB
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html" charset="utf-8"/>
<title>Section II - Uniforms and UI</title>
<script src="https://cdn.babylonjs.com/babylon.js"></script>
<style>
html, body {
overflow: hidden;
width : 100%;
height : 100%;
margin : 0;
padding : 0;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
*, *:before, *:after {
-webkit-box-sizing: inherit;
-moz-box-sizing: inherit;
box-sizing: inherit;
}
#renderCanvas {
width : 100%;
height : 100%;
touch-action: none;
}
.ui-block{
display:block;
position:absolute;
left:0;
top:0;
z-index:10001;
background:rgba(150,150,150,0.5);
width:240px;
font-size:16px;
font-family: Arial, Helvetica, sans-serif;
}
.ui-item{
display:block;
position:relative;
padding:0.2em 0.5em;
}
.ui-in-block{
display:inline-block;
width:60%;
white-space:nowrap;
}
.ui-in{
display:inline-block;
width:100%;
}
.ui-in-vec2{
width:50%;
}
.ui-in-vec3{
width:32.5%;
}
</style>
</head>
<body>
<canvas id="renderCanvas"></canvas>
<script>
SM = function(args, scene){
this.scene = scene;
args = args || {};
this.shaders.vx = args.vx || this.shaders.vx;
this.shaders.fx = args.fx || this.shaders.fx;
this.uniforms = args.uniforms || {};
this.uID = 'shader'+Date.now();
this.shader = null;
this.storeShader();
this.buildShader();
this.buildOutput();
this.buildGUI();
return this;
}
SM.prototype = {
getUniformsArray : function(){
var keys = Object.keys(this.uniforms);
return keys;
},
setUniformDefaults : function(){
var shader = this.shader;
var keys = this.getUniformsArray();
for(var i=0; i<keys.length; i++){
var u = this.uniforms[keys[i]];
var type = u.type;
var v = u.value;
shader[this.type2Method(type)](keys[i], v); // <== shader.setType( uniform, value );
}
},
type2Method : function(type){
var m;
switch(type){
case 'float': m ='setFloat'; break;
case 'vec2': m ='setVector2'; break;
case 'vec3': m ='setVector3'; break;
}
return m;
},
getShader : function(){
return this.shader;
},
buildGUI : function(){
this.ui = {
mainBlock : document.createElement('div'),
inputs : [],
};
this.ui.mainBlock.classList.add('ui-block');
var keys = this.getUniformsArray();
for(var i=0; i<keys.length; i++){
var u = this.uniforms[keys[i]];
if(!u.hasControl){continue;}
var _block = document.createElement('div');
_block.classList.add('ui-item');
var _title = document.createElement('span');
_title.innerHTML = keys[i]+":";
_block.appendChild(_title);
var _inBlock = document.createElement('span');
_inBlock.classList.add('ui-in-block');
var _inputs = [];
var _in;
if(u.type == 'float'){
_in = document.createElement('input');
_in.setAttribute('type', 'number');
_in.setAttribute('id', keys[i]);
_in.classList.add('ui-in-'+u.type, 'ui-in');
_in.value = u.value;
if(u.min){
_in.setAttribute('min', u.min.x);
}
if(u.max){
_in.setAttribute('max', u.max.x);
}
if(u.step){
_in.setAttribute('step', u.step.x);
}
_inputs.push(_in);
}
if(u.type == 'vec2' || u.type == 'vec3'){
_in = document.createElement('input');
_in.setAttribute('type', 'number');
_in.setAttribute('id', keys[i]+":x");
_in.classList.add('ui-in-'+u.type, 'ui-in');
_in.value = u.value.x;
if(u.min){
_in.setAttribute('min', u.min.x);
}
if(u.max){
_in.setAttribute('max', u.max.x);
}
if(u.step){
_in.setAttribute('step', u.step.x);
}
_inputs.push(_in);
_in = document.createElement('input');
_in.setAttribute('type', 'number');
_in.setAttribute('id', keys[i]+":y");
_in.classList.add('ui-in-'+u.type, 'ui-in');
_in.value = u.value.y;
if(u.min){
_in.setAttribute('min', u.min.y);
}
if(u.max){
_in.setAttribute('max', u.max.y);
}
if(u.step){
_in.setAttribute('step', u.step.y);
}
_inputs.push(_in);
}
if(u.type == 'vec3'){
_in = document.createElement('input');
_in.setAttribute('type', 'number');
_in.setAttribute('id', keys[i]+":z");
_in.classList.add('ui-in-'+u.type, 'ui-in');
_in.value = u.value.z;
if(u.min){
_in.setAttribute('min', u.min.z);
}
if(u.max){
_in.setAttribute('max', u.max.z);
}
if(u.step){
_in.setAttribute('step', u.step.z);
}
_inputs.push(_in);
}
for(var j=0; j<_inputs.length; j++){
_inBlock.appendChild(_inputs[j]);
}
_block.appendChild(_inBlock);
var _input = {
block : _block,
inputs : _inputs
};
this.ui.inputs.push(_input);
this.ui.mainBlock.appendChild(_input.block);
}
document.body.appendChild(this.ui.mainBlock);
var self = this;
function updateShaderValue(id, value){
if(id.length>1){
self.uniforms[id[0]].value[id[1]] = parseFloat(value);
if(id[1]=='vec2'){
(self.getShader()).setVector2(id[0], self.uniforms[id[0]].value);
}else if(id[1]=='vec3'){
(self.getShader()).setVector3(id[0], self.uniforms[id[0]].value);
}
}else{
self.uniforms[id[0]].value = parseFloat(value);
(self.getShader()).setFloat(id[0], self.uniforms[id[0]].value);
}
}
//BINDINGS//
this.ui.mainBlock.addEventListener('change', (e)=>{
var target = e.target;
var id = target.getAttribute('id').split(':');
var value = target.value;
updateShaderValue(id, value);
}, false);
},
buildOutput : function(){
if(this.output){this.output.dispose()}
var scene = this.scene;
var mesh = new BABYLON.Mesh('output', scene);
var vDat = new BABYLON.VertexData();
var c = scene.activeCamera;
var fov = c.fov;
var aspectRatio = scene._engine.getAspectRatio(c);
var d = c.position.length();
var h = 2 * d * Math.tan(fov / 2);
var w = h * aspectRatio;
vDat.positions =
[
w*-0.5, h*0.5, 0, //0
w*0.5, h*0.5, 0, //1
w*0.5, h*-0.5, 0, //2
w*-0.5, h*-0.5, 0 //3
];
vDat.uvs =
[
0,1,
1,1,
1,0,
0,0
];
vDat.normals =
[
0.0, 0.0, 1.0,//0
0.0, 0.0, 1.0,//1
0.0, 0.0, 1.0,//2
0.0, 0.0, 1.0 //3
];
vDat.indices =
[
2,1,0,
3,2,0
];
vDat.applyToMesh(mesh);
this.output = mesh;
if(this.shader){
this.output.material = this.shader;
}
},
buildShader : function(){
var scene = this.scene;
var uID = this.uID;
var _uniforms = ["world", "worldView", "worldViewProjection", "view", "projection"];
_uniforms = _uniforms.concat(this.getUniformsArray());
var shader = new BABYLON.ShaderMaterial("shader", scene, {
vertex: uID,
fragment: uID,
},{
attributes: ["position", "normal", "uv"],
uniforms: _uniforms
});
if(this.shader){this.shader.dispose();}
this.shader = shader;
this.setUniformDefaults();
if(this.output){
this.output.material = this.shader;
}
},
storeShader : function(){
BABYLON.Effect.ShadersStore[this.uID+'VertexShader'] = this.shaders.vx;
BABYLON.Effect.ShadersStore[this.uID+'FragmentShader'] = this.shaders.fx;
},
shaders:{
/*----TAB RESET FOR LITERALS-----*/
vx:
`precision highp float;
//Attributes
attribute vec3 position;
attribute vec2 uv;
// Uniforms
uniform mat4 worldViewProjection;
//Varyings
varying vec2 vUV;
varying vec2 tUV;
void main(void) {
vec4 p = vec4( position, 1. );
gl_Position = worldViewProjection * p;
vUV = uv;
tUV = uv*2.0-1.0;
}`,
fx :
`precision highp float;
//Varyings
varying vec2 vUV;
varying vec2 tUV;
void main(void) {
vec3 color = vec3(1.,1.,1.);
gl_FragColor = vec4(color, 1.0);
}`
}//End Shaders
}
var sm;
window.addEventListener('DOMContentLoaded', function(){
var canvas = document.getElementById('renderCanvas');
var engine = new BABYLON.Engine(canvas, true);
var createScene = function(){
var scene = new BABYLON.Scene(engine);
var camera = new BABYLON.FreeCamera('camera1', new BABYLON.Vector3(0, 0, -1), scene);
camera.setTarget(BABYLON.Vector3.Zero());
scene.clearColor = new BABYLON.Color3(1,0,0);
/*----TAB RESET FOR LITERALS-----*/
sm = new SM(
{
uniforms:{
brickCounts : {
type : 'vec2',
value : new BABYLON.Vector2(6,12),
min : new BABYLON.Vector2(1,1),
step : new BABYLON.Vector2(1,1),
hasControl : true
},
mortarSize : {
type: 'float',
value : 0.1,
min: 0.0001,
max: 0.9999,
step: 0.0001,
hasControl: true
},
brickColor : {
type: 'vec3',
value : new BABYLON.Vector3(0.8, 0.1, 0.1),
min: new BABYLON.Vector3(0, 0, 0),
max: new BABYLON.Vector3(1, 1, 1),
step: new BABYLON.Vector3(0.001, 0.001, 0.001),
hasControl: true
},
mortColor : {
type: 'vec3',
value : new BABYLON.Vector3(0.35, 0.35, 0.35),
min: new BABYLON.Vector3(0, 0, 0),
max: new BABYLON.Vector3(1, 1, 1),
step: new BABYLON.Vector3(0.001, 0.001, 0.001),
hasControl: true
},
},
fx :
`precision highp float;
//Varyings
varying vec2 vUV;
varying vec2 tUV;
//Methods
float pulse(float a, float b, float v){
return step(a,v) - step(b,v);
}
float pulsate(float a, float b, float v, float x){
return pulse(a,b,mod(v,x)/x);
}
float gamma(float g, float v){
return pow(v, 1./g);
}
float bias(float b, float v){
return pow(v, log(b)/log(0.5));
}
float gain(float g, float v){
if(v < 0.5){
return bias(1.0-g, 2.0*v)/2.0;
}else{
return 1.0 - bias(1.0-g, 2.0 - 2.0*v)/2.0;
}
}
/*----- UNIFORMS ------*/
uniform vec2 brickCounts;
uniform float mortarSize;
uniform vec3 brickColor;
uniform vec3 mortColor;
void main(void) {
vec2 brickSize = vec2(
1.0/brickCounts.x,
1.0/brickCounts.y
);
vec2 pos = vUV/brickSize;
vec2 mortSize = 1.0-vec2(mortarSize*(brickCounts.x/brickCounts.y), mortarSize);
pos += mortSize*0.5;
if(fract(pos.y * 0.5) > 0.5){
pos.x += 0.5;
}
pos = fract(pos);
vec2 brickOrMort = step(pos, mortSize);
vec3 color = mix(mortColor, brickColor, brickOrMort.x * brickOrMort.y);
gl_FragColor = vec4(color, 1.0);
}`
},scene);
console.log(sm);
return scene;
}
var scene = createScene();
engine.runRenderLoop(function(){
scene.render();
});
window.addEventListener('resize', function(){
engine.resize();
sm.buildOutput();
});
});
</script>
</body>
</html>
You can’t perform that action at this time.