【问题标题】:Redraw three js element重绘三个js元素
【发布时间】:2020-08-26 21:05:35
【问题描述】:

我用三个 js 看了this example 来绘制带有图像的粒子并且效果很好,但是我想在单击按钮时使用开关更改图像(调用此函数):

    const changeImg = function(num) {

    switch (num)
    {
        case 0:
            imgData ="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA....";
        break;

        case 1:
            imgData = "data:image/png;base64,iVBORw0KGgoAAAAN..."
        break;
    }

    img.src = imgData;

}

并且可以,但是当您多次单击时,网站会变慢。

如何在不降低网站速度的情况下仅更新图片?

编辑 1

我把代码改成这样:

var renderer, scene, camera, ww, wh, particles, mw, mh, mz, numState;

numState = 0;

mz = 6; // Matrerial size

ww = document.getElementById('map-container').offsetWidth,
wh = 450;

mw = ww * 2;
mh = wh * 2;

var centerVector = new THREE.Vector3(0, 0, 0);
var previousTime = 0
    speed = 10
    isMouseDown = false;

// Render
renderer = new THREE.WebGLRenderer({
    canvas: document.getElementById("map"),
    antialias: true
});

renderer.setSize(mw, mh);
renderer.setClearColor(0x12347C);

// Scence
scene = new THREE.Scene();

// Camera
camera = new THREE.OrthographicCamera( ww / - 2, ww / 2, wh / 2, wh / - 2, 1, 1000 );
camera.position.set(7, 0, 4);
camera.lookAt(centerVector);
scene.add(camera);
camera.zoom = 4;
camera.updateProjectionMatrix();

// Geometry
var geometry = new THREE.Geometry();
var material = new THREE.PointsMaterial({
    size: mz,
    color: 0xFFFFFF,
    sizeAttenuation: false
});

// Particle
particles = new THREE.Points();

var getImageData = function(image) {

    var canvas = document.createElement("canvas");
    canvas.width = image.width;
    canvas.height = image.height;

    var ctx = canvas.getContext("2d");
    ctx.drawImage(image, 0, 0);

    return ctx.getImageData(0, 0, image.width, image.height);
}

var drawTheMap = function() {

    geometry.dispose();
    particles.material.dispose();
    particles.geometry.dispose();

    for (var y = 0, y2 = imagedata.height; y < y2; y += 2) {
        for (var x = 0, x2 = imagedata.width; x < x2; x += 2) {
            if (imagedata.data[(x * 4 + y * 4 * imagedata.width)] < 128) {

                var vertex = new THREE.Vector3();
                vertex.x = x - imagedata.width / 2;
                vertex.y = -y + imagedata.height / 2;
                vertex.z = -Math.random()*500;

                vertex.speed = Math.random() / speed + 0.015;

                geometry.vertices.push(vertex);
            }
        }
    }

    particles.material = material;
    particles.geometry = geometry;

    scene.add(particles);

    requestAnimationFrame(render);
};

var init = function() {

    imagedata = getImageData(image);
    drawTheMap();

    onResize();

    window.addEventListener('mousemove', onMousemove, false);
    window.addEventListener('mousedown', onMousedown, false);
    window.addEventListener('mouseup', onMouseup, false);
    window.addEventListener('resize', onResize, false);

};


var onResize = function(){

    var mov1, mov2;

    ww = document.getElementById('map-container').offsetWidth;
    wh = 450;
    
    if (window.innerWidth > 850) {
        mw = ww * 2;
        mh = wh * 2;
        mz = 6;

        mov1 = 2.2;
        mov2 = 1.9;

        particles.material.size = mz;
    } else {
        mw = ww;
        mh = wh;
        mz = 3;

        mov1 = 2;
        mov2 = 2;

        particles.material.size = mz;
    }

    renderer.setSize(mw, mh);
    camera.left    = ww / - mov1;
    camera.right   = ww / 2;
    camera.top     = wh / mov2;
    camera.bottom  = wh / - 2;
    camera.updateProjectionMatrix();
};

var onMouseup = function(){
    isMouseDown = false;
}
var onMousedown = function(e){
    isMouseDown = true;
    lastMousePos = {x:e.clientX, y:e.clientY};
};
var onMousemove = function(e){
    
    if(isMouseDown){
        camera.position.x += (e.clientX-lastMousePos.x)/100;
        camera.position.y -= (e.clientY-lastMousePos.y)/100;
        camera.lookAt(centerVector);
        lastMousePos = {x:e.clientX, y:e.clientY};
    }
};

var render = function(a) {

    requestAnimationFrame(render);

    particles.geometry.verticesNeedUpdate = true;
    if(!isMouseDown){
        camera.position.x += (0-camera.position.x)*0.06;
        camera.position.y += (0-camera.position.y)*0.06;
        camera.lookAt(centerVector);
    }

    renderer.render(scene, camera);
};

var imgData;
var image;
imgData ="data:image/png;base64,iVBORw0KGgoAAA...";

const changeState = function(state, num) {

    document.getElementById('dropbox-choose').innerHTML = state;
    numState = num;

    switch (numState)
    {
        case 0:
            imgData ="data:image/png;base64,iVBORw0KGgoAAA...";
        break;

        case 1:
            imgData = "data:image/png;base64,iVBORw0KGgoI..."
        break;
    }

    image.src = imgData;
}

image = document.createElement("img");
image.onload = init;
image.src = imgData;

THREE.WebGLRenderer 只应用了一次,但是当我点击更改图像时,它并没有更新,而且我仍然遇到网站变慢的问题

这是我第一次使用三个js,我不知道我是否很好地应用了文档中所说的

编辑 2

var renderer, scene, camera, ww, wh, particles, mw, mh, mz, numState;

numState = 0;

mz = 6;
ww = document.getElementById('map-container').offsetWidth,
wh = 450;

mw = ww * 2;
mh = wh * 2;

var centerVector = new THREE.Vector3(0, 0, 0);
var previousTime = 0
    speed = 10
    isMouseDown = false;

// Render
renderer = new THREE.WebGLRenderer({
    canvas: document.getElementById("map"),
    antialias: true
});

renderer.setSize(mw, mh);
renderer.setClearColor(0x12347C);

// Scence
scene = new THREE.Scene();

// Camera
camera = new THREE.OrthographicCamera( ww / - 2, ww / 2, wh / 2, wh / - 2, 1, 1000 );
camera.position.set(7, 0, 4);
camera.lookAt(centerVector);
scene.add(camera);
camera.zoom = 4;
camera.updateProjectionMatrix();

// Geometry
//var geometry = new THREE.Geometry();
var material = new THREE.PointsMaterial({
    size: mz,
    color: 0xFFFFFF,
    sizeAttenuation: false
});

// Particle
particles = new THREE.Points();
particles.material = material

scene.add(particles);

var getImageData = function(image) {

    var canvas = document.createElement("canvas");
    canvas.width = image.width;
    canvas.height = image.height;

    var ctx = canvas.getContext("2d");
    ctx.drawImage(image, 0, 0);

    return ctx.getImageData(0, 0, image.width, image.height);
}

var drawTheMap = function() {

    let vertices = particles.geometry; // this acts as a REFERENCE!
    vertices.length = 0; // clears the vertices array


    for (var y = 0, y2 = imagedata.height; y < y2; y += 2) {
        for (var x = 0, x2 = imagedata.width; x < x2; x += 2) {
            if (imagedata.data[(x * 4 + y * 4 * imagedata.width)] < 128) {

                var vertex = new THREE.Vector3();
                vertex.x = x - imagedata.width / 2;
                vertex.y = -y + imagedata.height / 2;
                vertex.z = -Math.random()*500;

                vertex.speed = Math.random() / speed + 0.015;

                vertices.vertices.push(vertex);
            }
        }
    }

    particles.geometry.verticesNeedUpdate = true; // Inform three.js of the update

    requestAnimationFrame(render);
};

var init = function() {

    imagedata = getImageData(image);
    drawTheMap();

    onResize();

    window.addEventListener('mousemove', onMousemove, false);
    window.addEventListener('mousedown', onMousedown, false);
    window.addEventListener('mouseup', onMouseup, false);
    window.addEventListener('resize', onResize, false);

};


var onResize = function(){

    var mov1, mov2;

    ww = document.getElementById('map-container').offsetWidth;
    wh = 450;
    
    if (window.innerWidth > 850) {
        mw = ww * 2;
        mh = wh * 2;
        mz = 6;

        mov1 = 2.2;
        mov2 = 1.9;

        particles.material.size = mz;
    } else {
        mw = ww;
        mh = wh;
        mz = 3;

        mov1 = 2;
        mov2 = 2;

        particles.material.size = mz;
    }

    renderer.setSize(mw, mh);
    camera.left    = ww / - mov1;
    camera.right   = ww / 2;
    camera.top     = wh / mov2;
    camera.bottom  = wh / - 2;
    camera.updateProjectionMatrix();
};

var onMouseup = function(){
    isMouseDown = false;
}
var onMousedown = function(e){
    isMouseDown = true;
    lastMousePos = {x:e.clientX, y:e.clientY};
};
var onMousemove = function(e){
    if(isMouseDown){
        camera.position.x += (e.clientX-lastMousePos.x)/100;
        camera.position.y -= (e.clientY-lastMousePos.y)/100;
        camera.lookAt(centerVector);
        lastMousePos = {x:e.clientX, y:e.clientY};
    }
};

var render = function(a) {

    requestAnimationFrame(render);

    particles.geometry.verticesNeedUpdate = true;
    if(!isMouseDown){
        camera.position.x += (0-camera.position.x)*0.06;
        camera.position.y += (0-camera.position.y)*0.06;
        camera.lookAt(centerVector);
    }

    renderer.render(scene, camera);
};

var imgData;
var image;
imgData ="data:image/png;base64,iVBORw0KGgoAAA...";

const changeState = function(state, num) {

    document.getElementById('dropbox-choose').innerHTML = state;
    numState = num;

    switch (numState)
    {
        case 0:
            imgData ="data:image/png;base64,iVBORw0KGgoAAA...";
        break;

        case 1:
            imgData = "data:image/png;base64,iVBORw0KGgoAAA..."
        break;
    }

    image.src = imgData;
}

image = document.createElement("img");
image.onload = init;
image.src = imgData;

当我点击更改图像时,它没有更新,而且我仍然有网站变慢的问题。我将 vertcies.push 转换为 vertices.vertices.push()

【问题讨论】:

    标签: javascript three.js frontend


    【解决方案1】:

    我知道我在以前版本的答案中提到了处置,但让我们考虑重新使用所有对象。

    particles - 创建后立即添加到场景中。

    material - 立即分配给particles;无需每次都重新分配。

    geometry - 不要在全局范围内创建它,我们会让它在 particles 内部工作。

    现在我们要做的是替换顶点并告诉three.js有新顶点要上传到GPU。

    var drawTheMap = function() {
    
        let vertices = particles.geometry; // this acts as a REFERENCE!
        vertices.length = 0; // clears the vertices array
    
        for (var y = 0, y2 = imagedata.height; y < y2; y += 2) {
            for (var x = 0, x2 = imagedata.width; x < x2; x += 2) {
                if (imagedata.data[(x * 4 + y * 4 * imagedata.width)] < 128) {
    
                    var vertex = new THREE.Vector3();
                    vertex.x = x - imagedata.width / 2;
                    vertex.y = -y + imagedata.height / 2;
                    vertex.z = -Math.random()*500;
    
                    vertex.speed = Math.random() / speed + 0.015;
    
                    vertices.push(vertex);
                }
            }
        }
    
        particles.geometry.verticesNeedUpdate = true; // Inform three.js of the update
    
        requestAnimationFrame(render);
    };
    

    这里的重要部分(除了替换vertices 数组的内容)是设置particles.geometry.verticesNeedUpdate = true;。这就是触发 three.js 替换 GPU 上的顶点的原因。其他一切都是重复使用的,而不是重新创建的,所以它应该运行得相当顺利。

    【讨论】:

    • 我已经更改了代码,但现在我遇到了其他问题。用新代码更新帖子
    • 嗨。我已经按照你说的修改了代码,但是还是不行。我用我拥有的最新代码更新问题。
    【解决方案2】:

    解决方法是将 THREE.geometry 改为 THREE.BufferGeometry

    var drawTheMap = function() {
        particles.geometry = new THREE.BufferGeometry();
        var positions = [];
    
        for (var y = 0, y2 = imagedata.height; y < y2; y += 2) {
            for (var x = 0, x2 = imagedata.width; x < x2; x += 2) {
                if (imagedata.data[(x * 4 + y * 4 * imagedata.width)] < 128)  {
    
                    positions.push(x - imagedata.width / 2);
                    positions.push(-y + imagedata.height / 2);
                    positions.push(-Math.random()*500);
    
                    particles.geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );
    
                }
            }
        }
        
          particles.geometry.verticesNeedUpdate = true;
    
        requestAnimationFrame(render);
    };

    【讨论】:

      猜你喜欢
      • 2021-07-24
      • 2018-01-04
      • 2015-09-28
      • 2023-03-17
      • 2019-04-09
      • 2012-10-12
      • 1970-01-01
      • 2018-04-24
      • 2010-12-19
      相关资源
      最近更新 更多