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:
parent
db7195e4d3
commit
88c443b4ed
@ -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;
|
||||||
|
25
app/Resources/assets/style/modelviewer.scss
Normal file
25
app/Resources/assets/style/modelviewer.scss
Normal 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%;
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
@import "variables";
|
@import "variables";
|
||||||
|
|
||||||
@import "main";
|
@import "main";
|
||||||
|
@import "modelviewer";
|
||||||
|
@ -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>
|
||||||
|
@ -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
|
||||||
|
@ -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 () {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user