Adding textures to a three.js shape after it has gone throught a CSG.js process

StackOverflow https://stackoverflow.com/questions/9999531

  •  28-05-2021
  •  | 
  •  

문제

I am using both three.js and CSG.js together to make a new shape.

var materialText = new THREE.MeshBasicMaterial({
        map: THREE.ImageUtils.loadTexture(rel_path_name+"images/wood.jpg")
});
var material = new THREE.MeshLambertMaterial({
    color: 0xFFFFFF
});
var cylinder = new THREE.Mesh(new THREE.CylinderGeometry(120, 100, 300, 40, 50, false), material);
cylinder.position.y = 100;
var bodyMainCSG = new THREE.CSG.toCSG(cylinder);

var cutOutShapeMaterial = new THREE.MeshLambertMaterial({
    color: 0x000000
});

var bodyMainFront = new THREE.Mesh(new THREE.CylinderGeometry(200, 190, 300, 40, 50, false), material);
bodyMainFront.position.z = -126;
bodyMainFront.position.y = 100;
var bodyMainFrontCSG = new THREE.CSG.toCSG(bodyMainFront);

var cutOutShapeFront = new THREE.Mesh(new THREE.CubeGeometry(300,300,200), cutOutShapeMaterial);
cutOutShapeFront.position.z = 140;
cutOutShapeFront.position.y = 100;
var cutOutShapeFrontCSG = new THREE.CSG.toCSG(cutOutShapeFront);

var cutOutShapeBack = new THREE.Mesh(new THREE.CubeGeometry(300,300,200), cutOutShapeMaterial);
cutOutShapeBack.position.z = -140;
cutOutShapeBack.position.y = 100;
var cutOutShapeBackCSG = new THREE.CSG.toCSG(cutOutShapeBack);

var spareCube = new THREE.Mesh(new THREE.CubeGeometry(400,300,400), cutOutShapeMaterial);
    spareCube.position.z = -160;
    spareCube.position.y = 100;
    var spareCubeCSG = new THREE.CSG.toCSG(spareCube);


    var bodyMainBack = new THREE.Mesh(new THREE.CylinderGeometry(220, 210, 300, 40, 50, false), material);
bodyMainBack.position.z = 148;
bodyMainBack.position.y = 100;
var bodyMainBackCSG = new THREE.CSG.toCSG(bodyMainBack);

var spareCube2 = new THREE.Mesh(new THREE.CubeGeometry(440,300,440), cutOutShapeMaterial);
    spareCube2.position.z = 180;
    spareCube2.position.y = 100;
var spareCube2CSG = new THREE.CSG.toCSG(spareCube2);
//Front creation Shape - Mixture of body main shape/Cube cut out shape
var extraCircle = bodyMainFrontCSG.subtract(spareCubeCSG);




//Front creation Shape - Mixture of body main shape/Cube cut out shape
var extraCircle = bodyMainFrontCSG.subtract(spareCubeCSG);
var extraCircleBack = bodyMainBackCSG.subtract(spareCube2CSG);
var frontCreationShape = bodyMainCSG.subtract(cutOutShapeFrontCSG);
var backCreationShape = frontCreationShape.subtract(cutOutShapeBackCSG);
var geometry = extraCircle.union(backCreationShape);
var geometry = geometry.union(extraCircleBack);
//var bulkRemoval = bodyMainCSG.subtract(cubeBulkCG);
//var geometry = bulkRemoval.subtract(frontCreationShape);

var mesh = new THREE.Mesh(THREE.CSG.fromCSG( geometry ), materialText);

Not the best code - The most important lines are

    var materialText = new THREE.MeshBasicMaterial({
        map: THREE.ImageUtils.loadTexture(rel_path_name+"images/wood.jpg")
    });

    var mesh = new THREE.Mesh(THREE.CSG.fromCSG( geometry ), materialText);

Im trying to add a texture to a cut shapes that has been converted to CSG, then back to THREE. Every time i do it i get a random error from three.js. I tired changing MeshBasicMaterial to "MeshPhongMaterial" and "MeshLambertMaterial", still the same error.

So my question is , am i doing something wrong or is it not possible?

도움이 되었습니까?

해결책

This is actually quite easy by slightly changing CSG.js and THREE.CSG.js. UVs need to be introduced to the CSG vertex prototype and in THREE.CSG the UVs need to be passed into and out of the CSG polygon.

The adapted codes look like the following:

Vertex prototype in CSG.js:

CSG.Vertex = function(pos, normal, uv) {
  this.pos = new CSG.Vector(pos);
  this.normal = new CSG.Vector(normal);
  // modification
  this.uv = new CSG.Vector(uv);  
};

CSG.Vertex.prototype = {
  clone: function() {
    return new CSG.Vertex(
        this.pos.clone(),
        this.normal.clone(),
        // modification
        this.uv.clone()
    );
  },

  // Invert all orientation-specific data (e.g. vertex normal). Called when the
  // orientation of a polygon is flipped.
  flip: function() {
    this.normal = this.normal.negated();
  },

  // Create a new vertex between this vertex and `other` by linearly
  // interpolating all properties using a parameter of `t`. Subclasses should
  // override this to interpolate additional properties.
  interpolate: function(other, t) {
    return new CSG.Vertex(
      this.pos.lerp(other.pos, t),
      this.normal.lerp(other.normal, t),
      // modification
      this.uv.lerp(other.uv, t)
    );
  }
};

Whole THREE.CSG.js file:

/*
    THREE.CSG
    @author Chandler Prall <chandler.prall@gmail.com> http://chandler.prallfamily.com

    Wrapper for Evan Wallace's CSG library (https://github.com/evanw/csg.js/)
    Provides CSG capabilities for Three.js models.

    Provided under the MIT License
*/

THREE.CSG = {
    toCSG: function ( three_model, offset, rotation ) {
        var i, geometry, offset, polygons, vertices, rotation_matrix;

        if ( !CSG ) {
            throw 'CSG library not loaded. Please get a copy from https://github.com/evanw/csg.js';
        }

        if ( three_model instanceof THREE.Mesh ) {
            geometry = three_model.geometry;
            offset = offset || three_model.position;
            rotation = rotation || three_model.rotation;
        } else if ( three_model instanceof THREE.Geometry ) {
            geometry = three_model;
            offset = offset || new THREE.Vector3( 0, 0, 0 );
            rotation = rotation || new THREE.Vector3( 0, 0, 0 );
        } else {
            throw 'Model type not supported.';
        }
        rotation_matrix = new THREE.Matrix4( ).setRotationFromEuler( rotation );

        var polygons = [];
        for ( i = 0; i < geometry.faces.length; i++ ) {
            if ( geometry.faces[i] instanceof THREE.Face3 ) {


                vertices = [];
                vertices.push( new CSG.Vertex( rotation_matrix.multiplyVector3( geometry.vertices[geometry.faces[i].a].clone( ).addSelf( offset ) ), [ geometry.faces[i].normal.x, geometry.faces[i].normal.y, geometry.faces[i].normal.z ], [ geometry.faceVertexUvs[0][i][0].u, geometry.faceVertexUvs[0][i][0].v, 0 ] ) );
                vertices.push( new CSG.Vertex( rotation_matrix.multiplyVector3( geometry.vertices[geometry.faces[i].b].clone( ).addSelf( offset ) ), [ geometry.faces[i].normal.x, geometry.faces[i].normal.y, geometry.faces[i].normal.z ], [ geometry.faceVertexUvs[0][i][1].u, geometry.faceVertexUvs[0][i][1].v, 0 ] ) );
                vertices.push( new CSG.Vertex( rotation_matrix.multiplyVector3( geometry.vertices[geometry.faces[i].c].clone( ).addSelf( offset ) ), [ geometry.faces[i].normal.x, geometry.faces[i].normal.y, geometry.faces[i].normal.z ], [ geometry.faceVertexUvs[0][i][2].u, geometry.faceVertexUvs[0][i][2].v, 0 ] ) );
                polygons.push( new CSG.Polygon( vertices ) );

            } else if ( geometry.faces[i] instanceof THREE.Face4 ) {

                vertices = [];
                vertices.push( new CSG.Vertex( rotation_matrix.multiplyVector3( geometry.vertices[geometry.faces[i].a].clone( ).addSelf( offset ) ), [ geometry.faces[i].normal.x, geometry.faces[i].normal.y, geometry.faces[i].normal.z ], [ geometry.faceVertexUvs[0][i][0].u, geometry.faceVertexUvs[0][i][0].v, 0 ] ) );
                vertices.push( new CSG.Vertex( rotation_matrix.multiplyVector3( geometry.vertices[geometry.faces[i].b].clone( ).addSelf( offset ) ), [ geometry.faces[i].normal.x, geometry.faces[i].normal.y, geometry.faces[i].normal.z ], [ geometry.faceVertexUvs[0][i][1].u, geometry.faceVertexUvs[0][i][1].v, 0 ] ) );
                vertices.push( new CSG.Vertex( rotation_matrix.multiplyVector3( geometry.vertices[geometry.faces[i].d].clone( ).addSelf( offset ) ), [ geometry.faces[i].normal.x, geometry.faces[i].normal.y, geometry.faces[i].normal.z ], [ geometry.faceVertexUvs[0][i][3].u, geometry.faceVertexUvs[0][i][3].v, 0 ] ) );
                polygons.push( new CSG.Polygon( vertices ) );

                vertices = [];
                vertices.push( new CSG.Vertex( rotation_matrix.multiplyVector3( geometry.vertices[geometry.faces[i].b].clone( ).addSelf( offset ) ), [ geometry.faces[i].normal.x, geometry.faces[i].normal.y, geometry.faces[i].normal.z ], [ geometry.faceVertexUvs[0][i][1].u, geometry.faceVertexUvs[0][i][1].v, 0 ] ) );
                vertices.push( new CSG.Vertex( rotation_matrix.multiplyVector3( geometry.vertices[geometry.faces[i].c].clone( ).addSelf( offset ) ), [ geometry.faces[i].normal.x, geometry.faces[i].normal.y, geometry.faces[i].normal.z ], [ geometry.faceVertexUvs[0][i][2].u, geometry.faceVertexUvs[0][i][2].v, 0 ] ) );
                vertices.push( new CSG.Vertex( rotation_matrix.multiplyVector3( geometry.vertices[geometry.faces[i].d].clone( ).addSelf( offset ) ), [ geometry.faces[i].normal.x, geometry.faces[i].normal.y, geometry.faces[i].normal.z ], [ geometry.faceVertexUvs[0][i][3].u, geometry.faceVertexUvs[0][i][3].v, 0 ] ) );
                polygons.push( new CSG.Polygon( vertices ) );

            } else {
                throw 'Model contains unsupported face.';
            }
        }

        return CSG.fromPolygons( polygons );
    },

    fromCSG: function( csg_model ) {
        var i, j, vertices, face,
            three_geometry = new THREE.Geometry( ),
            polygons = csg_model.toPolygons( );

        if ( !CSG ) {
            throw 'CSG library not loaded. Please get a copy from https://github.com/evanw/csg.js';
        }

        for ( i = 0; i < polygons.length; i++ ) {

            // Vertices
            vertices = [];
            for ( j = 0; j < polygons[i].vertices.length; j++ ) {
                vertices.push( this.getGeometryVertice( three_geometry, polygons[i].vertices[j].pos ) );
            }
            if ( vertices[0] === vertices[vertices.length - 1] ) {
                vertices.pop( );
            }

            for (var j = 2; j < vertices.length; j++) {
                face = new THREE.Face3( vertices[0], vertices[j-1], vertices[j], new THREE.Vector3( ).copy( polygons[i].plane.normal ) );
                three_geometry.faces.push( face );
                three_geometry.faceVertexUvs[0].push([
                    new THREE.UV(polygons[i].vertices[0].uv.x, polygons[i].vertices[0].uv.y),
                    new THREE.UV(polygons[i].vertices[j-1].uv.x, polygons[i].vertices[j-1].uv.y),
                    new THREE.UV(polygons[i].vertices[j].uv.x, polygons[i].vertices[j].uv.y)
                ]);
            }
        }

        three_geometry.computeBoundingBox();

        return three_geometry;
    },

    getGeometryVertice: function ( geometry, vertice_position ) {
        var i;
        for ( i = 0; i < geometry.vertices.length; i++ ) {
            if ( geometry.vertices[i].x === vertice_position.x && geometry.vertices[i].y === vertice_position.y && geometry.vertices[i].z === vertice_position.z ) {
                // Vertice already exists
                return i;
            }
        };

        geometry.vertices.push( new THREE.Vector3( vertice_position.x, vertice_position.y, vertice_position.z ) );
        return geometry.vertices.length - 1;
    }
};

Using these codes, applying CSG-operations to two THREE.Geometry's textured with the same texture-map works well, while keeping up the correct vertex UVs.

Hope that may help you a little!

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top