Play 3D model intersection and complement of WebGL under HTML5

Constructive solid geometry has many practical uses, it is used where simple geometric objects are required, or where mathematical precision is important, almost all engineering CAD packages use CSG (which can be used to represent tool cuts, and where parts must be features that fit together). CSG is  the abbreviation of Constructive Solid Geometry  modeling technology. It combines the operations of subtraction, union and intersection to combine complex model effects. HT encapsulates primitive types such as ht.CSGNode and ht.CSGShape to support the combination function of CSG. It is commonly used in the application scenarios of hollowing out doors and windows in the wall.

CSG objects can be represented by a binary tree, where leaves represent primitives and nodes represent operations. In this graph, nodes are marked ∩ for intersection, ∪ for union, and - for difference. The models or surfaces provided by CSG look complex, but are really nothing more than clever combinations or decompositions of objects.

ht.CSGNode inherits from ht.Node. When the shape3d property of style is empty, it will display a hexahedral effect. If CSGNode is adsorbed to the host CSGNode or CSGShape through setHost, the host CSGNode or CSGShape can be combined with the adsorbed CSGNode primitive to build a CSG mold. For details, please refer to  the CSGNode chapter of the HT for Web Modeling Manual  . Here I wrote an example with the concept of CSG, so that everyone can better understand this concept.

Demo address of this example:  http://hightopo.com/guide/guide/plugin/modeling/examples/example_bookshelf.html

Let's take a look at the effect diagram first:

As can be seen from the above renderings, we divide the interface into three parts. The three parts are first divided up and down the right part, and then the entire interface is divided left and right. HT uses the packaged ht.widget.SplitView to divide the interface, and then Add the split component to the underlying div:

 

dm = new ht.DataModel();// data model            
treeView = new ht.widget.TreeView(dm); //tree component                                                                                                 
gv1 = new ht.graph3d.Graph3dView(dm); //3D component  
gv2 = new ht.graph3d.Graph3dView(dm);
splitView = new ht.widget.SplitView(gv1, gv2, 'v', 0.6);//Split component
mainSplit = new ht.widget.SplitView(treeView, splitView, 'h', 0.27);   
                
view = mainSplit.getView();  
view.className = 'main';
document.body.appendChild(view);    
window.addEventListener('resize', function (e) {
    mainSplit.invalidate();
}, false);                         

 

The above code is a very common way to add HT components in HTML. For details, please refer to the  Components chapter of the HT for Web Getting Started Manual . There is a point to pay attention to when adding HT components in this method, because HT generally uses the absolute positioning method of setting position as absolute, and must set basic css styles such as left, right, top, bottom, etc., like this:

 

.main {
     margin: 0px;
     padding: 0px;
     position: absolute;
     top: 0px;
     bottom: 0px;
     left: 0px;
     right: 0px;
}

 

Therefore, for the convenience of loading and filling the window with the outermost component, all components of HT have the addToDOM function. The logic of the idea is as follows, where iv is the abbreviation of invalidate:

 

addToDOM = function(){   
    var self = this,
    view = self.getView(),   
    style = view.style;
    document.body.appendChild(view);            
    style.left = '0';
    style.right = '0';
    style.top = '0';
    style.bottom = '0';      
    window.addEventListener('resize', function () { self.iv(); }, false);            
}  

 

In the future, we can directly call the addToDOM function in the code without writing a lot of code. The code above is replaced by addToDOM, and the code is as follows, and there is no need to describe the css style: 

 

dm = new ht.DataModel();// data model             
treeView = new ht.widget.TreeView(dm); //tree component                                                             
gv1 = new ht.graph3d.Graph3dView(dm); //3D component  
gv2 = new ht.graph3d.Graph3dView(dm);
splitView = new ht.widget.SplitView(gv1, gv2, 'v', 0.6);//Split component
mainSplit = new ht.widget.SplitView(treeView, splitView, 'h', 0.27);   
mainSplit.addToDOM();

 

After the interface is allocated, we will add content to it. The left part of the interface is the tree component encapsulated by HT. As I wrote in the previous article, the tree component is a very convenient component for drawing tree relationships. Developers can It is easy to get the relationship between data and nodes from the data model DataModel and put it on the tree. It is only necessary to put the corresponding data model DataModel into the parameters of the tree component in the process of declaring the tree component. Of course, we also extended Many functions related to tree components are very convenient and practical. Here we only use the expandAll function to expand all objects:

 

treeView = new ht.widget.TreeView(dm); //tree component   
treeView.expandAll();

 

The right part is divided into two parts up and down, both of which are 3D scenes, but the setting and display are a bit different, and the others are the same. The above 3D scene overloads the getVisibleFunc function, if the element's showMe attribute is true, it is visible; if the node is ht. CSGNode type and the parameter of the getHost function of the node is empty, it is not visible; other cases are visible:

 

gv1.setVisibleFunc(function(data){
    if(data.showMe){
        return true;
    }
    if(data instanceof ht.CSGNode && data.getHost()){
        return false;
    }
    return true;
});

 

Let's first add element objects to the 3D scene, we will explain the bookshelf in the middle first, and then supplement the bookshelves on both sides that are missing. First, we added a ht.CSGNode node shelf, as the main node of the bookshelf, other nodes are attached to this node, set the position, size, name and color of the six faces for this node, and then add it into the data model DataModel: 

 

var shelf = new ht.CSGNode();
shelf.s3(500, 400, 120);
shelf.p3(0, 200, 0);
shelf.setName('shelf1');
shelf.s({
    'all.color': '#E5BB77'
});
dm.add(shelf);

 

Then add 10 nodes to this shelf, make the grid effect of the bookshelf, and set the dependency relationship and parent-child relationship and add it to the data model:

 

for(var i=0; i<2; i++){
    for(var j=0; j<5; j++){
        var clipNode = new ht.CSGNode ();
        clipNode.setHost(shelf);
        clipNode.s3(80, 100, 120);
        clipNode.p3(-200+j*100, 340-i*120, 20);
        clipNode.setName('substract-'+i+'-'+j);
        clipNode.s('batch', 'tt');
        clipNode.setParent(shelf);
        dm.add(clipNode);
    }
}

 

In order to make the bookshelf more beautiful, we added ht.CSGNode to the upper, lower, left and right sides of the bookshelf. Finally, in order to be more concrete, we also added a book. The implementation method is similar, and it is very simple:

 

var book = new ht.Node();
book.setName('CSS3: The Missing Manual');
book.s3(60, 80, 8);
book.p3(-100, 210, 20);
book.r3(-Math.PI/6, Math.PI/5, 0);
book.setIcon('book');
book.s({
    'front.image': 'book',
    'back.color': 'white',
    'left.color': 'white',
    'all.color': 'gray'
});
book.setHost(shelf);
book.setParent(shelf);
dm.add(book);             

 

Then the bookshelf on the left is also constructed in a similar way. The difference is that there is a ht.CSGBox type here, which inherits from ht.CSGNode. In addition to the functions such as the hollowing out of the parent class CSGNode, it can also be used for six faces. Carry out the operation of rotating, expanding and closing, here our node only sets the previous ones that can be rotated and expanded, and sets a series of styles:

 

clipNode = new ht.CSGBox();
clipNode.setName('CSGBox-Expand-Left');
clipNode.s3(100, 100, 120);
clipNode.p3(0, 65, 0.1);
clipNode.setHost(shelf);
clipNode.showMe = true;
clipNode.s ({
    'all.visible': false,//6 faces are invisible
    'front.visible': true, // front visible
    'front.toggleable': true,//Allow double-click to expand the front                    
    'front.reverse.flip': true,//The front side shows the front content
    'front.transparent': true,//The front is transparent
    'front.end': Math.PI * 0.7,//The end rotation radian of the front expansion state
    'front.color': 'rgba(0, 50, 50, 0.7)'//front color
});

 

Maybe you also want to know how the earth below does it? I still remember that the previous article wrote that the shape3d property is set in HT. Setting this property is actually operating setShape3dModel(name, model) and getShape3dModel(name), which can be set to box|sphere|cylinder|cone|torus through this property |star|rect|roundRect|triangle|rightTriangle|parallelogram|trapezoid and other models, these models are also encapsulated by HT, and you can directly set shape3d as one of the values ​​when you want to use them. For example, "shape3d" is used in this example. : sphere" is set to a sphere. We simply wrap a map image on the outside of this sphere, of course, the map image is first registered via ht.Default.setImage, and then attached to this node via shape3d.image:

 

earth = new ht.Node();
earth.setName('earth');
earth.s3(70, 70, 70);
earth.p3(0, 50, 0);
earth.s({
    'shape3d': 'sphere',
    'shape3d.image': 'earth'
});
earth.setHost(shelf);  
earth.setParent(shelf);
dm.add(earth);

 

The bookshelf on the right also has a main node, and other nodes are attached to it, but we see that a new node type ht.DoorWindow has been changed here. ht.DoorWindow inherits from ht.CSGNode, except for those with parent class CSGNode. In addition to functions such as hollowing, it can also perform the overall rotation, unfolding and closing operations. It is often used as a business object for doors or windows, and the host attached to CSGNode or CSGShape is used as a primitive on the wall. This node type is an extension of ht.CSGNode. Relatively speaking, it distinguishes the actual application and adds different style parameters. For more properties, please  refer to the DoorWindow chapter of the HT for Web Modeling Manual  and add them to the node to play:

 

photos = new ht.DoorWindow ();
photos.setName ('DoorWindow-Photos');
photos.setIcon('ben12');
photos.s3(110, 100, 130);
photos.p3(5, 180, 0);                
photos.setHost(shelf);  
photos.showMe = true;
photos.s({                    
    'bottom.uv': [1,1, 1,0, 0,0, 0,1],
    'bottom.uv.scale': [1, 1],
    'left.uv.scale': [3, 3],
    'top.uv.scale': [2, 2],
    'dw.s3': [0.8, 0.9, 0.05],
    'dw.t3': [0, -5, 0],
    'dw.axis': 'v',
    'dw.toggleable': false,
    'front.image': 'ben1',
    'back.image': 'ben2',
    'all.color': '#F8CE8B'
});
photos.setParent(shelf);
dm.add(photos);

 

Finally, we rotate the earth earth on the left and the photo photo on the right:

 

var angle = 0;
setInterval(function(){
    angle += Math.PI/40;
    earth.r3(0, angle, 0);
    photos.s('dw.angle', angle);
}, 50);

 

We can see that although HT encapsulates many different CSG node types, the actual applications are similar, and the content is not particularly different. The difference is in the style parameter, but in actual development, this distinction is It will greatly speed up the development speed. After all, the name is clear at a glance, and you know which style attributes to use.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326481996&siteId=291194637