1
0
mirror of https://github.com/ToxicCrack/PrintABrick.git synced 2025-05-16 20:30:09 -07:00

Add 3D view toggle

This commit is contained in:
David Hübner 2017-04-08 11:24:20 +02:00
parent db7195e4d3
commit 88c443b4ed
6 changed files with 159 additions and 76 deletions

View File

@ -1,45 +1,75 @@
var ModelViewer = function($container) { var ModelViewer = function($dom_element) {
var $this = this; var $this = this;
this.container = $container; this.container = document.createElement('div');
this.dom_element = $dom_element;
$dom_element.append(this.container);
this.container.style.display = "none";
this.camera = null; this.camera = null;
this.scene = null; this.scene = null;
this.renderer = null; this.renderer = null;
this.controls = null; this.controls = null;
this.object = null; this.object = null;
this.width = parseFloat(this.container.width()); this.width = parseFloat($dom_element.width());
this.height = parseFloat(this.container.height()); this.height = parseFloat($dom_element.height());
this.visible = true; this.visible = true;
this.stats = null;
this.scale = 1; this.scale = 1;
this.wireframe = false;
this.rendering = false;
this.initHtml();
this.initScene(); this.initScene();
function renderLoop() { function renderLoop() {
requestAnimationFrame(renderLoop); requestAnimationFrame(renderLoop);
if($this.rendering) {
$this.render(); $this.render();
} }
$this.stats.update();
}
renderLoop(); renderLoop();
}; };
ModelViewer.prototype.initHtml = function () {
$this = this;
var buttons = document.createElement("div");
buttons.setAttribute("class", "modelviewer-buttons");
var toggleButton = $('<button/>', {
'class':'toggle',
'html':'<span>3D View</span>',
'click': $this.toggleRendering.bind($this)
}).appendTo(buttons);
this.dom_element.append(buttons);
};
ModelViewer.prototype.initScene = function() { ModelViewer.prototype.initScene = function() {
this.scene = new THREE.Scene(); this.scene = new THREE.Scene();
this.scene.background = new THREE.Color( 0xffffff );
this.camera = new THREE.PerspectiveCamera(45, this.width / this.height, 1, 1000); this.camera = new THREE.PerspectiveCamera(45, this.width / this.height, 1, 300);
this.camera.position.z = 8; this.camera.position.z = 7;
this.camera.position.y = -5; this.camera.position.y = -5;
this.camera.position.x = 3; this.camera.position.x = 3;
this.camera.up = new THREE.Vector3(0, 0, 1); this.camera.up = new THREE.Vector3(0, 0, 1);
this.reflectCamera = new THREE.CubeCamera(1, 50, 200); // this.reflectCamera = new THREE.CubeCamera(1, 50, 100);
this.scene.add(this.reflectCamera); // this.scene.add(this.reflectCamera);
this.scene.fog = new THREE.FogExp2(0xbbbbbb, 0.2);
var material = new THREE.MeshPhongMaterial({ var material = new THREE.MeshPhongMaterial({
color: 0xffffff, color: 0xffffff,
emissive: 0xffffff, emissive: 0xffffff,
shading: THREE.SmoothShading, shading: THREE.SmoothShading,
fog: false, fog: true,
side: THREE.BackSide side: THREE.BackSide
}); });
@ -48,13 +78,13 @@ ModelViewer.prototype.initScene = function() {
this.scene.add(skybox); this.scene.add(skybox);
var groundPlaneMaterial = new THREE.MeshPhongMaterial({ var groundPlaneMaterial = new THREE.MeshPhongMaterial({
color: 0x888888, color: 0x999999,
wireframe: false, wireframe: false,
transparent: true, transparent: true,
opacity: 0.25, opacity: 0.25,
// fog: true, fog: false,
// specular: 0x999999, specular: 0x999999,
envMap: this.reflectCamera.renderTarget // envMap: this.reflectCamera.renderTarget
}); });
var x = 80; var x = 80;
var y = 80; var y = 80;
@ -86,47 +116,54 @@ ModelViewer.prototype.initScene = function() {
this.renderer = new THREE.WebGLRenderer(); this.renderer = new THREE.WebGLRenderer();
this.renderer.setSize(this.width, this.height); this.renderer.setSize(this.width, this.height);
this.renderer.setPixelRatio(window.devicePixelRatio ? window.devicePixelRatio : 1);
this.container.append(this.renderer.domElement); this.container.append(this.renderer.domElement);
// this.renderer.shadowMap.enabled = true;
// this.renderer.shadowMap.renderReverseSided = false;
this.scene.fog = new THREE.FogExp2(0xcacaca, 0.9);
// // Light this.controls = new THREE.OrbitControls( this.camera, this.renderer.domElement );
this.spotLight = new THREE.SpotLight(0xffffff, 0.9, 0); this.controls.enableZoom = true;
this.spotLight.position.set(-70, 100, 100);
this.initLights();
this.stats = new Stats();
this.container.append( this.stats.dom );
};
ModelViewer.prototype.initLights = function () {
this.spotLight = new THREE.SpotLight(0xffffff, 0.8, 0);
this.spotLight.position.set(-100, 100, 100);
this.spotLight.castShadow = false; this.spotLight.castShadow = false;
this.scene.add(this.spotLight); this.scene.add(this.spotLight);
this.bottomSpotLight = new THREE.SpotLight(0xffffff, 0.3, 0); this.bottomSpotLight = new THREE.SpotLight(0xffffff, 0.5, 0);
this.bottomSpotLight.position.set(70, -100, -100); this.bottomSpotLight.position.set(70, -100, -100);
this.bottomSpotLight.castShadow = false; this.bottomSpotLight.castShadow = false;
this.scene.add(this.bottomSpotLight); this.scene.add(this.bottomSpotLight);
this.ambientLight = new THREE.AmbientLight(0xffffff, 0.1);
this.scene.add(this.ambientLight);
this.pointLight = new THREE.PointLight(0xffaaff, 0.9, 0); this.pointLight = new THREE.PointLight(0xfdfdfd, 1, 0);
this.pointLight.position.set(32, -39, 35); this.pointLight.position.set(32, -39, 35);
this.pointLight.castShadow = true; this.pointLight.castShadow = true;
this.scene.add(this.pointLight); this.scene.add(this.pointLight);
this.renderer.shadowMap.enabled = true;
this.renderer.shadowMap.renderReverseSided = false;
// $container.append(this.renderer.domElement);
this.controls = new THREE.OrbitControls( this.camera, this.renderer.domElement );
this.controls.enableZoom = true;
}; };
ModelViewer.prototype.addModel = function(geometry) { ModelViewer.prototype.addModel = function(geometry) {
var material = new THREE.MeshPhongMaterial({ var material = new THREE.MeshPhongMaterial({
color: 0x136FC3, color: 0x1379d7,
specular: 0x0D0D0D, specular: 0x0D0D0D,
shading: THREE.SmoothShading, shading: THREE.SmoothShading,
shininess: 150, shininess: 30,
fog: false, fog: false,
side: THREE.DoubleSide, side: THREE.DoubleSide,
// wireframe: true, wireframe: this.wireframe,
}); });
geometry.center(); geometry.center();
@ -179,7 +216,8 @@ ModelViewer.prototype.centerCamera = function(mesh) {
var geometry = mesh.geometry; var geometry = mesh.geometry;
var distanceX = (geometry.boundingBox.max.x - geometry.boundingBox.min.x) / 2 / Math.tan(this.camera.fov * this.camera.aspect * Math.PI / 360);
var distanceX = ((geometry.boundingBox.max.x - geometry.boundingBox.min.x) / 2) / Math.tan(this.camera.fov * this.camera.aspect * Math.PI / 360);
var distanceY = (geometry.boundingBox.max.y - geometry.boundingBox.min.y) / 2 / Math.tan(this.camera.fov * this.camera.aspect * Math.PI / 360); var distanceY = (geometry.boundingBox.max.y - geometry.boundingBox.min.y) / 2 / Math.tan(this.camera.fov * this.camera.aspect * Math.PI / 360);
var distanceZ = (geometry.boundingBox.max.z - geometry.boundingBox.min.z) / 2 / Math.tan(this.camera.fov * Math.PI / 360); var distanceZ = (geometry.boundingBox.max.z - geometry.boundingBox.min.z) / 2 / Math.tan(this.camera.fov * Math.PI / 360);
@ -195,6 +233,16 @@ ModelViewer.prototype.centerCamera = function(mesh) {
this.controls.reset(); this.controls.reset();
}; };
ModelViewer.prototype.toggleRendering = function () {
if($this.rendering) {
$this.container.style.display = "none";
$this.rendering = false;
} else {
$this.container.style.display = "block";
$this.rendering = true;
}
};
ModelViewer.prototype.objectCenter = function (mesh) { ModelViewer.prototype.objectCenter = function (mesh) {
var middle = new THREE.Vector3(); var middle = new THREE.Vector3();
var geometry = mesh.geometry; var geometry = mesh.geometry;

View File

@ -0,0 +1,25 @@
.model-container {
width:600px;
height: 400px;
position: relative;
img {
width: 100%;
height: 100%;
}
.modelviewer-buttons {
position: absolute;
top: 0;
height: 30px;
width: 100%;
}
#model-viewer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
}

View File

@ -1,3 +1,4 @@
@import "variables"; @import "variables";
@import "main"; @import "main";
@import "modelviewer";

View File

@ -7,6 +7,11 @@
{% block header %}{{ model.name }}{% endblock %} {% block header %}{{ model.name }}{% endblock %}
{% block content %} {% block content %}
<div class="model-container">
<img src="{{ asset('ldraw/images/'~model.number~'.png') | imagine_filter('model_large')}}">
<div id="model-viewer"></div>
</div>
<dl> <dl>
<dt>number:</dt><dd>{{ model.number }}</dd> <dt>number:</dt><dd>{{ model.number }}</dd>
<dt>name:</dt><dd>{{ model.name }}</dd> <dt>name:</dt><dd>{{ model.name }}</dd>
@ -39,12 +44,7 @@
</dd> </dd>
</dl> </dl>
<div style="display: flex; flex-wrap: wrap"> <div>
<div id="model" style="height: 200px; width: 300px; padding: 5px; display: inline-block"></div>
<div style="height: 300px; width: 300px; padding: 5px; display: inline-block">
<img src="{{ url('media_file', {'path': 'ldraw/images/'~model.number~'.png'}) }}" style="max-height: 90%; max-width: 100%">
</div>
<h4 class="ui horizontal divider header"> <h4 class="ui horizontal divider header">
<i class="puzzle icon"></i> Subparts of this model <i class="puzzle icon"></i> Subparts of this model
</h4> </h4>
@ -76,7 +76,7 @@
<script type="text/javascript"> <script type="text/javascript">
window.onload = function() { window.onload = function() {
modelView = new ModelViewer($('#model')); modelView = new ModelViewer($('#model-viewer'));
modelView.loadStl('{{ url('media_file', {'path': model.path }) }}'); modelView.loadStl('{{ url('media_file', {'path': model.path }) }}');
}; };
</script> </script>

View File

@ -112,6 +112,14 @@ liip_imagine:
quality: 80 quality: 80
filters: filters:
thumbnail: { size: [200, 200], mode: inset } thumbnail: { size: [200, 200], mode: inset }
background: { size: [250, 250], position: center, color: '#FFFFFF' }
model_large:
data_loader: media
cache: ~
quality: 92
filters:
thumbnail: { size: [400, 300], mode: inset }
background: { size: [600, 400], position: center, color: '#FFFFFF' }
rebrickable_part_min: rebrickable_part_min:
quality: 80 quality: 80
data_loader: rebrickable data_loader: rebrickable

View File

@ -32,6 +32,7 @@ gulp.task('js', function() {
'node_modules/jquery/dist/jquery.js', 'node_modules/jquery/dist/jquery.js',
'node_modules/semantic-ui/dist/semantic.js', 'node_modules/semantic-ui/dist/semantic.js',
'app/Resources/assets/js/**.js', 'app/Resources/assets/js/**.js',
'node_modules/three/examples/js/libs/stats.min.js'
]) ])
.pipe(plugins.concat('main.js')) .pipe(plugins.concat('main.js'))
.pipe(gulp.dest('web/resources/js')); .pipe(gulp.dest('web/resources/js'));
@ -45,7 +46,7 @@ gulp.task('files', function () {
gulp.task('watch', ['js', 'css', 'three'], function () { gulp.task('watch', ['js', 'css', 'three'], function () {
gulp.watch('app/Resources/assets/js/**.js' , ['js']); gulp.watch('app/Resources/assets/js/**.js' , ['js']);
gulp.watch('app/Resources/assets/style/**/*.sass' , ['css']); gulp.watch('app/Resources/assets/style/**/*.scss' , ['css']);
}); });
gulp.task('default', function () { gulp.task('default', function () {