当前位置:网站首页>babylonjs shader
babylonjs shader
2022-08-10 15:42:00 【qianbo_insist】
babylonjs
有关于他的基础知识我们就不提了,下面这个例子是他的shader例子,写的非常好。要做好特效,肯定是需要shader相关的知识了,学一学有益处,ok,看code
https://www.babylonjs.com/demos/actions/
https://playground.babylonjs.com/#GHCBUE#2
/* from threejs demo https://threejs.org/examples/?q=postp#webgl_postprocessing_rgb_halftone create by musk */
var createScene = function () {
// This creates a basic Babylon Scene object (non-mesh)
var scene = new BABYLON.Scene(engine);
scene.clearColor = BABYLON.Color3.FromHexString("#D6A6A6");
// This creates and positions a free camera (non-mesh)
// var camera = new BABYLON.FreeCamera("camera1", new BABYLON.Vector3(0, 5, -10), scene);
var camera = new BABYLON.ArcRotateCamera("camera", 1.57, 1.134, 3,new BABYLON.Vector3(0.01,0.18,-0.08), scene);
camera.wheelDeltaPercentage = 0.02;
// This attaches the camera to the canvas
camera.attachControl(canvas, true);
var bgCamera = new BABYLON.ArcRotateCamera("BGCamera", Math.PI / 2 + Math.PI / 7, Math.PI / 2, 100,
new BABYLON.Vector3(0, 0, 0),
scene);
bgCamera.layerMask = 0x10000000;
scene.activeCameras = [camera, bgCamera];
// This creates a light, aiming 0,1,0 - to the sky (non-mesh)
var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);
// Default intensity is 1. Let's dim the light a small amount
light.intensity = 0.7;
BABYLON.SceneLoader.ImportMesh("", "https://models.babylonjs.com/", "emoji_heart.glb", scene, function (meshes) {
meshes[0].scaling = new BABYLON.Vector3(20,20,20);
var ground = BABYLON.Mesh.CreateGround("ground1", 16, 16, 2, scene);
ground.receiveShadows = true;
// Create and tweak the background material.
var backgroundMaterial = new BABYLON.BackgroundMaterial("backgroundMaterial", scene);
var mirror = new BABYLON.MirrorTexture("mirror", 512, scene);
mirror.mirrorPlane = new BABYLON.Plane(0, -1, 0, 0);
mirror.renderList.push(scene.getMeshById("emoji_heart_new3.2"));
backgroundMaterial.reflectionTexture = mirror;
ground.material = backgroundMaterial;
});
BABYLON.Effect.ShadersStore["customFragmentShader"] = ` precision highp float; // Samplers uniform sampler2D textureSampler; varying vec2 vUV; // Parameters uniform vec2 screenSize; uniform int shape; uniform float radius; uniform float rotateR; uniform float rotateG; uniform float rotateB; uniform float scatter; uniform bool disable; uniform bool greyscale; uniform float blending; uniform int blendingMode; #define SQRT2_MINUS_ONE 0.41421356 #define SQRT2_HALF_MINUS_ONE 0.20710678 #define PI2 6.28318531 #define SHAPE_DOT 1 #define SHAPE_ELLIPSE 2 #define SHAPE_LINE 3 #define SHAPE_SQUARE 4 #define BLENDING_LINEAR 1 #define BLENDING_MULTIPLY 2 #define BLENDING_ADD 3 #define BLENDING_LIGHTER 4 #define BLENDING_DARKER 5 const int samples = 8; float blend( float a, float b, float t ) { // linear blend return a * ( 1.0 - t ) + b * t; } float hypot( float x, float y ) { // vector magnitude return sqrt( x * x + y * y ); } float rand( vec2 seed ){ // get pseudo-random number return fract( sin( dot( seed.xy, vec2( 12.9898, 78.233 ) ) ) * 43758.5453 ); } float distanceToDotRadius( float channel, vec2 coord, vec2 normal, vec2 p, float angle, float rad_max ) { // apply shape-specific transforms float dist = hypot( coord.x - p.x, coord.y - p.y ); float rad = channel; if ( shape == SHAPE_DOT ) { rad = pow( abs( rad ), 1.125 ) * rad_max; } else if ( shape == SHAPE_ELLIPSE ) { rad = pow( abs( rad ), 1.125 ) * rad_max; if ( dist != 0.0 ) { float dot_p = abs( ( p.x - coord.x ) / dist * normal.x + ( p.y - coord.y ) / dist * normal.y ); dist = ( dist * ( 1.0 - SQRT2_HALF_MINUS_ONE ) ) + dot_p * dist * SQRT2_MINUS_ONE; } } else if ( shape == SHAPE_LINE ) { rad = pow( abs( rad ), 1.5) * rad_max; float dot_p = ( p.x - coord.x ) * normal.x + ( p.y - coord.y ) * normal.y; dist = hypot( normal.x * dot_p, normal.y * dot_p ); } else if ( shape == SHAPE_SQUARE ) { float theta = atan( p.y - coord.y, p.x - coord.x ) - angle; float sin_t = abs( sin( theta ) ); float cos_t = abs( cos( theta ) ); rad = pow( abs( rad ), 1.4 ); rad = rad_max * ( rad + ( ( sin_t > cos_t ) ? rad - sin_t * rad : rad - cos_t * rad ) ); } return rad - dist; } struct Cell { // grid sample positions vec2 normal; vec2 p1; vec2 p2; vec2 p3; vec2 p4; float samp2; float samp1; float samp3; float samp4; }; vec4 getSample( vec2 point ) { // multi-sampled point vec4 tex = texture2D( textureSampler, vec2( point.x / screenSize.x, point.y / screenSize.y ) ); float base = rand( vec2( floor( point.x ), floor( point.y ) ) ) * PI2; float step = PI2 / float( samples ); float dist = radius * 0.66; for ( int i = 0; i < samples; ++i ) { float r = base + step * float( i ); vec2 coord = point + vec2( cos( r ) * dist, sin( r ) * dist ); tex += texture2D( textureSampler, vec2( coord.x / screenSize.x, coord.y / screenSize.y ) ); } tex /= float( samples ) + 1.0; return tex; } float getDotColour( Cell c, vec2 p, int channel, float angle, float aa ) { // get colour for given point float dist_c_1, dist_c_2, dist_c_3, dist_c_4, res; if ( channel == 0 ) { c.samp1 = getSample( c.p1 ).r; c.samp2 = getSample( c.p2 ).r; c.samp3 = getSample( c.p3 ).r; c.samp4 = getSample( c.p4 ).r; } else if (channel == 1) { c.samp1 = getSample( c.p1 ).g; c.samp2 = getSample( c.p2 ).g; c.samp3 = getSample( c.p3 ).g; c.samp4 = getSample( c.p4 ).g; } else { c.samp1 = getSample( c.p1 ).b; c.samp3 = getSample( c.p3 ).b; c.samp2 = getSample( c.p2 ).b; c.samp4 = getSample( c.p4 ).b; } dist_c_1 = distanceToDotRadius( c.samp1, c.p1, c.normal, p, angle, radius ); dist_c_2 = distanceToDotRadius( c.samp2, c.p2, c.normal, p, angle, radius ); dist_c_3 = distanceToDotRadius( c.samp3, c.p3, c.normal, p, angle, radius ); dist_c_4 = distanceToDotRadius( c.samp4, c.p4, c.normal, p, angle, radius ); res = ( dist_c_1 > 0.0 ) ? clamp( dist_c_1 / aa, 0.0, 1.0 ) : 0.0; res += ( dist_c_2 > 0.0 ) ? clamp( dist_c_2 / aa, 0.0, 1.0 ) : 0.0; res += ( dist_c_3 > 0.0 ) ? clamp( dist_c_3 / aa, 0.0, 1.0 ) : 0.0; res += ( dist_c_4 > 0.0 ) ? clamp( dist_c_4 / aa, 0.0, 1.0 ) : 0.0; res = clamp( res, 0.0, 1.0 ); return res; } Cell getReferenceCell( vec2 p, vec2 origin, float grid_angle, float step ) { // get containing cell Cell c; // calc grid vec2 n = vec2( cos( grid_angle ), sin( grid_angle ) ); float threshold = step * 0.5; float dot_normal = n.x * ( p.x - origin.x ) + n.y * ( p.y - origin.y ); float dot_line = -n.y * ( p.x - origin.x ) + n.x * ( p.y - origin.y ); vec2 offset = vec2( n.x * dot_normal, n.y * dot_normal ); float offset_normal = mod( hypot( offset.x, offset.y ), step ); float normal_dir = ( dot_normal < 0.0 ) ? 1.0 : -1.0; float normal_scale = ( ( offset_normal < threshold ) ? -offset_normal : step - offset_normal ) * normal_dir; float offset_line = mod( hypot( ( p.x - offset.x ) - origin.x, ( p.y - offset.y ) - origin.y ), step ); float line_dir = ( dot_line < 0.0 ) ? 1.0 : -1.0; float line_scale = ( ( offset_line < threshold ) ? -offset_line : step - offset_line ) * line_dir; // get closest corner c.normal = n; c.p1.x = p.x - n.x * normal_scale + n.y * line_scale; c.p1.y = p.y - n.y * normal_scale - n.x * line_scale; // scatter if ( scatter != 0.0 ) { float off_mag = scatter * threshold * 0.5; float off_angle = rand( vec2( floor( c.p1.x ), floor( c.p1.y ) ) ) * PI2; c.p1.x += cos( off_angle ) * off_mag; c.p1.y += sin( off_angle ) * off_mag; } // find corners float normal_step = normal_dir * ( ( offset_normal < threshold ) ? step : -step ); float line_step = line_dir * ( ( offset_line < threshold ) ? step : -step ); c.p2.x = c.p1.x - n.x * normal_step; c.p2.y = c.p1.y - n.y * normal_step; c.p3.x = c.p1.x + n.y * line_step; c.p3.y = c.p1.y - n.x * line_step; c.p4.x = c.p1.x - n.x * normal_step + n.y * line_step; c.p4.y = c.p1.y - n.y * normal_step - n.x * line_step; return c; } float blendColour( float a, float b, float t ) { // blend colours if ( blendingMode == BLENDING_LINEAR ) { return blend( a, b, 1.0 - t ); } else if ( blendingMode == BLENDING_ADD ) { return blend( a, min( 1.0, a + b ), t ); } else if ( blendingMode == BLENDING_MULTIPLY ) { return blend( a, max( 0.0, a * b ), t ); } else if ( blendingMode == BLENDING_LIGHTER ) { return blend( a, max( a, b ), t ); } else if ( blendingMode == BLENDING_DARKER ) { return blend( a, min( a, b ), t ); } else { return blend( a, b, 1.0 - t ); } } void main() { if ( ! disable ) { // setup vec2 p = vec2( vUV.x * screenSize.x, vUV.y * screenSize.y ); vec2 origin = vec2( 0, 0 ); float aa = ( radius < 2.5 ) ? radius * 0.5 : 1.25; // get channel samples Cell cell_r = getReferenceCell( p, origin, rotateR, radius ); Cell cell_g = getReferenceCell( p, origin, rotateG, radius ); Cell cell_b = getReferenceCell( p, origin, rotateB, radius ); float r = getDotColour( cell_r, p, 0, rotateR, aa ); float g = getDotColour( cell_g, p, 1, rotateG, aa ); float b = getDotColour( cell_b, p, 2, rotateB, aa ); // blend with original vec4 colour = texture2D( textureSampler, vUV ); r = blendColour( r, colour.r, blending ); g = blendColour( g, colour.g, blending ); b = blendColour( b, colour.b, blending ); if ( greyscale ) { r = g = b = (r + b + g) / 3.0; } gl_FragColor = vec4( r, g, b, 1 ); } else { gl_FragColor = texture2D( textureSampler, vUV ); } } `;
var panel = new BABYLON.GUI.StackPanel();
panel.width = "220px";
panel.fontSize = "34px";
panel.outlineWidth = 10;
panel.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_RIGHT;
panel.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER;
var advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI("UI");
advancedTexture.layer.layerMask = 0x10000000;
var postProcess = new BABYLON.PostProcess("My custom post process", "custom", ["screenSize", "shape","radius","rotateR","rotateG","rotateB","scatter","blending","blendingMode","greyscale","disable"], null, 1, camera,BABYLON.Texture.NEAREST_NEAREST, engine, true);
var shapev = 1;
var radiusv = 15.0;
var rotateRv = Math.PI / 5 ;
var rotateGv = Math.PI / 5 ;
var rotateBv = Math.PI / 5 ;
var scatterv = .0 ;
var blendingv = 1.0 ;
var blendingModev = 1 ;
var greyscalev = false ;
var disablev = false ;
postProcess.onApply = (effect)=>{
effect.setFloat2("screenSize", postProcess.width, postProcess.height);
effect.setInt("shape", shapev);
effect.setFloat("radius", radiusv);
effect.setFloat("rotateR", rotateRv);
effect.setFloat("rotateG", rotateGv);
effect.setFloat("rotateB", rotateBv);
effect.setFloat("scatter", scatterv);
effect.setFloat("blending", blendingv);
effect.setInt("blendingMode", blendingModev);
effect.setBool("greyscale", greyscalev);
effect.setBool("disable", disablev);
};
// shape 'Dot': 1, 'Ellipse': 2, 'Line': 3, 'Square': 4
var shapewheader = new BABYLON.GUI.TextBlock();
shapewheader.text = "shape"+": ";
shapewheader.height = "30px";
shapewheader.color = "red";
shapewheader.outlineWidth = 10;
panel.addControl(shapewheader);
var shapeslider = new BABYLON.GUI.Slider();
shapeslider.minimum = 1;
shapeslider.maximum = 4;
shapeslider.value = 1;
shapeslider.step = 1;
shapeslider.height = "20px";
shapeslider.width = "200px";
shapeslider.onValueChangedObservable.add(function(value) {
shapewheader.text = "shape"+": " + (value | 1) ;
shapev = value;
console.log(value)
});
panel.addControl(shapeslider);
// radius 1-100
var radiuswheader = new BABYLON.GUI.TextBlock();
radiuswheader.text = "radius"+": ";
radiuswheader.height = "30px";
radiuswheader.color = "red";
radiuswheader.outlineWidth = 10;
panel.addControl(radiuswheader);
var radiusslider = new BABYLON.GUI.Slider();
radiusslider.minimum = 0;
radiusslider.maximum = 100;
radiusslider.value = 15;
radiusslider.step = 1;
radiusslider.height = "20px";
radiusslider.width = "200px";
radiusslider.onValueChangedObservable.add(function(value) {
radiuswheader.text = "radius"+": " + (value | 1) ;
radiusv = value;
console.log(value)
});
panel.addControl(radiusslider);
// rotateR 0-90
var rotateRwheader = new BABYLON.GUI.TextBlock();
rotateRwheader.text = "rotateR"+": ";
rotateRwheader.height = "30px";
rotateRwheader.color = "red";
rotateRwheader.outlineWidth = 10;
panel.addControl(rotateRwheader);
var rotateRslider = new BABYLON.GUI.Slider();
rotateRslider.minimum = 0;
rotateRslider.maximum = Math.PI;
rotateRslider.value = Math.PI / 5;
rotateRslider.step = 0.1;
rotateRslider.height = "20px";
rotateRslider.width = "200px";
rotateRslider.onValueChangedObservable.add(function(value) {
rotateRwheader.text = "rotateR"+": " + (value | 1) ;
rotateRv = value;
console.log(value)
});
panel.addControl(rotateRslider);
// rotateG 0-90
var rotateGwheader = new BABYLON.GUI.TextBlock();
rotateGwheader.text = "rotateG"+": ";
rotateGwheader.height = "30px";
rotateGwheader.color = "red";
rotateGwheader.outlineWidth = 10;
panel.addControl(rotateGwheader);
var rotateGslider = new BABYLON.GUI.Slider();
rotateGslider.minimum = 0;
rotateGslider.maximum = Math.PI;
rotateGslider.value = Math.PI / 5;
rotateGslider.step = 0.1;
rotateGslider.height = "20px";
rotateGslider.width = "200px";
rotateGslider.onValueChangedObservable.add(function(value) {
rotateGwheader.text = "rotateG"+": " + (value | 1) ;
rotateGv = value;
console.log(value)
});
panel.addControl(rotateGslider);
// rotateB 0-90
var rotateBwheader = new BABYLON.GUI.TextBlock();
rotateBwheader.text = "rotateB"+": ";
rotateBwheader.height = "30px";
rotateBwheader.color = "red";
rotateBwheader.outlineWidth = 10;
panel.addControl(rotateBwheader);
var rotateBslider = new BABYLON.GUI.Slider();
rotateBslider.minimum = 0;
rotateBslider.maximum = Math.PI;
rotateBslider.value = Math.PI / 5;
rotateBslider.step = 0.1;
rotateBslider.height = "20px";
rotateBslider.width = "200px";
rotateBslider.onValueChangedObservable.add(function(value) {
rotateBwheader.text = "rotateB"+": " + (value | 1) ;
rotateBv = value;
console.log(value)
});
panel.addControl(rotateBslider);
// scatter 0, 1, 0.01
var scatterwheader = new BABYLON.GUI.TextBlock();
scatterwheader.text = "scatter"+": ";
scatterwheader.height = "30px";
scatterwheader.color = "red";
scatterwheader.outlineWidth = 10;
panel.addControl(scatterwheader);
var scatterslider = new BABYLON.GUI.Slider();
scatterslider.minimum = 0;
scatterslider.maximum = 1;
scatterslider.value = 0;
scatterslider.step = 0.01;
scatterslider.height = "20px";
scatterslider.width = "200px";
scatterslider.onValueChangedObservable.add(function(value) {
scatterwheader.text = "scatter"+": " + (value | 1) ;
scatterv = value;
console.log(value)
});
panel.addControl(scatterslider);
// blending 0, 1, 0.01
var blendingwheader = new BABYLON.GUI.TextBlock();
blendingwheader.text = "blending"+": ";
blendingwheader.height = "30px";
blendingwheader.color = "red";
blendingwheader.outlineWidth = 10;
panel.addControl(blendingwheader);
var blendingslider = new BABYLON.GUI.Slider();
blendingslider.minimum = 0;
blendingslider.maximum = 1;
blendingslider.value = 0;
blendingslider.step = 0.01;
blendingslider.height = "20px";
blendingslider.width = "200px";
blendingslider.onValueChangedObservable.add(function(value) {
blendingwheader.text = "blending"+": " + (value | 1) ;
blendingv = value;
console.log(value)
});
panel.addControl(blendingslider);
// blendingMode 'Linear': 1, 'Multiply': 2, 'Add': 3, 'Lighter': 4, 'Darker': 5
var blendingModewheader = new BABYLON.GUI.TextBlock();
blendingModewheader.text = "blendingMode"+": ";
blendingModewheader.height = "30px";
blendingModewheader.color = "red";
blendingModewheader.outlineWidth = 10;
panel.addControl(blendingModewheader);
var blendingModeslider = new BABYLON.GUI.Slider();
blendingModeslider.minimum = 1;
blendingModeslider.maximum = 5;
blendingModeslider.value = 1;
blendingModeslider.step = 1
blendingModeslider.height = "20px";
blendingModeslider.width = "200px";
blendingModeslider.onValueChangedObservable.add(function(value) {
blendingModewheader.text = "blendingMode"+": " + (value | 1) ;
blendingModev = value;
console.log(value)
});
panel.addControl(blendingModeslider);
// greyscale
advancedTexture.addControl(panel);
var greyscalecheckbox = new BABYLON.GUI.Checkbox();
greyscalecheckbox.width = "30px";
greyscalecheckbox.height = "30px";
greyscalecheckbox.isChecked = false;
greyscalecheckbox.color = "red";
greyscalecheckbox.outlineWidth = 10;
greyscalecheckbox.onIsCheckedChangedObservable.add(function(value) {
greyscalev = value;
});
var greyscaleCheckboxH = BABYLON.GUI.Control.AddHeader(greyscalecheckbox, "greyscale", "180px", {
isHorizontal: true, controlFirst: true});
greyscaleCheckboxH.color = "red";
greyscaleCheckboxH.height = "40px";
greyscaleCheckboxH._children[1]._outlineWidth = 10;
greyscaleCheckboxH.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
panel.addControl(greyscaleCheckboxH);
// disable
advancedTexture.addControl(panel);
var disablecheckbox = new BABYLON.GUI.Checkbox();
disablecheckbox.width = "30px";
disablecheckbox.height = "30px";
disablecheckbox.isChecked = false;
disablecheckbox.color = "red";
disablecheckbox.onIsCheckedChangedObservable.add(function(value) {
disablev = value;
});
var disableCheckboxH = BABYLON.GUI.Control.AddHeader(disablecheckbox, "disable", "180px", {
isHorizontal: true, controlFirst: true});
disableCheckboxH.color = "red";
disableCheckboxH.height = "40px";
disableCheckboxH._children[1]._outlineWidth = 10;
disableCheckboxH.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
panel.addControl(disableCheckboxH);
return scene;
};
边栏推荐
猜你喜欢

秒杀项目收获

Colocate Join :ClickHouse的一种高性能分布式join查询模型

A test tool for ABAP Development Tool custom service endpoint

虚拟电厂可视化大屏,深挖痛点精准减碳

推荐几款最好用的MySQL开源客户端,建议收藏!

Oracle database backup DMP file is too big, what method can be split into multiple DMP when backup?

关于“算力”,这篇文章值得一看

面了个腾讯25k+出来的,他让我见识到什么基础的天花板

NFT digital collection development issue - digital collection platform

多线程面试指南
随机推荐
Chapter one module of the re module,
LeetCode-876. Middle of the Linked List
潜水员 ← 二维费用的背包问题
程序调试介绍及其使用
I met a 25k+ from Tencent, he let me see what kind of basic ceiling
智为链接,慧享生活,荣耀智慧服务,只为 “懂” 你
MySQL-创建、修改和删除表
Servlet简单项目操作
Asterisk SIP media path
【芯片】人人皆可免费造芯?谷歌开源芯片计划已释放90nm、130nm和180nm工艺设计套件
并发容器线程安全应对之道
Etcd Kubernetes 集群稳定性:LIST 请求源码分析、性能评估与大规模基础服务部署调优
Cesium快速上手4-Polylines图元使用讲解
全志V853开发板移植基于 LVGL 的 2048 小游戏
Colocate Join :ClickHouse的一种高性能分布式join查询模型
NPM - Cannot read properties of null (reading 'pickAlgorithm') 解决方案
铜锁密码库
哈希表应用:只出现一次的数字
A Sina Weibo semantic sentiment analysis tool developed by ABAP
Oracle database backup DMP file is too big, what method can be split into multiple DMP when backup?