干扰(noise)
程序员文章站
2022-07-01 13:54:32
...
更多有趣示例 尽在小红砖社区
示例
HTML
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec4 mod289(vec4 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec4 permute(vec4 x) {
return mod289(((x*34.0)+1.0)*x);
}
vec4 taylorInvSqrt(vec4 r){
return 1.79284291400159 - 0.85373472095314 * r;
}
float snoise(vec3 v) {
const vec2 C = vec2(1.0/6.0, 1.0/3.0) ;
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
// First corner
vec3 i = floor(v + dot(v, C.yyy) );
vec3 x0 = v - i + dot(i, C.xxx) ;
// Other corners
vec3 g = step(x0.yzx, x0.xyz);
vec3 l = 1.0 - g;
vec3 i1 = min( g.xyz, l.zxy );
vec3 i2 = max( g.xyz, l.zxy );
// x0 = x0 - 0.0 + 0.0 * C.xxx;
// x1 = x0 - i1 + 1.0 * C.xxx;
// x2 = x0 - i2 + 2.0 * C.xxx;
// x3 = x0 - 1.0 + 3.0 * C.xxx;
vec3 x1 = x0 - i1 + C.xxx;
vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y
// Permutations
i = mod289(i);
vec4 p = permute( permute( permute(
i.z + vec4(0.0, i1.z, i2.z, 1.0 ))
+ i.y + vec4(0.0, i1.y, i2.y, 1.0 ))
+ i.x + vec4(0.0, i1.x, i2.x, 1.0 ));
// Gradients: 7x7 points over a square, mapped onto an octahedron.
// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
float n_ = 0.142857142857; // 1.0/7.0
vec3 ns = n_ * D.wyz - D.xzx;
vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7)
vec4 x_ = floor(j * ns.z);
vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N)
vec4 x = x_ *ns.x + ns.yyyy;
vec4 y = y_ *ns.x + ns.yyyy;
vec4 h = 1.0 - abs(x) - abs(y);
vec4 b0 = vec4( x.xy, y.xy );
vec4 b1 = vec4( x.zw, y.zw );
//vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
//vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
vec4 s0 = floor(b0)*2.0 + 1.0;
vec4 s1 = floor(b1)*2.0 + 1.0;
vec4 sh = -step(h, vec4(0.0));
vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;
vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;
vec3 p0 = vec3(a0.xy,h.x);
vec3 p1 = vec3(a0.zw,h.y);
vec3 p2 = vec3(a1.xy,h.z);
vec3 p3 = vec3(a1.zw,h.w);
//Normalise gradients
vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
p0 *= norm.x;
p1 *= norm.y;
p2 *= norm.z;
p3 *= norm.w;
// Mix final noise value
vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
m = m * m;
return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3) ) );
}
</script>
CSS
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
background-color: #0000FF;
}
.stats {
position: absolute;
top: 5px;
left: 5px;
}
JS
// Original here https://twitter.com/etiennejcb/status/1092882184321548289
// Original Code: https://gist.github.com/Bleuje/094d45a8cb11d16ce002d014ba761559
class ThreeBasic {
useControls = false;
renderer = null;
camera = null;
scene = null;
controls = null;
constructor(withControls = false){
this.hasControls = withControls;
}
init(){
const VIEW_ANGLE = 45,
ASPECT = window.innerWidth / window.innerHeight,
NEAR = 0.1,
FAR = 10000;
const camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
camera.position.z = 30;
const scene = new THREE.Scene();
const renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true});
if(this.hasControls){
this.controls = new THREE.OrbitControls(camera, renderer.domElement);
}
document.body.appendChild(renderer.domElement);
this.camera = camera;
this.scene = scene;
this.renderer = renderer;
this.onResize();
}
add(mesh){
this.scene.add(mesh);
}
onResize(){
this.renderer.setSize(window.innerWidth, window.innerHeight);
// uniforms.u_res.value.x = renderer.domElement.width;
// uniforms.u_res.value.y = renderer.domElement.height;
this.camera.aspect = window.innerWidth / window.innerHeight;
}
render(){
this.renderer.render( this.scene, this.camera );
}
}
const App = new ThreeBasic(true);
App.init();
const variants = ['z-noise','noise-zoom-in'];
const config = {
timeSpeed: 0.005,
variant: variants[0]
}
const src1 = 'https://images.pexels.com/photos/1930421/pexels-photo-1930421.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260';
const src2 = 'https://images.pexels.com/photos/1906819/pexels-photo-1906819.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260';
const t0 = new THREE.TextureLoader().load(src1);
const t1 = new THREE.TextureLoader().load(src2);
// CODE GOES HERE
const uniforms = {
u_time: {type:'f', value: 0},
u_freq: {type:'f', value: 10.},
u_speed: {type:'f', value: 2.},
t0: {type:'t', value: t0},
t1: {type:'t', value:t1},
}
let segments = 128;
let geometry = new THREE.PlaneBufferGeometry(16,16,segments, segments);
const noise = document.getElementById('noise').textContent;
const getShaders = (name)=>{
let vertex = document.getElementById(name+'-vertex') || document.getElementById('vertex');
let fragment = document.getElementById(name+'-fragment') || document.getElementById('fragment');
return {
fragmentShader: noise+fragment.textContent,
vertexShader: noise+vertex.textContent
}
}
const material = new THREE.ShaderMaterial({
uniforms,
...getShaders(config.variant),
side: THREE.DoubleSide
});
const mesh = new THREE.Mesh(geometry, material);
// Adding materials
App.add(mesh);
//
let stats = new Stats();
stats.showPanel(0);
stats.domElement.className = "stats"
document.body.appendChild( stats.domElement );
/*
pow(
(1 + noise.eval(
4 * SEED + scl * pos.x/2,
scl * pos.y / 2 + mr * cos(TWO_PI*t),
scl * pos.z / 2 + mr * sin(TWO_PI*t))
)/2,
4.0);
*/
const gui = new dat.GUI()
gui.add(config,"timeSpeed", 0.005,0.04);
const gui_variant = gui.add(config, 'variant', variants);
gui_variant.onFinishChange((type)=>{
const shaders = getShaders(type);
material.vertexShader = shaders.vertexShader;
material.fragmentShader = shaders.fragmentShader;
material.needsUpdate = true;
});
const possibles = [];
const calcPosibleSpeeds = () => {
while(possibles.length > 0){
possibles.splice(0, 1);
}
for(var i = 1, max = uniforms.u_freq.value; i < max; i++) {
if(max % i === 0) {
possibles.push(i);
}
}
}
calcPosibleSpeeds();
console.log(possibles);
// const gui_speed = gui.add(uniforms.u_speed, "value", possibles );
const gui_freq = gui.add(uniforms.u_freq, "value", 2,15,1);
gui_freq.name("frequency");
gui_freq.onFinishChange((val)=>{
// calcPosibleSpeeds();
// gui_speed.options(possibles);
// console.log(possibles)
// uniforms.u_speed.value = possibles[0];
})
// Gui controls go here
gui.close();
const update = ()=>{
uniforms.u_time.value += config.timeSpeed;
// squareMesh.rotation.y+=0.025;
}
function draw(){
stats.begin();
App.render();
stats.end();
update();
requestAnimationFrame(draw)
}
function init(){
requestAnimationFrame(draw)
}
window.addEventListener('resize', ()=>{
App.onResize();
});
window.addEventListener('mousemove',(e)=>{
// uniforms.u_mouse.value.x = e.clientX/window.innerWidth;
// uniforms.u_mouse.value.y = e.clientY/window.innerHeight;
})
init();
上一篇: NAT地址转换&NTP 网络时间协议
下一篇: 307-搭建简单P2P网络