@sohale/implisolid
Version:
A Solid Modelling Kernel in Javascript based on Implicit Surfaces, for MP5 file format
701 lines (541 loc) • 23.1 kB
HTML
<html>
<head>
<meta charset="utf-8"/>
</head>
<script type="text/javascript" src="mc2_sol.cpp.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r77/three.js"></script>
<!--script type="text/javascript" src="https://raw.githubusercontent.com/mrdoob/three.js/69079243426506ed86d0d0ea71b4fdda9dbb2f88/examples/js/controls/OrbitControls.js"></script
-->
<!-- Refused to execute script '...' because its MIME type ('text/plain') is not executable, and strict MIME type checking is enabled.
-->
<script type="text/javascript" src="./controls/OrbitControls.js"></script>
<body>
Written using C++ and ThreeJS.
<br>
<script>
//'use strict';
var WIREFRAME = false;
var make_object;
var main;
function init1()
{
make_object = Module.cwrap('make_object', null, ['number', 'number', 'number', 'number']);
main = Module.cwrap('main', 'number', []);
console.log("ok");
}
function do_it(q)
{
const VEC_SIZE = 3;
const ELEM_SIZE = 8;
var offset = Module._malloc(ELEM_SIZE*VEC_SIZE)
Module.HEAPF64.set(new Float64Array(q), offset/ELEM_SIZE);
//Module.HEAPF64 is a Float64Array
var r2 = Module.HEAPF64.subarray(offs2/ELEM_SIZE, offs2/ELEM_SIZE + VEC_SIZE);
return r2;
}
function do_vf()
{
//const DBLFLOAT_SIZE = 8;
const FLOAT_SIZE = 4;
const INT_SIZE = 4;
//4 int
//4 float
//4 long
//var max_verts = 2000 * 3; // *2
//var max_faces = 10000; //*5
var max_verts = 10000; // *2
var max_faces = 5000; //*5
var verts_address = Module._malloc(FLOAT_SIZE*3*max_verts);
var nv_address = Module._malloc(INT_SIZE*1);
var faces_address = Module._malloc(INT_SIZE*3*max_faces)
var nf_address = Module._malloc(INT_SIZE*1);
//Module.HEAPF64.set (new Float64Array(q), offset/DBLFLOAT_SIZE);
make_object(verts_address, nv_address, faces_address, nf_address);
// console.log("Patatee")
//Module.HEAPF64 is a Float64Array
var nverts = Module.HEAPU32[nv_address/INT_SIZE];
console.log("nverts : "+ nverts)
var nfaces = Module.HEAPU32[nf_address/INT_SIZE];
console.log("nfaces : "+ nfaces)
var verts = Module.HEAPF32.subarray(verts_address/FLOAT_SIZE, verts_address/FLOAT_SIZE + 3*nverts);
var faces = Module.HEAPU32.subarray(faces_address/INT_SIZE, faces_address/INT_SIZE + 3*nfaces);
//var verts = undefined;
return [verts, faces];
}
//init1();
//alert('Computing3: ' + JSON.stringify(do_vf() ));
var q = [2., 3, 4]
//alert('Computing2: ' + callvect(q));
//var r2 = do_it(q)
//console.log("Result:");
//console.log( do_it(q) );
//alert('Computing2: ' + JSON.stringify(r2));
//console.log(JSON.stringify( do_vf() ));
/*
function make_my_geometry()
{
vf = do_vf();
v = vf[0];
f = vf[1];
for(int vi=0; vi < v.length; vi++)
for(int di=0; di < 3; di++)
verts[vi*3+di] = verts1[vi][di];
for(int fi=0; fi < f.length; fi++)
for(int si=0; si < 3; si++)
faces[fi*3+si] = f1[fi][si];
return [v, f];
}
*/
MyBufferGeometry = function ( verts, faces, width, height, depth, widthSegments, heightSegments, depthSegments ) {
THREE.BufferGeometry.call( this );
this.type = 'MyBufferGeometry';
// console.log(verts);
width=20;
height=20;
depth=20;
widthSegments=undefined;
heightSegments=undefined;
depthSegments=undefined;
this.parameters = {
/*width: width,
height: height,
depth: depth,
widthSegments: widthSegments,
heightSegments: heightSegments,
depthSegments: depthSegments*/
};
var scope = this;
// segments
widthSegments = Math.floor( widthSegments ) || 1;
heightSegments = Math.floor( heightSegments ) || 1;
depthSegments = Math.floor( depthSegments ) || 1;
//var vcount = 24; //
//calculateVertexCount( widthSegments, heightSegments, depthSegments );
//vcount = verts.length/3;
// these are used to calculate buffer length
//var vertexCount = 24; //vcount;
//var indexCount = 36; //calculateIndexCount( widthSegments, heightSegments, depthSegments );
// var vertexCount = 24; //verts.length;
// var indexCount = 36; //faces.length;
// var vertexCount = calculateVertexCount( widthSegments, heightSegments, depthSegments );
// var indexCount = calculateIndexCount( widthSegments, heightSegments, depthSegments );
var vertexCount = verts.length/3;
var indexCount = faces.length;
var nbr_faces = indexCount/3;
console.log("vertexCount indexCount")
console.log(vertexCount+ " , " + indexCount);
// buffers
var indices = new ( indexCount > 65535 ? Uint32Array : Uint16Array )( indexCount );
// var vertices = new Float32Array( indexCount);
// var normals = new Float32Array( indexCount );
// var uvs = new Float32Array( indexCount * 2./3.0);
var vertices = new Float32Array( vertexCount*3 );
var normals = new Float32Array( vertexCount*3 );
var uvs = new Float32Array( vertexCount * 2.);
// offset variables
var vertexBufferOffset = 0;
var uvBufferOffset = 0;
var indexBufferOffset = 0;
var numberOfVertices = 0;
// group variables
var groupStart = 0;
// build each side of the box geometry
/*
buildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px
buildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx
buildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py
buildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny
buildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz
buildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz
*/
//output: vertices, normals, uvs, indices
SCALE = 1.
if(1){
//console.log(verts.length);
//console.log(faces.length);
console.log(verts);
console.log(faces);
//exfdgdg()
console.log("Vertexcount: "+vertexCount);
console.log("**************************************");
for(var i=0; i < vertexCount; i++)
{ var fi = i/3;
var si = i%3;
for(var di=0;di<3;di++)
// vertices[i*3+di] = verts[faces[fi*3+ si]*3+di] * SCALE;
// vertices[i*3+di] = verts[faces[i*3+di]]*SCALE;
// x = verts[faces[i*3+0]];
// y = verts[faces[i*3+1]];
// z = verts[faces[i*3+2]];
vertices[i*3+di] = verts[i*3+di]*SCALE;
x = verts[i*3+0];
y = verts[i*3+1];
z = verts[i*3+2];
// x = verts[faces[i]*3+0];
// y = verts[faces[i]*3+1];
// z = verts[faces[i]*3+2];
d = Math.sqrt(x*x+y*y+z*z);
d=d+0.;
//if(d==0) d=1.;
if(isNaN(d)) {
d=1.;x=1.;y=1.;z=1.;
console.log("Warning");
}
//console.log("x y z"+x+" "+y+" "+z+" / "+ d)
/*
if(Math.random()>0.5)
sgn=-1;
else
sgn = +1;
*/
sgn = +1;
normals[i*3 + 0] = x/d*sgn;
normals[i*3 + 1] = y/d*sgn;
normals[i*3 + 2] = z/d*sgn;
if(isNaN(x/d))
console.error("WARNING: NaN.");
//console.log("verts "+verts[i*3+0]+" "+verts[i*3+1]+" "+verts[i*3+2])
//console.log("d "+d)
//if(d<0.00001){
// sdsgf()
//}
d2 = Math.sqrt(x*x+y*y);
uvs[i*2+0] = x/d2;
uvs[i*2+1] = y/d2;
}
console.log(vertices);
for(var i=0; i < nbr_faces; i++)
for(var si=0; si<3; si++)
indices[i*3+si] = faces[i*3+si];
materialIndex = 0;
this.addGroup( 0, nbr_faces*3, materialIndex ); //not sure about *3 . Why??
// console.log(vertices);
// console.log(normals);
// console.log(uvs);
console.log(indices);
}
//this.addGroup( groupStart, groupCount, materialIndex ); //groupCount is same as indices' index.
//modified, but not output: indexBufferOffset, vertexBufferOffset, uvBufferOffset, numberOfVertices, groupStart
// build geometry
this.setIndex( new THREE.BufferAttribute( indices, 3 ) );
this.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
this.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
this.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) );
// helper functions
function calculateVertexCount ( w, h, d ) {
var vertices = 0;
// calculate the amount of vertices for each side (plane)
vertices += (w + 1) * (h + 1) * 2; // xy
vertices += (w + 1) * (d + 1) * 2; // xz
vertices += (d + 1) * (h + 1) * 2; // zy
return vertices;
}
function calculateIndexCount ( w, h, d ) {
var index = 0;
// calculate the amount of squares for each side
index += w * h * 2; // xy
index += w * d * 2; // xz
index += d * h * 2; // zy
return index * 6; // two triangles per square => six vertices per square
}
function buildPlane ( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) {
/* output: vertices, normals, uvs, vertexBufferOffset, uvBufferOffset
indices indexBufferOffset numberOfVertices groupStart
*/
var segmentWidth = width / gridX;
var segmentHeight = height / gridY;
var widthHalf = width / 2;
var heightHalf = height / 2;
var depthHalf = depth / 2;
var gridX1 = gridX + 1;
var gridY1 = gridY + 1;
var vertexCounter = 0;
var groupCount = 0;
var vector = new THREE.Vector3();
// generate vertices, normals and uvs
for ( var iy = 0; iy < gridY1; iy ++ ) {
var y = iy * segmentHeight - heightHalf;
for ( var ix = 0; ix < gridX1; ix ++ ) {
var x = ix * segmentWidth - widthHalf;
// set values to correct vector component
vector[ u ] = x * udir;
vector[ v ] = y * vdir;
vector[ w ] = depthHalf;
// now apply vector to vertex buffer
vertices[ vertexBufferOffset ] = vector.x;
vertices[ vertexBufferOffset + 1 ] = vector.y;
vertices[ vertexBufferOffset + 2 ] = vector.z;
// set values to correct vector component
vector[ u ] = 0;
vector[ v ] = 0;
vector[ w ] = depth > 0 ? 1 : - 1;
// now apply vector to normal buffer
normals[ vertexBufferOffset ] = vector.x;
normals[ vertexBufferOffset + 1 ] = vector.y;
normals[ vertexBufferOffset + 2 ] = vector.z;
// uvs
uvs[ uvBufferOffset ] = ix / gridX;
uvs[ uvBufferOffset + 1 ] = 1 - ( iy / gridY );
// update offsets and counters
vertexBufferOffset += 3;
uvBufferOffset += 2;
vertexCounter += 1;
}
}
// 1. you need three indices to draw a single face
// 2. a single segment consists of two faces
// 3. so we need to generate six (2*3) indices per segment
for ( iy = 0; iy < gridY; iy ++ ) {
for ( ix = 0; ix < gridX; ix ++ ) {
// indices
var a = numberOfVertices + ix + gridX1 * iy;
var b = numberOfVertices + ix + gridX1 * ( iy + 1 );
var c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 );
var d = numberOfVertices + ( ix + 1 ) + gridX1 * iy;
// face one
indices[ indexBufferOffset ] = a;
indices[ indexBufferOffset + 1 ] = b;
indices[ indexBufferOffset + 2 ] = d;
// face two
indices[ indexBufferOffset + 3 ] = b;
indices[ indexBufferOffset + 4 ] = c;
indices[ indexBufferOffset + 5 ] = d;
// update offsets and counters
indexBufferOffset += 6;
groupCount += 6;
}
}
// add a group to the geometry. this will ensure multi material support
scope.addGroup( groupStart, groupCount, materialIndex );
// calculate new start value for groups
groupStart += groupCount;
// update total number of vertices
numberOfVertices += vertexCounter;
}
};
MyBufferGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
MyBufferGeometry.prototype.constructor = MyBufferGeometry;
MyGeometry = function (verts, faces) {
//vects, faces
THREE.Geometry.call( this );
this.type = 'ImplicitGeometry'; //?
this.parameters = {
/*width: width,
height: height,
depth: depth,
widthSegments: widthSegments,
heightSegments: heightSegments,
depthSegments: depthSegments*/
};
//faces = faces.subarray(0, 300);
this.fromBufferGeometry( new MyBufferGeometry( verts, faces ) );
//this.mergeVertices();
};
MyGeometry.prototype = Object.create( THREE.Geometry.prototype );
MyGeometry.prototype.constructor = MyGeometry;
//var zz=new MyGeometry();
//console.log(zz);
function make_geometry()
{
vf = do_vf();
v = vf[0];
f = vf[1];
//console.log(v);
//console.log(f);
//scale
return new MyGeometry(v, f);
}
function cut_away(){
//return new THREE.BoxGeometry( 200, 200, 200 );
/*
var geometry = new THREE.Geometry();
//console.log(v);
console.log(v.length/3.);
for(var vi=0; vi < v.length/3; vi++)
{
geometry.vertices.push(
new THREE.Vector3( v[vi*3 + 0], v[vi*3 + 1], v[vi*3 + 2] )
);
}
geometry.faces.push( new THREE.Face3( 0, 1, 2 ) );
geometry.faces.push( new THREE.Face3( 0, 1, 3 ) );
geometry.computeFaceNormals();
geometry.computeBoundingSphere();
*/
//geometry
//return geometry;
/*
this = geometry;
var positions = new THREE.BufferAttribute( new Float32Array( vertexCount * 3 ), 3 );
var normals = new THREE.BufferAttribute( new Float32Array( vertexCount * 3 ), 3 );
var uvs = new THREE.BufferAttribute( new Float32Array( vertexCount * 2 ), 2 );
this.setIndex( new ( positions.count > 65535 ? THREE.Uint32Attribute : THREE.Uint16Attribute )( indices, 1 ) );
this.addAttribute( 'position', positions );
this.addAttribute( 'normal', normals );
this.addAttribute( 'uv', uvs );
this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius );
*/
if(0)
{
geometry = new THREE.BufferGeometry();
positions = new THREE.BufferAttribute( v );
//geometry.addAttribute( 'position', positions );
//this.addAttribute( 'normal', normals );
//this.addAttribute( 'uv', uvs );
//indices = f;
indices = []
for(var i=0; i < f.length; i++)
indices.push( f[i] );
console.log( indices );
geometry.setIndex( new ( positions.count > 65535 ? THREE.Uint32Attribute : THREE.Uint16Attribute )( indices, 1 ) );
geometry.addAttribute( 'position', positions );
/*
this.addAttribute( 'normal', normals );
this.addAttribute( 'uv', uvs );
*/
geometry.computeFaceNormals();
geometry.computeBoundingSphere();
return geometry;
}
if(0){
var geom = new THREE.Geometry();
for(var i=0; i < v.length; i++)
//geom.vertices.push( new THREE.Vector3(v[i][0], v[i][1], v[i][2] ) );
geom.vertices.push( v[i][0], v[i][1], v[i][2] );
for(var i=0; i < f.length; i++)
//geom.faces.push( new THREE.Face3( f[i][0], f[i][1], f[i][2] ) );
geom.faces.push( f[i][0], f[i][1], f[i][2] );
console.log(geom.vertices);
console.log(geom.faces);
geom.computeFaceNormals();
geom.computeBoundingSphere();
return geom;
}
}
mesh = null;
function init2() {
scene = new THREE.Scene();
WIDTH = 300;
HEIGHT = 300;
WIDTH = window.innerWidth;
HEIGHT = window.innerHeight;
camera = new THREE.PerspectiveCamera( 75, WIDTH / HEIGHT, 1, 10000 );
camera.position.z = 1000;
materials_list = look_nice(scene);
material = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: true, opacity:0.3, transparent: true, } );
if(1){
//geometry = new THREE.BoxGeometry( 200, 200, 200 );
geometry = make_geometry();
//geometry = new MyGeometry();
mesh = new THREE.Mesh( geometry, material );
mesh.position.set( 0, 0, 0 );
//mesh.scale.set( 10*10, 10*10, 10*10 );
mesh.scale.set( 300, 300, 300 );
//mesh.position.z = +0;
//mesh.rotation.y = -Math.PI * .5;
scene.add( mesh );
//this.fromBufferGeometry( new THREE.SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) );
}
material_f = new THREE.MeshBasicMaterial( { color: 0xffffff, wireframe: false, opacity:0.4, transparent: true } );
//meshf = new THREE.Mesh( geometry, material_f );
//nice ones: 2, 3, (checked until 4)
meshf = new THREE.Mesh( geometry, materials_list[3] );
meshf.position.set( 0, 0, 0 );
meshf.scale.set( 300, 300, 300 );
scene.add( meshf );
geo2 = new THREE.BoxGeometry( 20, 20, 20 );
mesh2 = new THREE.Mesh( geo2, material );
mesh2.position.set( 0, 0, 0 );
scene.add( mesh2 );
//mesh2.scale.set( 10, 10, 10 );
var dirLight = new THREE.DirectionalLight(0xffffff, 1);
dirLight.position.set(100, 100, 50);
scene.add(dirLight);
console.log("RENDERER");
renderer = new THREE.WebGLRenderer( { antialias: true } );
//renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setSize( WIDTH, HEIGHT );
document.body.appendChild( renderer.domElement );
// CONTROLS
//see https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometry_teapot.html
cameraControls = new THREE.OrbitControls( camera, renderer.domElement );
cameraControls.target.set( 0, 0, 0 );
cameraControls.addEventListener( 'change', function () {;} );
}
//based on http://threejs.org/examples/#webgl_materials
function generateTexture() {
var canvas = document.createElement( 'canvas' );
canvas.width = 256;
canvas.height = 256;
var context = canvas.getContext( '2d' );
var image = context.getImageData( 0, 0, 256, 256 );
var x = 0, y = 0;
for ( var i = 0, j = 0, l = image.data.length; i < l; i += 4, j ++ ) {
x = j % 256;
y = x == 0 ? y + 1 : y;
image.data[ i ] = 255;
image.data[ i + 1 ] = 255;
image.data[ i + 2 ] = 255;
image.data[ i + 3 ] = Math.floor( x ^ y );
}
context.putImageData( image, 0, 0 );
return canvas;
}
function look_nice(scene){
var materials = [];
// Grid
var line_material = new THREE.LineBasicMaterial( { color: 0x303030 } ),
geometry = new THREE.Geometry(),
floor = -75, step = 25;
for ( var i = 0; i <= 40; i ++ ) {
geometry.vertices.push( new THREE.Vector3( - 500, floor, i * step - 500 ) );
geometry.vertices.push( new THREE.Vector3( 500, floor, i * step - 500 ) );
geometry.vertices.push( new THREE.Vector3( i * step - 500, floor, -500 ) );
geometry.vertices.push( new THREE.Vector3( i * step - 500, floor, 500 ) );
}
var line = new THREE.LineSegments( geometry, line_material );
scene.add( line );
// Materials
var texture = new THREE.Texture( generateTexture() );
texture.needsUpdate = true;
materials.push( new THREE.MeshLambertMaterial( { map: texture, transparent: true } ) );
materials.push( new THREE.MeshLambertMaterial( { color: 0xdddddd, shading: THREE.FlatShading } ) );
materials.push( new THREE.MeshPhongMaterial( { color: 0xdddddd, specular: 0x009900, shininess: 30, shading: THREE.FlatShading } ) );
materials.push( new THREE.MeshNormalMaterial( ) );
materials.push( new THREE.MeshBasicMaterial( { color: 0xffaa00, transparent: true, blending: THREE.AdditiveBlending } ) );
//materials.push( new THREE.MeshBasicMaterial( { color: 0xff0000, blending: THREE.SubtractiveBlending } ) );
materials.push( new THREE.MeshLambertMaterial( { color: 0xdddddd, shading: THREE.SmoothShading } ) );
materials.push( new THREE.MeshPhongMaterial( { color: 0xdddddd, specular: 0x009900, shininess: 30, shading: THREE.SmoothShading, map: texture, transparent: true } ) );
materials.push( new THREE.MeshNormalMaterial( { shading: THREE.SmoothShading } ) );
materials.push( new THREE.MeshBasicMaterial( { color: 0xffaa00, wireframe: true } ) );
materials.push( new THREE.MeshDepthMaterial() );
materials.push( new THREE.MeshLambertMaterial( { color: 0x666666, emissive: 0xff0000, shading: THREE.SmoothShading } ) );
materials.push( new THREE.MeshPhongMaterial( { color: 0x000000, specular: 0x666666, emissive: 0xff0000, shininess: 10, shading: THREE.SmoothShading, opacity: 0.9, transparent: true } ) );
materials.push( new THREE.MeshBasicMaterial( { map: texture, transparent: true } ) );
return materials;
}
function animate() {
requestAnimationFrame( animate );
//var SPEED = 0;
var SPEED = 3. / 100;
if(mesh){
mesh.rotation.x += 0.01*SPEED;
mesh.rotation.y += 0.02*SPEED;
meshf.rotation.x += 0.01*SPEED;
meshf.rotation.y += 0.02*SPEED;
}
mesh2.rotation.z += 0.01*SPEED;
mesh2.rotation.y += 0.02*SPEED;
//materials_list[ materials.length - 2 ].emissive.setHSL( 0.54, 1, 0.35 * ( 0.5 + 0.5 * Math.sin( 35 * timer ) ) );
//materials_list[ materials.length - 3 ].emissive.setHSL( 0.04, 1, 0.35 * ( 0.5 + 0.5 * Math.cos( 35 * timer ) ) );
renderer.render( scene, camera );
}
var scene, camera, renderer;
var geometry, material, mesh;
window.setTimeout(function()
{
init1();
init2();
animate();
}, 2000);
</script>