Greetings,
My name is Andreas Pappas and I’m working at CERN for the LHCb experiment.
I’m working on a modern visualization application for LHCb event data and geometry and currently I have a fulllhcb.root file ( the one that is used as well in the jsroot itself link)
I’ve already made 2 exporters, one to generate a .gltf file from the root one and one to generate a .json.gz ( three.js json format )
My problem is that my web browser tool to display the generated files does not render properly the json.gz one but it renders properly .gltf file. You can have a look here ~> link
So after all this introduction I wanted to ask if someone can help me on exporting multiple .gltf
files from one
root file. So for example for LHCb specifically I would like to generate multiple .gltf files and i.e. one for the velo, one for the magnet, one for the Ecalorimeter, Hcalorimeter and so on. So basically multiple .gltf files for each subdetector or even each geometry object from the root file itself maybe?
At this point I will provide the 2 exporters I already have, as well as the root file and the .gltf file
root to .json.gz exporter using node.js
let jsroot = require("jsroot");
let fs = require("fs");
var zlib = require('zlib');
console.log('JSROOT version', jsroot.version);
function exportGeometry(obj) {
let opt = { numfaces: 100000, numnodes: 1000, wireframe: false };
if (d.has("all")) {
opt.numfaces *= 100;
opt.numnodes *= 100;
}
if (d.has("dflt") || d.has("dflt_colors"))
opt.dflt_colors = true;
let volumes = obj.fMasterVolume.fNodes.arr
let top_volumes_names = []
for (var i in volumes) {
const name = volumes[i].fName
top_volumes_names.push(name)
console.log(i, name)
}
let obj3d = jsroot.GEO.build(obj, opt);
if (!obj3d) return;
let data = obj3d.toJSON();
data["info"] = []
// add additional info to json
for (var i in top_volumes_names) {
const name = top_volumes_names[i]
console.log(i, name, data["geometries"][i])
data["info"].push(top_volumes_names[i])
}
const outputFileName = "old_LHCb_geometry.json";
fs.writeFileSync(outputFileName, JSON.stringify(data));
// save also compressed
out = fs.createWriteStream(outputFileName + ".gz");
var gzip = zlib.createGzip();
const input = fs.createReadStream(outputFileName);
input.pipe(gzip).pipe(out);
}
function main() {
d = jsroot.decodeUrl();
{
let filename = "./lhcbfull.root"
if (filename.indexOf(".root") > 0) {
// it is a ROOT file, must include a 'geo' key with the geometry (TGeoManager)
let itemname = "Geometry;1";
jsroot.openFile(filename)
.then(file => file.readObject(itemname))
.then(exportGeometry);
}
}
}
jsroot.require('geom').then(main);
root to .gltf exporter
<html>
<head>
<meta charset=utf-8>
<title>Test display</title>
<style>
body {
margin: 0;
}
canvas {
width: 100%;
height: 100%
}
</style>
<script src="jsroot/node_modules/three/build/three.js"></script>
<script src="jsroot/node_modules/three/examples/js/controls/OrbitControls.js"></script>
<script src="GLTFExporter.js"> </script>
<script src="jsroot/scripts/JSRootCore.js?geom&onload=init" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.8/FileSaver.js"></script>
</head>
<body>
<div id="mylog" style="block"></div>
<script>
var mylog = document.getElementById('mylog');
var container, stats;
var camera, scene, renderer, controls;
var mouse = new THREE.Vector2(),
INTERSECTED;
var alllines = new THREE.Object3D();
var rootgeom;
var detector;
var to_hide = ["HcalInstallationlvHcalInnerSupportFrame",
"MagnetYoke", "ITlvAirVolume", "EcalModules", "HcalModules", "VeloVacTank", "VeloRFBox",
"VeloRFFoil", "PipeSection", "Rich1lvRich1Mgs", "Rich1lvRich1MagSh", "Rich1lvRich1Exit",
"Velo2Rich", "Rich2lvRich2MagSh", "Rich2lvRich2Tube"];
var hide_children = ["HcalInstallationlvHcal_4825", "EcalInstallationEcal_4826"];
function process_root_node(node, level = 0, path = "") {
//mylog.innerHTML += path + " " + level + " " + node.fName + "\n";
tmpname = node.fName;
iterate_children = true;
//console.log("processing:", tmpname, path, node)
for (let i = 0; i < to_hide.length; i++) {
item = to_hide[i];
//console.log("Checking:", item);
if (tmpname.startsWith(item)) {
node.fVolume.fGeoAtt = 0;
}
}
for (let i = 0; i < hide_children.length; i++) {
item = hide_children[i];
//console.log("Checking:", item);
if (tmpname.startsWith(item)) {
node.fVolume.fGeoAtt = 4;
iterate_children = false;
//console.log("Matched", item, tmpname, path)
}
}
//console.log("subvolume:", tmpname, node);
if (node.fVolume.fNodes && iterate_children) {
for (let j = 0; j < node.fVolume.fNodes.arr.length; j++) {
snode = node.fVolume.fNodes.arr[j];
process_root_node(snode, level + 1, path + "/" + tmpname);
}
}
}
function add_geometry(obj) {
// options for building three.js model
var opt = {
numfaces: 5000000,
numnodes: 50000,
dflt_colors: true,
vislevel: 4
};
console.log(obj);
rootgeom = obj;
process_root_node(obj.fNodes.arr[0], 0, "");
var obj3d = JSROOT.GEO.build(obj, opt, display_geometry);
}
function display_geometry(obj3d) {
console.log("DISPLAYING", obj3d);
if (!obj3d) return;
detector = obj3d;
scene.add(obj3d);
var box3 = new THREE.Box3().setFromObject(obj3d);
geom_size = box3.getSize().length();
camera.far = geom_size * 5;
camera.updateProjectionMatrix();
postinit();
}
function loadgeo() {
container = document.createElement('div');
document.body.appendChild(container);
// renderer
renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0xFFFFFF);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
//renderer.setFaceCulling(false);
renderer.sortObjects = false;
container.appendChild(renderer.domElement);
var info = document.createElement('div');
info.style.position = 'absolute';
info.style.top = '10px';
info.style.width = '100%';
info.style.textAlign = 'center';
// camera
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(-10000, 1000, 3000);
//camera.up.set(0.0, 1.0, 0.0);
// controls
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.target.set(0.0, 0.0, 8);
// scene
scene = new THREE.Scene();
var filename = "lhcbfull.root"
JSROOT.OpenFile(filename, function (file) {
file.ReadObject("Geometry;1", add_geometry);
});
}
function postinit() {
// Particles
// line 1
var linegeometry1 = new THREE.Geometry();
var line1 = new THREE.Line(linegeometry1, new THREE.LineBasicMaterial({
color: 0x00033
}));
linegeometry1.vertices.push(new THREE.Vector3(0, 0, -1500));
linegeometry1.vertices.push(new THREE.Vector3(1000, 1000, 15000));
alllines.add(line1);
// line 2
var linegeometry2 = new THREE.Geometry();
var line2 = new THREE.Line(linegeometry2, new THREE.LineBasicMaterial({
color: 0x00033
}));
linegeometry2.vertices.push(new THREE.Vector3(0, 0, -1500));
linegeometry2.vertices.push(new THREE.Vector3(-1000, 1000, 15000));
alllines.add(line2);
//line 3
var linegeometry3 = new THREE.Geometry();
var line3 = new THREE.Line(linegeometry3, new THREE.LineBasicMaterial({
color: 0x00033
}));
linegeometry3.vertices.push(new THREE.Vector3(0, 0, -1500));
linegeometry3.vertices.push(new THREE.Vector3(-1000, -1000, 15000));
alllines.add(line3);
scene.add(alllines);
scene.add(new THREE.AmbientLight(0xff0000, 0.8));
var light = new THREE.DirectionalLight(0x00ff00, 1);
light.position.set(-100, 4000, -10000); //.normalize();
scene.add(light);
window.addEventListener('resize', onWindowResize, false);
var doexport = true;
if (doexport) {
options = {};
GLTFExporter.parse(detector, function (gltf) {
console.log(gltf);
var fileToSave = new Blob([JSON.stringify(gltf)], {
type: 'application/json',
name: "lhcb.gltf"
});
// Save the file
saveAs(fileToSave, "lhcb.gltf");
}, options);
}
animate();
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
renderer.render(scene, camera);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
</script>
<script>
function init() {
console.log("In init");
loadgeo();
}
</script>
</body>
It would be ideal if you could help me also modify somehow the .gltf exporter to use it with node.js and not as a javascript application in the browser since I want only to use it to generate the multiple .gltf files from the single give root file.
Thank you very much in advance for your time and effort on this!
Best regards,
Andreas Pappas
P.S. Here you can file the root file mentioned. Unfortunately I'm not able to upload the generated .gltf file because it is too large. But if you use the exporter mentioned above and the following root file then the .gltf will be generated properly.
lhcbfull.root (328.2 KB)