使用three.js循环浏览材料onclick

时间:2019-01-01 02:53:16

标签: javascript three.js

我是three.js的新手,我想学习如何在onclick材料之间循环。 This example展示了我要实现的目标,除了循环遍历纹理而不是遍历材质。

我想将材料排列成一个阵列,然后能够单击画布以循环浏览这些材料。

以下是上面示例的代码:

var scene = new THREE.Scene();
scene.background = new THREE.Color( 0xcccccc );

var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
camera.position.y = 5;
camera.position.x = 5;
camera.lookAt(new THREE.Vector3(0,0,0)); // Make the camera look at the point of origin

var renderer = new THREE.WebGLRenderer({antialias:true});
var devicePixelRatio = window.devicePixelRatio || 1; // To handle high pixel density displays

renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(devicePixelRatio);

document.body.appendChild( renderer.domElement );

var render = function () {

    requestAnimationFrame( render );
    renderer.render(scene, camera);
};

// instantiate a texture loader
var loader = new THREE.TextureLoader();
//allow cross origin loading
loader.crossOrigin = '';

// The textures to use
var arr = [
    'https://s3-us-west-2.amazonaws.com/s.cdpn.io/259155/THREE_gates.jpg',
    'https://s3-us-west-2.amazonaws.com/s.cdpn.io/259155/THREE_crate1.jpg',
    'https://s3-us-west-2.amazonaws.com/s.cdpn.io/259155/THREE_crate2.jpg'
];
var textureToShow = 0;

// Load the first texture
// var texture = loadTexture('https://s3-us-west-2.amazonaws.com/s.cdpn.io/259155/MarbleSurface.jpg');

// Instantiate the material we will be using
var material = new THREE.MeshBasicMaterial();
// Instantiate a geometry to use
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
// Instatiate the mesh with the geometry and material
var cube = new THREE.Mesh( geometry, material );
cube.position.y = 0.5;

// Then load the texture
loader.load(arr[textureToShow], function(tex) {
    // Once the texture has loaded
    // Asign it to the material
    material.map = tex;
    // Update the next texture to show
    textureToShow++;
    // Add the mesh into the scene
    scene.add( cube );
});

// Click interaction
var canvas = document.getElementsByTagName("canvas")[0];

canvas.addEventListener("click", function() {

    loader.load(arr[textureToShow], function(tex) {
        // Once the texture has loaded
        // Asign it to the material
        material.map = tex;
        // Update the next texture to show
        textureToShow++;
        // Have we got to the end of the textures array
        if(textureToShow > arr.length-1) {
            textureToShow = 0;
        }
    }); 
});

// Start rendering the scene
render();

这是我无法使用的代码:

        var container, stats;
    var camera, scene, renderer;
    var mouseX = 0,
        mouseY = 0;
    var windowHalfX = window.innerWidth / 2;
    var windowHalfY = window.innerHeight / 2;
    var globalObject;

    init();
    animate();

    function init() {
        container = document.createElement('div');
        document.body.appendChild(container);

        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000);
        camera.position.z = 500;

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

        ambientLight = new THREE.AmbientLight(0xffffff, 0.2);
        scene.add(ambientLight);

        pointLight = new THREE.PointLight(0xff0000, 0.5);
        pointLight.position.z = 2500;
        scene.add(pointLight);

        var pointLight2 = new THREE.PointLight(0xff6666, 1);
        camera.add(pointLight2);

        var pointLight3 = new THREE.PointLight(0x0000ff, 0.5);
        pointLight3.position.x = -1000;
        pointLight3.position.z = 1000;
        scene.add(pointLight3);

        //manager
        var manager = new THREE.LoadingManager();
        manager.onProgress = function(item, loaded, total) {
            console.log(item, loaded, total);
        };

        //materials
        var path = "textures/cube/skybox/";
        var format = '.jpg';
        var urls = [
            path + 'px' + format, path + 'nx' + format,
            path + 'py' + format, path + 'ny' + format,
            path + 'pz' + format, path + 'nz' + format
        ];

        var reflectionCube = new THREE.CubeTextureLoader().load(urls);

        var material = new THREE.MeshStandardMaterial({
            envMap: reflectionCube,
            roughness: 0.1,
            metalness: 1,
            color: 0xfee6af,
        });

        var materialTwo = new THREE.MeshStandardMaterial({
            envMap: reflectionCube,
            roughness: 0.1,
            metalness: 0,
            color: 0xffff00,
        });




        //model
        var loader = new THREE.OBJLoader(manager);
        loader.load('logo97.obj', function(object) {
            //store global reference to .obj
            globalObject = object;

            object.traverse(function(child) {
                if (child instanceof THREE.Mesh) {
                    child.material = material;
                    child.material.needsUpdate = true;
                }
            });

            object.position.y = 0;
            scene.add(object);
        });

        //render
        renderer = new THREE.WebGLRenderer({
            antialias: true,
            alpha: true
        });
        renderer.setSize(window.innerWidth, window.innerHeight);
        container.appendChild(renderer.domElement);

        document.addEventListener('mousemove', onDocumentMouseMove, false);
        window.addEventListener('resize', onWindowResize, false);
    }

    function onWindowResize() {
        windowHalfX = window.innerWidth / 2;
        windowHalfY = window.innerHeight / 2;
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }

    function onDocumentMouseMove(event) {
        mouseX = (event.clientX - windowHalfX) / 2;
        mouseY = (event.clientY - windowHalfY) / 2;
    }

    // Click interaction
    var canvas = document.getElementsByTagName("canvas")[0];

    canvas.addEventListener("click", function() {

         var materials = [
            new THREE.MeshBasicMaterial( {color:'#b02030'} ),
            new THREE.MeshLambertMaterial( {color:'#b02030'} ), 
            new THREE.MeshPhongMaterial( {color:'#b02030', shininess: 100 } ),
            new THREE.MeshNormalMaterial(),
            // ...
        ];
        var materialToShow = 0;

        materialToShow ++;
        if ( materialToShow >= materials.length ) materialToShow = 0;
        child.material = materials[materialToShow]; 


    });

    //animate
    function animate() {
        requestAnimationFrame(animate);
        render();
    }

    function render() {
        camera.position.x += (mouseX - camera.position.x) * .05;
        camera.position.y += (-mouseY - camera.position.y) * .05;
        camera.lookAt(scene.position);
        renderer.render(scene, camera);
    }

1 个答案:

答案 0 :(得分:1)

您必须创建一个THREE.Material个数组:

例如

var materials = [
    new THREE.MeshBasicMaterial( {color:'#b02030'} ),
    new THREE.MeshLambertMaterial( {color:'#b02030'} ), 
    new THREE.MeshPhongMaterial( {color:'#b02030', shininess: 100 } ),
    new THREE.MeshNormalMaterial(),
    // ...
];
var materialToShow = 0;

"click"中,可以通过更改属性THREE.Mesh来更改.material的当前材料。

canvas.addEventListener("click", function() {

    materialToShow ++;
    if ( materialToShow >= materials.length ) materialToShow = 0;
    mesh.material = materials[materialToShow];   
});

当然,您必须向场景添加一些光(例如THREE.AmbientLightTHREE.DirectionalLight),以使不同材质的行为“可见”。

请参见示例,其中我将建议的更改应用于原始代码。
我使用了一个球体来表示THREE.MeshPhongMaterial的镜面反射高光。
我删除了纹理,但是您当然也可以应用纹理。

var scene = new THREE.Scene();
scene.background = new THREE.Color( 0xcccccc );

var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.y = 4;
camera.lookAt(new THREE.Vector3(0,0,0)); // Make the camera look at the point of origin

var renderer = new THREE.WebGLRenderer({antialias:true});
var devicePixelRatio = window.devicePixelRatio || 1; // To handle high pixel density displays

renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(devicePixelRatio);

document.body.appendChild( renderer.domElement );
window.onresize = resize;

var ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);

var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
directionalLight.position.set(1,2,-1.0);
scene.add( directionalLight );

var render = function () {

    requestAnimationFrame( render );
    renderer.render(scene, camera);
};

var materials = [
    new THREE.MeshBasicMaterial( {color:'#b02030'} ),
    new THREE.MeshLambertMaterial( {color:'#b02030'} ), 
    new THREE.MeshPhongMaterial( {color:'#b02030', shininess: 100 } ),
    new THREE.MeshNormalMaterial(),
    // ...
];
var materialToShow = 0;

var geometry = new THREE.SphereGeometry( 1, 32, 16 );
var mesh = new THREE.Mesh( geometry, materials[materialToShow] );
scene.add( mesh );

// Click interaction
var canvas = document.getElementsByTagName("canvas")[0];

canvas.addEventListener("click", function() {

    materialToShow ++;
    if ( materialToShow >= materials.length ) materialToShow = 0;
    mesh.material = materials[materialToShow];   
});

function resize() {
    
    var aspect = window.innerWidth / window.innerHeight;
    renderer.setSize(window.innerWidth, window.innerHeight);
    camera.aspect = aspect;
    camera.updateProjectionMatrix();
}

// Start rendering the scene
render();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/99/three.min.js"></script>


由于使用了THREE.OBJLoader,因此必须更改根对象.material.children)的Object3DglobalObject。 当然,materialToShowmaterials只需初始化一次:

var materials = [
    new THREE.MeshBasicMaterial( {color:'#b02030'} ),
    new THREE.MeshLambertMaterial( {color:'#b02030'} ), 
    new THREE.MeshPhongMaterial( {color:'#b02030', shininess: 100 } ),
    new THREE.MeshNormalMaterial(),
    // ...
];
var materialToShow = 0;
canvas.addEventListener("click", function() {

    materialToShow ++;
    if ( materialToShow >= materials.length ) materialToShow = 0;

    globalObject.traverse(function(child) {
        if (child instanceof THREE.Mesh) {
            child.material = materials[materialToShow];
            child.material.needsUpdate = true;
        }
    });
});

请参见示例,在该示例中,我将更改应用于原始代码,并进行了一些更改以使其在此处起作用:

var container, stats;
var camera, scene, renderer;
var mouseX = 0,
    mouseY = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
var globalObject;

init();
animate();

function init() {
    container = document.createElement('div');
    document.body.appendChild(container);

    camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000);
    camera.position.y = 3;
    camera.position.z = 3;

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

    ambientLight = new THREE.AmbientLight(0xffffff, 0.2);
    scene.add(ambientLight);

    var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
    directionalLight.position.set(0.5,2,-1.0);
    scene.add( directionalLight );

    pointLight = new THREE.PointLight(0xff0000, 0.5);
    pointLight.position.z = 10;
    scene.add(pointLight);

    var pointLight2 = new THREE.PointLight(0xff6666, 1);
    camera.add(pointLight2);

    var pointLight3 = new THREE.PointLight(0x0000ff, 0.5);
    pointLight3.position.x = -10;
    pointLight3.position.z = 10;
    scene.add(pointLight3);

    //manager
    var manager = new THREE.LoadingManager();
    manager.onProgress = function(item, loaded, total) {
        console.log(item, loaded, total);
    };

    //materials
    /*
    var path = "textures/cube/skybox/";
    var format = '.jpg';
    var urls = [
        path + 'px' + format, path + 'nx' + format,
        path + 'py' + format, path + 'ny' + format,
        path + 'pz' + format, path + 'nz' + format
    ];
    */

    //var reflectionCube = new THREE.CubeTextureLoader().load(urls);

    var material = new THREE.MeshStandardMaterial({
        //envMap: reflectionCube,
        roughness: 0.1,
        metalness: 1,
        color: 0xfee6af,
    });

    var materialTwo = new THREE.MeshStandardMaterial({
        //envMap: reflectionCube,
        roughness: 0.1,
        metalness: 0,
        color: 0xffff00,
    });


    makeTextFile = function (text) {
      var data = new Blob([text], {type: 'text/plain'});
      var textFile = window.URL.createObjectURL(data);
      return textFile;   
    }
    var textbox_obj = document.getElementById('plane_obj');
    var obj_url = makeTextFile(textbox_obj.value);


    //model
    var loader = new THREE.OBJLoader(manager);
    loader.load(obj_url, function(object) {
        //store global reference to .obj
        globalObject = object;

        object.traverse(function(child) {
            if (child instanceof THREE.Mesh) {
                child.material = material;
                child.material.needsUpdate = true;
            }
        });

        object.position.y = 0;
        scene.add(object);
    });

    //render
    renderer = new THREE.WebGLRenderer({
        antialias: true,
        alpha: true
    });
    renderer.setSize(window.innerWidth, window.innerHeight);
    container.appendChild(renderer.domElement);

    document.addEventListener('mousemove', onDocumentMouseMove, false);
    window.addEventListener('resize', onWindowResize, false);
}

function onWindowResize() {
    windowHalfX = window.innerWidth / 2;
    windowHalfY = window.innerHeight / 2;
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
}

function onDocumentMouseMove(event) {
    mouseX = (event.clientX - windowHalfX) / 2;
    mouseY = (event.clientY - windowHalfY) / 2;
}

// Click interaction
var canvas = document.getElementsByTagName("canvas")[0];

var materials = [
    new THREE.MeshBasicMaterial( {color:'#b02030'} ),
    new THREE.MeshLambertMaterial( {color:'#b02030'} ), 
    new THREE.MeshPhongMaterial( {color:'#b02030', shininess: 100 } ),
    new THREE.MeshNormalMaterial(),
    // ...
];
var materialToShow = 0;
canvas.addEventListener("click", function() {

     materialToShow ++;
    if ( materialToShow >= materials.length ) materialToShow = 0;
        
    globalObject.traverse(function(child) {
        if (child instanceof THREE.Mesh) {
            child.material = materials[materialToShow];
            child.material.needsUpdate = true;
        }
    });
});

//animate
function animate() {
    requestAnimationFrame(animate);
    render();
}

function render() {
    //camera.position.x += (mouseX - camera.position.x) * .05;
    //camera.position.y += (-mouseY - camera.position.y) * .05;
    camera.lookAt(scene.position);
    renderer.render(scene, camera);
}
<textarea id="plane_obj" style="display:none;">
# Blender v2.77 (sub 0) OBJ File: 'Plane.blend'
# www.blender.org
mtllib Plane.mtl
o Plane

v -1.000000 0.000000 1.000000
v 1.000000 0.000000 1.000000
v -1.000000 0.000000 -1.000000
v 1.000000 0.000000 -1.000000

vt 0.000000 0.000000
vt 1.000000 0.000000
vt 0.000000 1.000000
vt 1.000000 1.000000

vn 0.0000 1.0000 0.0000

usemtl Material
s off
f 1/1/1 2/2/1 4/4/1 3/3/1
</textarea>

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/99/three.min.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/loaders/OBJLoader.js"></script>