Javascript 使用webgl和meatballs.js的响应画布

Javascript 使用webgl和meatballs.js的响应画布,javascript,canvas,responsive-design,webgl,responsive,Javascript,Canvas,Responsive Design,Webgl,Responsive,我正试图实现作为我的个人网站的背景。我对WebGL没有真正的了解,所以请容忍我。我临时添加了一个事件侦听器,以便在调整页面大小时更新画布的宽度和高度。我可以说这是可行的,因为当气泡开始超出边界时,它们会继续运动,不会从页面边缘反弹,所以我知道它在某种程度上是按照我希望的方式工作的。当片段着色器源被定义时,它也定义了宽度和高度,我不确定之后如何更改这些变量。我尝试用新的宽度和高度重新定义、重新编译和重新附加片段着色器源。这显然是不起作用的,因为创建画布时,气泡不会超过页面的大小。我不确定我是否用正

我正试图实现作为我的个人网站的背景。我对WebGL没有真正的了解,所以请容忍我。我临时添加了一个事件侦听器,以便在调整页面大小时更新画布的宽度和高度。我可以说这是可行的,因为当气泡开始超出边界时,它们会继续运动,不会从页面边缘反弹,所以我知道它在某种程度上是按照我希望的方式工作的。当片段着色器源被定义时,它也定义了宽度和高度,我不确定之后如何更改这些变量。我尝试用新的宽度和高度重新定义、重新编译和重新附加片段着色器源。这显然是不起作用的,因为创建画布时,气泡不会超过页面的大小。我不确定我是否用正确的方式来做这件事,如果是这样,我做错了什么?非常感谢您的帮助,谢谢

我更改的代码:

var canvas = document.createElement("canvas");
var width = canvas.width = window.innerWidth * 0.75;
var height = canvas.height = window.innerHeight * 0.75;
document.body.appendChild(canvas);
var gl = canvas.getContext('webgl');

var mouse = {x: 0, y: 0};

var numMetaballs = 30;
var metaballs = [];

var first = true

window.addEventListener('resize', function(){
    width = canvas.width = window.innerWidth * 0.75;
    height = canvas.height = window.innerHeight * 0.75;
    shaderStuff()
})

function shaderStuff(){
    if(!first) {
        gl.detachShader(program, gl.getAttachedShaders(program)[1])
    }
    first = false
    
    var fragmentShaderSrc = `
    precision highp float;

    const float WIDTH = ` + (width >> 0) + `.0;
    const float HEIGHT = ` + (height >> 0) + `.0;

    uniform vec3 metaballs[` + numMetaballs + `];

    void main(){
    float x = gl_FragCoord.x;
    float y = gl_FragCoord.y;

    float sum = 0.0;
    for (int i = 0; i < ` + numMetaballs + `; i++) {
    vec3 metaball = metaballs[i];
    float dx = metaball.x - x;
    float dy = metaball.y - y;
    float radius = metaball.z;

    sum += (radius * radius) / (dx * dx + dy * dy);
    }

    if (sum >= 0.99) {
    gl_FragColor = vec4(mix(vec3(x / WIDTH, y / HEIGHT, 1.0), vec3(0, 0, 0), max(0.0, 1.0 - (sum - 0.99) * 100.0)), 1.0);
    return;
    }

    gl_FragColor = vec4(0, 0, 0, 0);
    }

    `;
    
    var fragmentShader = compileShader(fragmentShaderSrc, gl.FRAGMENT_SHADER);
    gl.attachShader(program, fragmentShader);
}

for (var i = 0; i < numMetaballs; i++) {
  var radius = Math.random() * 60 + 10;
  metaballs.push({
    x: Math.random() * (width - 2 * radius) + radius,
    y: Math.random() * (height - 2 * radius) + radius,
    vx: (Math.random() - 0.5) * 3,
    vy: (Math.random() - 0.5) * 3,
    r: radius * 0.75
  });
}

var vertexShaderSrc = `
attribute vec2 position;

void main() {
// position specifies only x and y.
// We set z to be 0.0, and w to be 1.0
gl_Position = vec4(position, 0.0, 1.0);
}
`;



var vertexShader = compileShader(vertexShaderSrc, gl.VERTEX_SHADER);


var program = gl.createProgram();
gl.attachShader(program, vertexShader);
shaderStuff()
gl.linkProgram(program);
gl.useProgram(program);

var canvas=document.createElement(“canvas”);
var width=canvas.width=window.innerWidth*0.75;
var height=canvas.height=window.innerHeight*0.75;
document.body.appendChild(画布);
var gl=canvas.getContext('webgl');
变量鼠标={x:0,y:0};
var nummetaball=30;
var metaballs=[];
var first=true
addEventListener('resize',function()){
宽度=canvas.width=window.innerWidth*0.75;
高度=canvas.height=window.innerHeight*0.75;
shaderStuff()
})
函数shaderStuff(){
如果(!第一个){
gl.detachShader(程序,gl.getAttachedShaders(程序)[1])
}
第一个=错误
var fragmentShaderSrc=`
高精度浮点;
常量浮点宽度=`+(宽度>>0)+`.0;
常量浮点高度=`+(高度>>0)+`.0;
统一的vec3元球[`+nummetables+`];
void main(){
浮点数x=gl_FragCoord.x;
浮动y=gl_FragCoord.y;
浮动总和=0.0;
对于(int i=0;i<`+nummetables++;i++){
vec3元球=元球[i];
浮点dx=metaball.x-x;
float dy=metaball.y-y;
浮动半径=变形球.z;
总和+=(半径*半径)/(dx*dx+dy*dy);
}
如果(总和>=0.99){
gl_FragColor=vec4(混合(vec3(x/宽度,y/高度,1.0),vec3(0,0,0),最大值(0.0,1.0-(总和-0.99)*100.0)),1.0);
返回;
}
gl_FragColor=vec4(0,0,0,0);
}
`;
var fragmentShader=compileShader(fragmentShaderSrc,gl.FRAGMENT\u着色器);
gl.attachShader(程序、碎片着色器);
}
对于(var i=0;i
整个项目


原始的

最简单的方法是将所有后台创建代码放入一个函数中,并在每次调整页面大小时调用它

您还需要添加一些代码来停止以前的后台循环,并且应该添加一些限制,以防止一次创建太多的后台

这有点低效,但大多数用户并不期望应用程序在调整大小时具有极高的响应能力,而且调整大小的操作并不频繁

我添加了一个代码片段,它似乎可以工作,但是我无法让我的更改在codepen中工作。我相信这是因为codepen以某种方式插入和修改代码,从而破坏了代码(jsbin有类似的行为来防止无限循环,并对其进行沙箱处理)。然而,我只在一个.html文件中测试了我的更改,它们似乎在那里工作,所以它们应该在您的站点上工作

另一方面,WebGL的使用非常酷

var nextBackgroundId=1;
var currentBackgroundId=0;
setupBackground(currentBackgroundId);
window.addEventListener(“调整大小”,()=>{
var ourBackgroundId=nextBackgroundId++;
currentBackgroundId=我们的BackgroundId;
设置超时(()=>{
setupBackground(我们的背景ID);
}, 100);
});
函数设置背景(ourBackgroundId){
如果(currentBackgroundId!==我们的BackgroundId){
返回;
}
var prevCanvas=document.getElementById(“blob画布”);
如果(前画布){
prevCanvas.remove();
}
var canvas=document.createElement(“canvas”);
canvas.id=“blob canvas”;
变量鼠标={x:0,y:0};
canvas.onmousemove=函数(e){
mouse.x=e.clientX;
mouse.y=e.clientY;
}
var width=canvas.width=window.innerWidth;
var height=canvas.height=window.innerHeight;
document.body.appendChild(画布);
var gl=canvas.getContext('webgl');
var nummetaball=30;
var metaballs=[];
对于(var i=0;i>0)+`.0;
常量浮点高度=`+(高度>>0)+`.0;
统一的vec3元球[`+nummetables+`];
void main(){
浮点数x=gl_FragCoord.x;
弗洛亚
var width = canvas.width = window.innerWidth * 0.75;
var height = canvas.height = window.innerHeight * 0.75;
html, body {
  height: 100%;
  overflow: hidden;
}     
canvas {
  width: 100%;
  height: 100%;
}
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
html, body {
  height: 100%;
  /* removed overflow: hidden */
}     
canvas {
  width: 100%;
  height: 100%;
  display: block;
}
var fragmentShaderSrc = `
precision highp float;

const float WIDTH = ` + (width >> 0) + `.0;
const float HEIGHT = ` + (height >> 0) + `.0;

uniform vec3 metaballs[` + numMetaballs + `];
...
`;
var fragmentShaderSrc = `
precision highp float;

const float WIDTH = ${width >> 0}.0;
const float HEIGHT = ${height >> 0}.0;

uniform vec3 metaballs[${numMetaballs}];
...
`;
const float WIDTH = ${width >> 0}.0;
const float HEIGHT = ${height >> 0}.0;
uniform float WIDTH;
uniform float HEIGHT;