На html странице: Содержимое antjsc3d.js: /** * Copyright (c) 2016 anteh.ru * @preserve Copyright (c) 2011~2014 Humu , Laurent Piroelle . * Данная MIT лицензия разрешает лицам, получившим копию данного программного обеспечения и сопутствующей документации (в дальнейшем именуемыми «Программное Обеспечение»), безвозмездно использовать Программное Обеспечение без ограничений, включая неограниченное право на использование, копирование, изменение, добавление, публикацию, распространение, сублицензирование и/или продажу копий Программного Обеспечения, а также лицам, которым предоставляется данное Программное Обеспечение, при соблюдении следующих условий: * Указанное выше уведомление об авторском праве и данные условия должны быть включены во все копии или значимые части данного Программного Обеспечения. * ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ЯВНО ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ ГАРАНТИИ ТОВАРНОЙ ПРИГОДНОСТИ, СООТВЕТСТВИЯ ПО ЕГО КОНКРЕТНОМУ НАЗНАЧЕНИЮ И ОТСУТСТВИЯ НАРУШЕНИЙ, НО НЕ ОГРАНИЧИВАЯСЬ ИМИ. НИ В КАКОМ СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ НЕ НЕСУТ ОТВЕТСТВЕННОСТИ ПО КАКИМ-ЛИБО ИСКАМ, ЗА УЩЕРБ ИЛИ ПО ИНЫМ ТРЕБОВАНИЯМ, В ТОМ ЧИСЛЕ, ПРИ ДЕЙСТВИИ КОНТРАКТА, ДЕЛИКТЕ ИЛИ ИНОЙ СИТУАЦИИ, ВОЗНИКШИМ ИЗ-ЗА ИСПОЛЬЗОВАНИЯ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ ИЛИ ИНЫХ ДЕЙСТВИЙ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ. */ //========================================================================= //пространство имён ant var ant = ant || {}; ant.aview = []; //Массив экземпляров класса new ant.ViewStateSafe() ant.c3d = []; //массив начальных настроек каждого canvas ant.script = false; //флаг для однократной инициализации подключаемых jsc3d библиотек при загрузке страницы ant.l2 = new Loader(); ant.jsiw = false; ant.init = function(pr) //Инициализация отображения 3D объекта только по клику на canvas области { ant.c3d = pr; var si = false; //Флаг однократной инициализации подгрузки jsc3d.js jsc3d.touch.js jsc3d.webgl.js, если ранее был активирован хотя бы один canvas for (var i = 0; i < ant.c3d.length; i++) { for(var o in ant.c3d[i]) //Установка ширины высоты, фона, флага отображения 3D сразу после загрузки страницы, canvas { if(o === 'w') $('#'+ant.c3d[i].id).width(ant.c3d[i][o]); if(o === 'h') $('#'+ant.c3d[i].id).height(ant.c3d[i][o]); if(o === 'bkgurl') $('#'+ant.c3d[i].id).css("background-image", "url(" + ant.c3d[i][o] + ")"); if(o === 'display3D' && ant.c3d[i][o] === 'on') localStorage.setItem(ant.c3d[i].id, JSON.stringify(ant.c3d[i].id)); //Установка отображения 3D модели при загрузке страницы } //Задаём важные css параметры используемых canvas $('#'+ant.c3d[i].id).css({"position": "relative", "float": "left", "z-index": 0}); //Событие одиночного клика по canvas, после первого срабатывания событие отключается $('#'+ant.c3d[i].id).bind('mousedown', ant.ioc); //Если canvas с таким ID был уже хоть раз инициализированн, то он инициализируется автоматически при перезагрузке страницы if(!si) if(JSON.parse(localStorage.getItem(ant.c3d[i].id)) === ant.c3d[i].id){si = true; ant.ioc();} //Инициализирующий запуск для загрузки jsc3d.js jsc3d.touch.js jsc3d.webgl.js выполняется, если ранее был запущен хоть один canvas } }; ant.ioc = function() //Функция однократной инициализации canvas 3D элемента по клику мышкой { var tid = this.id; //ID canvas по которому был произведён клик, если это был инициализирующий запуск, то tid = undefined if(ant.script === false) { ant.script = true; //jQuery.ajax({url: "/JSC/jsc3d.js",dataType: "script",cache: true,async: false}); //jQuery.ajax({url: "/JSC/jsc3d.touch.js",dataType: "script",cache: true,async: false}); //jQuery.ajax({url: "/JSC/jsc3d.webgl.js",dataType: "script",cache: true,async: false}); ant.l2.require(["/JSC/jsc3d.js", "/JSC/jsc3d.touch.js", "/JSC/jsc3d.webgl.js"], function() { // Callback однократная инициализация, далее считается что скрипты будут подгружаться из cash браузера //jsc3d.js функция вычисления текущего угла поворота модели в градусах, относительно X, Y, Z осей, углы вычисляются по матрице поворота //Диапазон оборота в градусах, для X{0 180 -180 0}, Y{0 90 0 -90 0}, Z{0 180 180 0 и -180 180 + ещё как-то} по Z градусы меняются в зависимости от X и на глаз непонятным образом. Это видно и по формуле для angles[2] //Все значения выдаются правильные, но для преобразования их к привычным и понятным диапазонам нужен дополнительный алгоритм. Полученые значения можно использовать в штатной функции rotate //Формуля для вычисления углов по данным матрицы вращения взяты из соответствующего справочного материала JSC3D.Viewer.prototype.getRotationAngles = function(){ var angles = []; angles[0] = Math.atan2(this.rotMatrix.m21, this.rotMatrix.m22); angles[1] = Math.atan2(-this.rotMatrix.m20, Math.sqrt(this.rotMatrix.m00*this.rotMatrix.m00 + this.rotMatrix.m10*this.rotMatrix.m10)); angles[2] = Math.atan2(Math.sin(angles[0])*this.rotMatrix.m02 - Math.cos(angles[0])*this.rotMatrix.m01, Math.cos(angles[0])*this.rotMatrix.m11 - Math.sin(angles[0])*this.rotMatrix.m12 ); angles[0] = angles[0] * 180 / Math.PI; //rotX angles[1] = angles[1] * 180 / Math.PI; //rotY angles[2] = angles[2] * 180 / Math.PI; //rotZ return angles; }; //Сохранение zoom rotate pan для последующего восстановления //localStorage хранит данные пока хотя бы один экземпляр браузера запущен. И не обязательно с сайтом его использующим. Проверено на IE $(window).unload(function(){ for(var i=0; i'); //3D кнопка сброса zoom rotate panning $('#'+this.id+'0').after(''); //3D кнопка переключения из 3D режима в режим отображеня изображения var pos = $('#'+this.id).position(); $('#'+this.id+'0').css({"position": "absolute", "z-index": "1", "width": "30", "height": "30", "top": pos.top+5, "left": pos.left+5}); $('#'+this.id+'1').css({"position": "absolute", "z-index": "1", "width": "30", "height": "30", "top": pos.top+5, "left": pos.left+5+$('#'+this.id+'0').width()+5}); var cl = {}; //передача данных по значению в ViewStateSafe for(var key in ant.c3d[i]) cl[key] = ant.c3d[i][key]; ant.aview.push(new ant.ViewStateSafe(cl)); $('#'+ant.c3d[i].id).unbind("mousedown"); }; //Класс управлением отображения 3D объекта в canvas ant.ViewStateSafe = function(opt) { //var iii = i; //Поля класса, инициализация дефолтными значениями, если не заданны var def = {id: 'idca', url: '', bkgurl: '', w: 400, h: 200, rx: 0, ry: 0, rz: 0, panx: 0, pany: 0, zoomscale: 1, breset_r: 'off', bclose_r: 'off', main_r: 'off', debug: 'off'}; //Дефолтные значения for(var o in def) this[o] = opt && opt[o] === undefined ? def[o] : opt[o]; //Указатели на setInterval функции, для последующего удаления this.vr_si = null; //вращение основного canvas this.bc_si = null; //вращение кнопки отключения canvas this.br_si = null; //вращение кнопки перезапуска canvas var k = this; //Установка флага инициализации-отображения текущего canvas localStorage.setItem(k.id, JSON.stringify(k.id)); //Основной canvas отображения 3D модели this.vr = new JSC3D.Viewer(document.getElementById(this.id), { SceneUrl: this.url, InitRotationX: 0, InitRotationY: 0, InitRotationZ: 0, //ModelColor: '', //Set ModelColor to specify the color of the default material which will be used for rendering of meshes that do not have an own material. For example, an STL model does not contain any material information, so it will be rendered using the default material. An valid value for this parameter should be the color's string representation formated as '#RRGGBB'. //BackgroundImageUrl //Background //Set Background to 'on' to indicate the background area should be filled up with specified colors on images. If this parameter is set to 'off', then the background area becomes completely transparent. As a result, the DOM element behind the canvas will be visible accordingly. BackgroundColor1: '#FFFFFF', BackgroundColor2: '#383840', //SphereMapUrl: 'bmw/dullchrome.jpg', //Set SphereMapUrl to URL of an image that will be used as the spherical reflection map for the model. Sphere mapping is an image-based simulation technique to cast environment onto surfaces of the model. In current implementation, sphere mapping is available only under the 'texturesmooth' render mode. A mesh's isEnvironmentCast property should be set to true to indicate it is involved in shpere mapping. RenderMode: 'texturesmooth', //point - meshes will be rendered as points. //wireframe - meshes will be rendered as wireframe. //flat - meshes will be rendered using flat shading. This is the default value for the RenderMode parameter. //smooth - meshes will be rendered using smooth shading. //texture - meshes will be rendered as textured primitives with no lighting applied. If textures are unavailable, the flat mode will be used as the fallback. //textureflat - meshes will be rendered as textured primitives with lighting computed per face. If textures are unavailable, the flat mode will be used as the fallback. //texturesmooth - meshes will be rendered as textured primitives with lighting computed per vertex and then interpolated. If textures are unavailable, the smooth mode will be used as the fallback. Renderer: 'webgl' //Set Renderer to 'webgl' to enable WebGL to take charge of all rendering. If this is set, the viewer instance will be internally initialized with the WebGL render back-end to replace the default software rendering modules. This brings about better graphic output and more efficient rendering especially for large models. For browsers without WebGL support, software rendering will be automatically enabled as the fallback. It should be noted that in current implementation, the WebGL render back-end is provided as an optional component through a separate JavaScript source file jsc3d.webgl.js, which should also be included to enable WebGL rendering. Otherwise, this parameter has no effect. //MipMapping //Set MipMapping to 'on' to enable automatically mipmap generation for textures. Mipmaps are a group of images that are generated from a main texture by cascaded downsampling. This is a technique to improve the rendering quality for textured meshes. Mipmap generation is disabled by default. //CreaseAngle: 10 //Set CreaseAngle to define an angle threshold (in degrees) to preserve sharp edges in smooth rendering. Crease angle affects how vertex normals are generated. If the angle between the normals of two adjacent faces is less than the given crease angle, the vertex normals should be computed so that the faces will be shaded smoothly across the edge. Otherwise there should be a lighting discontinuity (aka a crease) across the edge. This parameter only works under the 'smooth' and 'texturesmooth' render modes. If it is set to 0, the rendered result is equivalent to that under the 'flat' or 'textureflat' render mode. In most cases, an angle value between 30~45 degrees produces nice output. //ProgressBar //Set ProgressBar to 'on'/'off' to enable/disable the default progress bar. The viewer provides a default progress bar which will be displayed when a model file is still in loading. By setting this parameter to 'off', the default progress bar is turned off so that a user-defined progress indicator can be used. The default value is 'on'. }); this.vr.init(); this.vr.setDefinition('high'); //high standard low //low - the model will be rendered into frame buffers with half the dimensions of the canvas and then resampled to put to display. The output quality is rather low. Especially there will be apparent 'jagged' effect on edges of the polygons. //high - dimensions of frame buffers will be set to twice of those of the canvas. The rendering will be resampled to put to display. This technique is also known as 2x2 FSAA(Full Screen Anti-Anliasing) which helps to reduce artificial on edge area and thus produces better results. //standard - dimensions of frame buffers will be set to the same with the canvas. This is the default value for the Definition parameter. this.vr.update(); //zoom ограничение, на увеличение/уменьшение больше/меньше заданного значения this.vr.onmousewheel = function() { var d = this.scene.aabb.lengthOfDiagonal(); var z = (this.frameWidth < this.frameHeight ? this.frameWidth : this.frameHeight) / d; var max_scale_from_z = 7; //Максимальный zoom масштаб от оригинального масштаба z при инициализации var min_scale_from_z = 1; //Минимальный zoom масштаб от оригинального масштаба z при инициализации if(this.zoomFactor/z > max_scale_from_z) this.zoomFactor = z*max_scale_from_z; if(this.zoomFactor/z < min_scale_from_z) this.zoomFactor = z*min_scale_from_z; } //Функция чтения угловых поворотов вокруг осей x y z и вывод их в div var e1 = $(document.createElement('div')); e1.text('x'); e1.attr({ id: 'MC', position: 'absolute' }); e1.css({ 'background-color': document.bgColor, 'display': 'inline-block', 'z-index': '2' }); this.vr.onmousedown = function() //Используем для отображения текущих углов поворота 3D модели в canvas. Для использования их в строке инициализации начальных углов поворота 3D модели { if(k.debug !== 'on') return; //Выход, если не включён отладочный режим отображения углов поворота 3D модели в домолнительном div $('#'+e1.attr('id')).remove(); //Удаление старого div отображения угловой ориентации $('#'+k.id).before(e1); //Вставка нового div отображения угловой ориентации var a = this.getRotationAngles(); $('div#MC').text('x= ' +a[0]+ ' y= ' +a[1]+ ' z= ' +a[2]); ant.ButtonPosReset(); } //********************************************************************* //canvas отображения 3D кнопки сброса this.br = new JSC3D.Viewer(document.getElementById(this.id+'0'), { SceneUrl: '/m3d/reset3db.stl', InitRotationX: -90, InitRotationY: 10, InitRotationZ: 10, CreaseAngle: 30, Background: 'off', ProgressBar: 'off', RenderMode: 'texturesmooth', Renderer: 'webgl' }); this.br.init(); this.br.setDefinition('low'); this.br.update(); this.br.onloadingcomplete = function() { k.br.setMouseUsage('rotate'); k.br.zoomFactor = k.br.zoomFactor*2.2; //2.2 увеличение оригинального масштаба задаваемого при инициализации в 2.2 раза k.br.update(); if(k.breset_r === 'on'){ k.br_si = setInterval(function(){ //Вращение 3D кнопки reset k.br.rotate(0, -5, 0); k.br.update(); }, 100);} } this.br.onmousedown = function() //Установка zoom rotate pan в значения по умолчанию { localStorage.removeItem(k.id+'_zfact'); var d = k.vr.scene.aabb.lengthOfDiagonal(); var z = (k.vr.frameWidth < k.vr.frameHeight ? k.vr.frameWidth : k.vr.frameHeight) / d; k.vr.zoomFactor = z*k.zoomscale; localStorage.removeItem(k.id+'_xyzang'); //Очистка коэффициентов матрицы вращения для сброса углов поворота в 0 k.vr.rotMatrix.m00 = 1; k.vr.rotMatrix.m01 = 0; k.vr.rotMatrix.m02 = 0; k.vr.rotMatrix.m03 = 0; k.vr.rotMatrix.m10 = 0; k.vr.rotMatrix.m11 = 1; k.vr.rotMatrix.m12 = 0; k.vr.rotMatrix.m13 = 0; k.vr.rotMatrix.m20 = 0; k.vr.rotMatrix.m21 = 0; k.vr.rotMatrix.m22 = 1; k.vr.rotMatrix.m23 = 0; k.vr.rotate(k.rx, k.ry, k.rz); localStorage.removeItem(k.id+'_pan'); k.vr.panning = [k.panx, k.pany]; k.vr.update(); } //zoom ограничение на увеличение/уменьшение больше/меньше заданного значения this.br.onmousewheel = function() { var d = this.scene.aabb.lengthOfDiagonal(); var z = (this.frameWidth < this.frameHeight ? this.frameWidth : this.frameHeight) / d; var max_scale_from_z = 4; //Максимальный zoom масштаб от оригинального масштаба z при инициализации var min_scale_from_z = 2; //Минимальный zoom масштаб от оригинального масштаба z при инициализации if(this.zoomFactor/z > max_scale_from_z) this.zoomFactor = z*max_scale_from_z; if(this.zoomFactor/z < min_scale_from_z) this.zoomFactor = z*min_scale_from_z; } //*********************************************************************** //canvas отображения 3D кнопки переключения canvas в режим отображения картинки. Сброс/отключение canvas this.bc = new JSC3D.Viewer(document.getElementById(this.id+'1'),{ SceneUrl: '/m3d/reset3db.stl', InitRotationX: -90, InitRotationY: 0, InitRotationZ: 0, CreaseAngle: 30, Background: 'off', ProgressBar: 'off', RenderMode: 'texturesmooth', Renderer: 'webgl' }); this.bc.init(); this.bc.setDefinition('low'); this.bc.update(); this.bc.onloadingcomplete = function() { k.bc.setMouseUsage('rotate'); k.bc.zoomFactor = k.bc.zoomFactor*2.2; //2.2 увеличение оригинального масштаба задаваемого при инициализации в 2.2 раза k.bc.update(); if(k.bclose_r === 'on'){ k.bc_si = setInterval(function(){ //Вращение 3D кнопки отключения отображения 3D контента в canvas k.bc.rotate(0, -5, 0); k.bc.update(); }, 100);} } //Переключение canvas на отображение изображения вместо 3D модели this.bc.onmousedown = function() { localStorage.removeItem(k.id); //Удаление флага произведённой инициализации текущего canvas //Остановка всех, возможно включённых таймеров, перед перезагрузкой для правильной очистки памяти clearInterval(k.vr_si); clearInterval(k.bc_si); clearInterval(k.br_si); //location.reload(false); //Перезагрузка страницы из кэша window.history.go(); //Перезагрузка страницы из cache с возвратом к позиции просмотра страницы //ant.aview.splice(0,2); //k.bc.params.Background='off'; //k.bc.init(); //k.bc.canvas.disabled = true; //k.bc.scene.children[0].visible = false; //k.bc.sceneUrl=''; //k.bc.init(); //k.bc.update(); //k.br.params.Background='off'; //k.br.canvas.disabled = true; //k.br.scene.children[0].visible = false; //k.br.sceneUrl=''; //k.br.init(); //k.br.update(); //k.vr.canvas.disabled = true; //k.vr.scene.children[0].visible = false; //k.vr.params.Background='off'; //k.vr.sceneUrl=''; //k.vr.init(); //k.vr.bkgImageUrl='/impic/Russia.png'; //k.vr.params.Background='off'; //k.vr.init(); //k.vr.setBackgroudImageFromUrl('/impic/Russia.png') //k.vr.update(); } //zoom ограничение на увеличение/уменьшение больше/меньше заданного значения this.bc.onmousewheel = function() { var d = this.scene.aabb.lengthOfDiagonal(); var z = (this.frameWidth < this.frameHeight ? this.frameWidth : this.frameHeight) / d; var max_scale_from_z = 4; //Максимальный zoom масштаб от оригинального масштаба z при инициализации var min_scale_from_z = 2; //Минимальный zoom масштаб от оригинального масштаба z при инициализации if(this.zoomFactor/z > max_scale_from_z) this.zoomFactor = z*max_scale_from_z; if(this.zoomFactor/z < min_scale_from_z) this.zoomFactor = z*min_scale_from_z; } //*********************************************************************** //Восстановление zoom, rotate, panning и инициализация значениями по умолчанию, если это первый запуск клиента this.vr.onloadingcomplete = function() { var z = JSON.parse(localStorage.getItem(k.id+'_zfact')); //zoom фактор. Масштаб vr при первоначальной инициализации if(z === null){k.vr.zoomFactor = k.vr.zoomFactor*k.zoomscale;}else k.vr.zoomFactor = z; var a = JSON.parse(localStorage.getItem(k.id+'_xyzang')); //xyz углы if(a === null) k.vr.rotate(k.rx, k.ry, k.rz); else k.vr.rotate(a[0], a[1], a[2]); var p = JSON.parse(localStorage.getItem(k.id+'_pan')); //panning if(p === null) k.vr.panning = [k.panx, k.pany]; else k.vr.panning = p; k.vr.update(); } };