Hi!
Short version:
I want to build a website where I can load and render/view a 3D lego model from a .io or .ldr file.
So I only need a view window within the html file where I can view, zoom and rotate the lego model.
What is the easiert way for that?
More detailed version:
Here are 2 example files (I can open and view the .io file in Studio 2.0 from Brick Link):
BUILD_Schere-Stein-Papier_v1.0.io (205.8 KB)
BUILD_Schere-Stein-Papier_v1.0.ldr (10.7 KB)
Note: The .ldr file is obtained by conversion from the .io file (so I cannot 100% guarantee that it is correct)
I already downloaded the parts from the official site LDraw.org website and tried some renderers from the internet for .ldr files (including ThreeJS and LDraw). None of them worked. In the web tools command line, I got some missing parts errors, even tough I downloaded all parts I could find. It seemed there were some case sensitive naming issues (some parts where named .DAT but the lego “compiler” seemed to search for them as .dat and couldn’t find them). But there where too many parts to rename them manually. So the error seemed strange. Why could Studio 2.0 render the file and the Web renderer not?
Can anyone help with this problem?
So basically, I need a .io or .ldr viewer for web pages.
And, if possible, I need a place where I can test if my models are correct (at least the converted .ldr file) → but only if I go for .ldr rendering (the .io file should be fine)
Here is how I tried to use three.js webgl - LDrawLoader:
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - LDrawLoader</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
font-family: Monospace;
background-color: #000;
color: #fff;
margin: 0px;
overflow: hidden;
}
#info {
color: #fff;
position: absolute;
top: 10px;
width: 100%;
text-align: center;
z-index: 100;
display:block;
}
#info a, .button { color: #f00; font-weight: bold; text-decoration: underline; cursor: pointer }
</style>
</head>
<body>
<div id="info">
<a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> - LDrawLoader
</div>
<script src="../build/three.js"></script>
<script src="js/loaders/LDrawLoader.js"></script>
<script src="js/controls/OrbitControls.js"></script>
<script src='js/libs/dat.gui.min.js'></script>
<script>
var container, stats, progressBar, progressBarDiv;
var camera, scene, renderer, pointLight, controls, gui, guiData;
var modelFileList, model, textureCube;
var envMapActivated = false;
var ldrawPath = 'models/ldraw/officialLibrary/';
var modelFileList = {
'SSP': 'models/BUILD_Schere-Stein-Papier_v1.0.ldr',
'Car': 'models/car.ldr_Packed.mpd',
'Lunar Vehicle': 'models/1621-1-LunarMPVVehicle.mpd_Packed.mpd',
'Radar Truck': 'models/889-1-RadarTruck.mpd_Packed.mpd',
'Trailer': 'models/4838-1-MiniVehicles.mpd_Packed.mpd',
'Bulldozer': 'models/4915-1-MiniConstruction.mpd_Packed.mpd',
'Helicopter': 'models/4918-1-MiniFlyers.mpd_Packed.mpd',
'Plane': 'models/5935-1-IslandHopper.mpd_Packed.mpd',
'Lighthouse': 'models/30023-1-Lighthouse.ldr_Packed.mpd',
'X-Wing mini': 'models/30051-1-X-wingFighter-Mini.mpd_Packed.mpd',
'AT-ST mini': 'models/30054-1-AT-ST-Mini.mpd_Packed.mpd',
'AT-AT mini': 'models/4489-1-AT-AT-Mini.mpd_Packed.mpd',
'Shuttle': 'models/4494-1-Imperial Shuttle-Mini.mpd_Packed.mpd',
'TIE Interceptor': 'models/6965-1-TIEIntercep_4h4MXk5.mpd_Packed.mpd',
'Star fighter': 'models/6966-1-JediStarfighter-Mini.mpd_Packed.mpd',
'X-Wing': 'models/7140-1-X-wingFighter.mpd_Packed.mpd',
'AT-ST': 'models/10174-1-ImperialAT-ST-UCS.mpd_Packed.mpd'
};
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set( 150, 200, 250 );
// scene
scene = new THREE.Scene();
var ambientLight = new THREE.AmbientLight( 0xcccccc, 0.4 );
scene.add( ambientLight );
pointLight = new THREE.PointLight( 0xffffff, 1 );
pointLight.position.set( -1000, 1200, 1500 );
scene.add( pointLight );
//
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
controls = new THREE.OrbitControls( camera, renderer.domElement );
//
guiData = {
modelFileName: modelFileList[ 'SSP' ],
envMapActivated: false
};
gui = new dat.GUI( { width: 350 } );
var modelFolder = gui.addFolder( "Model" );
modelFolder.add( guiData, 'modelFileName', modelFileList ).name( 'Model' ).onFinishChange( function () {
reloadObject( true );
} );
modelFolder.open();
var graphicsFolder = gui.addFolder( "Graphics" );
graphicsFolder.add( guiData , 'envMapActivated' ).name( 'Env. map' ).onChange( function ( value ) {
envMapActivated = value;
reloadObject( false );
} );
graphicsFolder.open();
window.addEventListener( 'resize', onWindowResize, false );
progressBarDiv = document.createElement( 'div' );
progressBarDiv.innerText = "Loading...";
progressBarDiv.style.fontSize = "3em";
progressBarDiv.style.display = "block";
progressBarDiv.style.position = "absolute";
progressBarDiv.style.top = "50%";
progressBarDiv.style.left = "50%";
// load materials and then the model
reloadObject( true );
}
function reloadObject ( resetCamera ) {
if ( model ) {
scene.remove( model );
}
model = null;
updateProgressBar( 0 );
showProgressBar();
var lDrawLoader = new THREE.LDrawLoader();
lDrawLoader
.setPath( ldrawPath )
.load( guiData.modelFileName, function ( group2 ) {
if ( model ) {
scene.remove( model );
}
model = group2;
// Convert from LDraw coordinates: rotate 180 degrees around OX
model.rotation.x = Math.PI;
scene.add( model );
// Adjust materials
var materials = lDrawLoader.materials;
if ( envMapActivated ) {
if ( ! textureCube ) {
// Envmap texture
var r = "textures/cube/Bridge2/";
var urls = [ r + "posx.jpg", r + "negx.jpg",
r + "posy.jpg", r + "negy.jpg",
r + "posz.jpg", r + "negz.jpg" ];
textureCube = new THREE.CubeTextureLoader().load( urls );
textureCube.format = THREE.RGBFormat;
textureCube.mapping = THREE.CubeReflectionMapping;
}
for ( var i = 0, n = materials.length; i < n; i ++ ) {
var material = materials[ i ];
if ( material.userData.canHaveEnvMap ) {
material.envMap = textureCube;
}
};
}
// Adjust camera and light
var bbox = new THREE.Box3().setFromObject( model );
var size = bbox.getSize( new THREE.Vector3() );
var radius = Math.max( size.x, Math.max( size.y, size.z ) ) * 0.5;
if ( resetCamera ) {
controls.target0.copy( bbox.getCenter( new THREE.Vector3() ) );
controls.position0.set( - 2.3, 2, 2 ).multiplyScalar( radius ).add( controls.target0 );
controls.reset();
}
pointLight.position.normalize().multiplyScalar( radius * 3 );
hideProgressBar();
}, onProgress, onError );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
//
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
renderer.render( scene, camera );
}
function onProgress ( xhr ) {
if ( xhr.lengthComputable ) {
updateProgressBar( xhr.loaded / xhr.total );
console.log( Math.round( xhr.loaded / xhr.total * 100, 2 ) + '% downloaded' );
}
}
function onError ( error ) {
var message = "Error loading model";
progressBarDiv.innerText = message;
console.log( message );
}
function showProgressBar () {
document.body.appendChild( progressBarDiv );
}
function hideProgressBar () {
document.body.removeChild( progressBarDiv );
}
function updateProgressBar ( fraction ) {
progressBarDiv.innerText = 'Loading... ' + Math.round( fraction * 100, 2 ) + '%';
}
</script>
<!-- LDraw.org CC BY 2.0 Parts Library attribution -->
<div style="display: block; position: absolute; bottom: 0px; right: 0px; width: 160px; padding: 2px; border: #838A92 1px solid; background-color: #F3F7F8;">
<center>
<a href="http://www.ldraw.org"><img style="width: 145px" src="files/ldraw_org_logo/Stamp145.png"></a>
<br />
<a href="http://www.ldraw.org/">This software uses the LDraw Parts Library</a>
</center>
</div>
</body>
</html>
It worked with some demo .mpd files (that I did not need), but I didn’t work with my .ldr file (the Missing Parts Error came up)