/**
* @module MyThree
* @description I use MyThree in my projects for displaying of my 3D objects in the canvas.
* @copyright 2011 Data Arts Team, Google Creative Lab
*
* @license under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*/
import Player from '../player/player.js';
import MyPoints from '../myPoints/myPoints.js';
import StereoEffect from '../StereoEffect/StereoEffect.js';
//import StereoEffect from 'https://raw.githack.com/anhr/commonNodeJS/master/StereoEffect/StereoEffect.js';
import CanvasMenu from '../canvasMenu/canvasMenu.js';
//import CanvasMenu from 'https://raw.githack.com/anhr/commonNodeJS/master/canvasMenu/canvasMenu.js';
import { getLanguageCode } from '../lang.js';
//import { getLanguageCode } from 'https://raw.githack.com/anhr/commonNodeJS/master/lang.js';
import AxesHelper from '../AxesHelper/AxesHelper.js';
//import AxesHelper from 'https://raw.githack.com/anhr/commonNodeJS/master/AxesHelper/AxesHelper.js';
import AxesHelperGui from '../AxesHelper/AxesHelperGui.js';
//import AxesHelperGui from 'https://raw.githack.com/anhr/commonNodeJS/master/AxesHelper/AxesHelperGui.js';
import OrbitControlsGui from '../OrbitControls/OrbitControlsGui.js';
//import OrbitControlsGui from 'http://localhost/anhr/commonNodeJS/master/OrbitControls/OrbitControlsGui.js';
//import OrbitControlsGui from 'https://raw.githack.com/anhr/commonNodeJS/master/OrbitControls/OrbitControlsGui.js';
import { dat } from '../dat/dat.module.js';
import GuiSelectPoint from '../guiSelectPoint/guiSelectPoint.js';
import { getWorldPosition } from '../getPosition.js';
import { SpriteTextGui } from '../SpriteText/SpriteTextGui.js';
import ColorPicker from '../colorpicker/colorpicker.js';
//import ColorPicker from 'https://raw.githack.com/anhr/commonNodeJS/master/colorpicker/colorpicker.js';
import MoveGroupGui from '../MoveGroupGui.js';
import CameraGui from '../CameraGui.js';
//import CameraGui from 'https://raw.githack.com/anhr/commonNodeJS/master/CameraGui.js';
import { getObjectPosition } from '../getPosition.js';
//https://github.com/mrdoob/stats.js/
//import Stats from '../../../three.js/dev/examples/jsm/libs/stats.module.js';
import FrustumPoints from '../frustumPoints/frustumPoints.js';
import three from '../three.js'
if ( typeof dat !== 'undefined' )
three.dat = dat;
import FolderPoint from '../folderPoint.js'
/*проверка duplicate THREE
//import * as THREE2 from 'https://threejs.org/build/three.module.js';
import * as THREE2 from '../../../three.js/dev/build/three.module.js';
three.THREE = THREE2;
*/
import Options from '../Options.js'
import pointLight from '../pointLight.js'
function arrayContainersF() {
const array = [];
this.push = function ( elContainer ) {
array.push( elContainer );
};
this.display = function ( elContainer, fullScreen ) {
array.forEach( function ( itemElContainer ) {
itemElContainer.style.display = ( itemElContainer === elContainer ) || !fullScreen ? 'block' : 'none';
} );
};
Object.defineProperties( this, {
/**
* getter
*/
length: {
get: function () {
return array.length;
},
},
} );
};
const arrayContainers = new arrayContainersF();
/*
* if you asynhronous creates two or more myThreejs same time, then you will receive the error message:
*
* Uncaught ReferenceError: WEBGL is not defined
*
* For resolving of the issue I have remembers myThreejs parameters in the arrayCreates
* and creates next myThreejs only after creating of previous myThreejs.
*/
var arrayCreates = [];
/**
* @callback createXDobjects
* @param {THREE.Group} group [group]{@link https://threejs.org/docs/index.html?q=Gro#api/en/objects/Group} of objects to which a new XD object will be added
* @param {Options} options See <a href="../../jsdoc/Options/index.html" target="_blank">Options</a>. Followed parameters is allowed.
* @param {THREE.PerspectiveCamera} [options.camera] [PerspectiveCamera]{@link https://threejs.org/docs/index.html#api/en/cameras/PerspectiveCamera}.
* @param {object} [options.frustumPoints] <a href="../../frustumPoints/jsdoc/index.html" target="_blank">FrustumPoints</a> instance.
* @param {object} [options.point] point settings. See <b>options.point</b> parameter of <a href="../../myThree/jsdoc/module-MyThree-MyThree.html" target="_blank">MyThree</a> for details.
* @param {Player} [options.player] <a href="../../Player/jsdoc/index.html" target="_blank">Player</a> instance. Playing of 3D ojbects in my projects.
* @param {GuiSelectPoint} [options.guiSelectPoint] <a href="../../guiSelectPoint/jsdoc/index.html" target="_blank">GuiSelectPoint</a> instance.
* @param {Options.raycaster.EventListeners} [options.eventListeners] <a href="../../jsdoc/Options/Raycaster_EventListeners.html" target="_blank">Options.raycaster.EventListeners</a> instance.
* Mouse events listeners for [Raycaster]{@link https://threejs.org/docs/index.html?q=Raycaster#api/en/core/Raycaster} instance.
* @param {THREE.WebGLRenderer} [options.renderer] [WebGLRenderer]{@link https://threejs.org/docs/index.html#api/en/renderers/WebGLRenderer}
*/
class MyThree {
/**
* @description I use MyThree in my projects for displaying of my 3D objects in the canvas.
* @param {createXDobjects} [createXDobjects] <a href="../../myThree/jsdoc/module-MyThree.html#~createXDobjects" target="_blank">callback</a> creates my 3D objects.
* @param {Object} [options] See <a href="../../jsdoc/Options/Options.html" target="_blank">Options</a>.
* The following options are available:
* @param {HTMLElement|string} [options.elContainer=document.getElementById( "containerDSE" ) or a new div element, child of body] If an HTMLElement, then a HTMLElement, contains a canvas and HTMLElement with id="iframe-goes-in-here" for gui.
* <pre>
* If a string, then is id of the HTMLElement.
* Examples of the <b>elContainer</b>:
* <b><div class="container" id="containerDSE">
* <canvas id="canvas" style="background-color:black"></canvas>
* </div></b>;
* or
* <b><div class="container" id="containerDSE">
* </div></b>
* New canvas is created inside of the div tag.
* </pre>
*
* @param {THREE.PerspectiveCamera} [options.camera] [PerspectiveCamera]{@link https://threejs.org/docs/index.html#api/en/cameras/PerspectiveCamera}.
* @param {THREE.Vector3} [options.camera.position=new THREE.Vector3( 0.4, 0.4, 2 )] camera position.
* @param {THREE.Vector3} [options.camera.scale=new THREE.Vector3( 1, 1, 1 )] camera scale.
* @param {Number} [options.camera.fov=70] Camera frustum vertical field of view. See [fov]{@link https://threejs.org/docs/?q=PerspectiveCamera#api/en/cameras/PerspectiveCamera.fov}.
* @param {Number} [options.camera.aspect=window.innerWidth / window.innerHeight] Camera frustum aspect ratio. See [aspect]{@link https://threejs.org/docs/?q=PerspectiveCamera#api/en/cameras/PerspectiveCamera.aspect}.
* @param {Number} [options.camera.near=0.01] Camera frustum near plane. See [near]{@link https://threejs.org/docs/?q=PerspectiveCamera#api/en/cameras/PerspectiveCamera.near}.
* @param {Number} [options.camera.far=10] Camera frustum far plane. See [far]{@link https://threejs.org/docs/?q=PerspectiveCamera#api/en/cameras/PerspectiveCamera.far}.
*
* @param {THREE.Scene} [options.scene] [Scene]{@link https://threejs.org/docs/index.html#api/en/scenes/Scene}.
* @param {THREE.Vector3} [options.scene.position=new THREE.Vector3( 0, 0, 0 )] scene position.
* @param {boolean|object} [options.orbitControls] false - do not add the [OrbitControls]{@link https://threejs.org/docs/index.html#examples/en/controls/OrbitControls}. Allow the camera to orbit around a target.
* <pre>
* or
* </pre>
* @param {boolean} [options.orbitControls.enableRotate=true] Enable or disable horizontal and vertical rotation of the camera.
* @param {boolean} [options.axesHelper] false - do not add the <a href="../../AxesHelper/jsdoc/index.html" target="_blank">AxesHelper</a>.
* @param {boolean} [options.canvasMenu] false - do not create a <a href="../../canvasMenu/jsdoc/index.html" target="_blank">canvasMenu</a> instance.
* @param {boolean} [options.stereoEffect] false - do not use <a href="../../StereoEffect/jsdoc/index.html" target="_blank">StereoEffect</a>.
* @param {boolean|Object} [options.pointLight] false - do not use <a href="../../jsdoc/pointLight/index.html" target="_blank">pointLight</a>.
* @param {Object} [options.pointLight.pointLight1] First <b>pointLight</b> settings.
* @param {THREE.Vector3} [options.pointLight.pointLight1.position] <b>pointLight</b> position.
* @param {Object} [options.pointLight.pointLight2] Second <b>pointLight</b> settings.
* @param {THREE.Vector3} [options.pointLight.pointLight2.position] <b>pointLight</b> position.
* @param {object} [options.spriteText] spriteText options. See <a href="../../SpriteText/jsdoc/module-SpriteText.html" target="_blank">SpriteText</a> <b>options</b> parameter for details.
*
* @param {boolean} [options.player] false - do not create a <a href="../../player/jsdoc/index.html" target="_blank">Player</a> instance.
* @param {object} [options.playerOptions] See <b>settings.options.playerOptions</b> parameter of the <a href="../../player/jsdoc/module-Player-Player.html" target="_blank">Player</a>.
*
* @param {Function|string} [options.getLanguageCode=language code of your browser] Your custom <b>getLanguageCode()</b> function or language code string.
* <pre>
* returns the "primary language" subtag of the language version of the browser.
* Examples: "en" - English language, "ru" Russian.
* See the {@link https://tools.ietf.org/html/rfc4646#section-2.1|rfc4646 2.1 Syntax} for details.
* You can import { getLanguageCode } from '../../commonNodeJS/master/lang.js';
* Currently available follow language code strings:
* "en" - English language,
* "ru" - Russian.
* </pre>
* @param {object|boolean} [options.dat] use dat-gui JavaScript Controller Library. [dat.gui]{@link https://github.com/dataarts/dat.gui}.
* <p>false - do not use dat-gui.</p>
* @param {GUI} options.dat.dat [dat.GUI()]{@link https://github.com/dataarts/dat.gui}.
* @param {GUI} [options.dat.gui] new [dat.GUI()]{@link https://github.com/dataarts/dat.gui} instance.
* <p>
* undefined - do not use <b>dat-gui JavaScript Controller Library<b>. [dat.gui]{@link https://github.com/dataarts/dat.gui}.
* </p>
* @param {HTMLtag} [options.dat.parent] Parent of the canvas. Use if you want to see <b>dat.gui</b> inside of the canvas if canvas is not full screen.
* @param {boolean} [options.dat.cookie] false - do not save to cookie all user settings
* @param {string} [options.dat.cookieName] Name of the cookie.
* @param {boolean} [options.dat.orbitControlsGui] false - do not adds a <a href="../../OrbitControls/jsdoc/" target="_blank">OrbitControlsGui</a> into [dat.gui]{@link https://github.com/dataarts/dat.gui}.
* @param {boolean} [options.dat.axesHelperGui] false - do not adds a <a href="../../AxesHelper/jsdoc/module-AxesHelperGui.html" target="_blank">AxesHelperGui</a> into [dat.gui]{@link https://github.com/dataarts/dat.gui}.
* @param {boolean} [options.dat.playerGui] false - do not adds a <a href="../../player/jsdoc/module-Player-Player.html#gui" target="_blank">Player controllers</a> into [dat.gui]{@link https://github.com/dataarts/dat.gui}.
* @param {boolean} [options.dat.playController] false - do not adds a <a href="../../player/jsdoc/module-Player-Player_PlayController_PlayController.html" target="_blank">PlayController</a> into [dat.gui]{@link https://github.com/dataarts/dat.gui}.
* @param {boolean} [options.dat.stereoEffectsGui] false - do not adds <a href="../../StereoEffect/jsdoc/module-StereoEffect-StereoEffect.html#gui" target="_blank">Stereo Effects folder</a> into [dat.gui]{@link https://github.com/dataarts/dat.gui}.
* @param {boolean|Object} [options.dat.guiSelectPoint] false - do not displays the <a href="../../guiSelectPoint/jsdoc/module-GuiSelectPoint.html" target="_blank">Select Point</a>. [dat.gui]{@link https://github.com/dataarts/dat.gui} based graphical user interface for select a point from the mesh.
* @param {Function} [options.dat.guiSelectPoint.point] Callback function to create custom controllers for each point of selected mesh with custom controllers.
* <pre>
* parameter <b>options</b> See <b>options</b> parameter above.
* parameter <b>dat</b> [dat.GUI()]{@link https://github.com/dataarts/dat.gui}.
* parameter <b>fParent</b> parent folder.
* example <b>point: function ( options, dat, fMesh ) { return new FermatSpiral.gui( options, dat, fMesh ); },</b>
* </pre>
* @param {boolean} [options.dat.guiSelectPoint.boDisplayVerticeID] true - display on the scene the point ID near to the point.
* @param {boolean} [options.dat.guiFrustumPoints] false - do not adds <a href="../../FrustumPoints/jsdoc/FrustumPoints.html#gui" target="_blank">Frustum Points folder</a> into [dat.gui]{@link https://github.com/dataarts/dat.gui}.
* @param {boolean} [options.dat.cameraGui] false - do not adds <a href="../../jsdoc/CameraGui/module-CameraGui-CameraGui.html" target="_blank">Camera folder</a> into [dat.gui]{@link https://github.com/dataarts/dat.gui}.
* @param {object} [options.dat.moveScene] false - do not displays the <a href="../../jsdoc/MoveGroupGui/index.html" target="_blank">move group gui</a>.
* @param {object} [options.dat.spriteTextGui] false - do not displays the <a href="../../SpriteText/jsdoc/module-SpriteTextGui.html" target="_blank">SpriteTextGui</a>.
* @param {object} [options.dat.folderPoint] false - do not adds a <a href="../../jsdoc/folderPoint" target="_blank">Point settings</a> folder.
* @param {object} [options.dat.pointLightGui] false - do not adds a [PointLight]{@link https://threejs.org/docs/index.html?q=PointLight#api/en/lights/PointLight} folder.
* @param {object} [options.cameraTarget] camera looking at selected point during playing. See the <b>cameraTarget</b> parameter of the <a href="../../player/jsdoc/module-Player-Player.cameraTarget.html#init" target="_blank">Player.cameraTarget.init(...)</a> function for details.
* @param {object} [options.frustumPoints] Creates a <a href="../../frustumPoints/jsdoc/index.html" target="_blank">FrustumPoints</a> instance.
* See <b>settings.options.frustumPoints</b> parameter of <a href="../../frustumPoints/jsdoc/FrustumPoints.html" target="_blank">FrustumPoints</a> class.
* @param {MyThree.ColorPicker.palette|boolean|number|String} [options.palette=true] Points сolor.
* <pre>
* <b>MyThree.ColorPicker.palette</b> - is <b>new ColorPicker.palette( ... )</b>
* See <a href="../../colorpicker/jsdoc/index.html" target="_blank">ColorPicker</a> for details.
* <b>boolean</b>: true - <b>new ColorPicker.palette( { palette: ColorPicker.paletteIndexes.BGYW } )</b>;
* <b>number</b>: is <b>MyThree.ColorPicker.paletteIndexes</b>. See <a href="../../colorpicker/jsdoc/module-ColorPicker.html#~paletteIndexes" target="_blank">ColorPicker.paletteIndexes</a> for details.
* <b>String</b> - color name. See list of available color names in the <b>_colorKeywords</b> object in the [Color.js]{@link https://github.com/mrdoob/three.js/blob/dev/src/math/Color.js} file. Example: 'red'.
* See <a href="../../jsdoc/Options/Options.html#setPalette" target="_blank">Options.setPalette</a>.
* </pre>
* @param {object} [options.canvas] <b>canvas</b> properties
* @param {number} [options.canvas.width] width of the canvas
* @param {number} [options.canvas.height] height of the canvas
* @param {boolean} [options.canvas.fullScreen] default is full screen. false - no full screen
* @param {boolean} [options.canvas.noButtonFullScreen] true - hide Full Screen button. default - Full Screen button is visible.
* @param {number} [options.a=1] Can be use as 'a' parameter of the <b>Function</b>. See <b>options.a</b> parameter of the <a href="../../player/jsdoc/module-Player-Player.execFunc.html" target="_blank">Player.execFunc</a>.
* @param {number} [options.b=0] Can be use as 'b' parameter of the <b>Function</b>. See <b>options.b</b> parameter of the <a href="../../player/jsdoc/module-Player-Player.execFunc.html" target="_blank">Player.execFunc</a>.
* @param {object} [options.point] point settings. See <a href="../../jsdoc/Options/global.html#point" target="_blank">Options.point</a> for details.
* @param {object} [options.stats] Use JavaScript Performance Monitor. [stats]{@link https://github.com/mrdoob/stats.js/} .
* @param {object} [options.scales] axes scales.
* See <b>options.scales</b> of the <a href="../../AxesHelper/jsdoc/module-AxesHelper-AxesHelper.html" target="_blank">AxesHelper</a>.
*
* @param {object} [options.scales.w] <b>w</b> axis options. See <a href="../../jsdoc/Options/Options.html#setW" target="_blank">Options.setW(options)</a> <b>options.scales.w</b> for details.
* @param {object} [options.controllers] Controllers list.
* <pre>
* User can see and edit some parameters on the web page.
* See <a href="../../jsdoc/Options/global.html#controllers" target="_blank">controllers</a> of the <b>Options</b>.
* </pre>
* @param {Object} [options.controllers.t] current <a href="../../player/jsdoc/index.html" target="_blank">Player</a> time.
* @param {HTMLElement|string} [options.controllers.t.controller='time'] <b>input</b> element of current <a href="../../player/jsdoc/index.html" target="_blank">Player</a> time
* or <b>id</b> of the time <b>input</b> element.
* @param {HTMLElement|string} [options.controllers.t.elName='tName'] <b>span</b> element of the <b>Player</b> time name. See <b>settings.options.playerOptions.name</b > parameter of <a href = "../../player/jsdoc/module-Player-Player.html" target = "_blank" >Player</a>
* <pre>
* or <b>id</b> of the <b>span</b> element.
* </pre>
* @param {Object} [options.controllers.player] <a href="../../player/jsdoc/index.html" target="_blank">Player's</a> buttons on the web page.
* See <a href="../../player/jsdoc/module-Player-Player.html#createControllersButtons" target="_blank">player.createControllersButtons(options)</a> for details.
* @param {HTMLElement|string} [options.controllers.player.prev='prev'] <b>input</b> element of the button type. Go to previous animation scene.
* <pre>
* or element <b>id</b>.
* </pre>
* @param {HTMLElement|string} [options.controllers.player.play='play'] <b>input</b> element of the button type. Start/stop of the playing.
* <pre>
* or element <b>id</b>.
* </pre>
* @param {HTMLElement|string} [options.controllers.player.next='next'] <b>input</b> element of the button type. Go to next animation scene.
* <pre>
* or element <b>id</b>.
* </pre>
* @param {event} [options.onSelectScene] New time of the <a href="../../player/jsdoc/index.html" target="_blank">Player</a>.
* @param {string} [options.title] text in the top left corner of the canvas.
*/
constructor( createXDobjects, options ) {
options = options || {};
const THREE = three.THREE;
var myThreejs = this;
arrayCreates.push( {
createXDobjects: createXDobjects,
options: options,
} );
if ( arrayCreates.length > 1 )
return;
var camera, group, scene, canvas;
var elContainer = options.elContainer === undefined ? document.getElementById( "containerDSE" ) :
typeof options.elContainer === "string" ? document.getElementById( options.elContainer ) : options.elContainer;
if ( elContainer === null ) {
if ( typeof options.elContainer === "string" )
console.warn( 'The ' + options.elContainer + ' element was not detected.' );
elContainer = document.createElement( 'div' );
document.querySelector( 'body' ).appendChild( elContainer );
}
arrayContainers.push( elContainer );
if ( !elContainer.querySelector('canvas') ) {
elContainer.innerHTML = '';
const elDiv = document.createElement( 'div' );
elDiv.className = 'container';
elDiv.appendChild( document.createElement( 'canvas' ) );
elContainer.appendChild( elDiv );
elContainer = elDiv;
}
if ( three.dat && ( options.dat !== false ) ) {
options.dat = options.dat || {};
options.dat.parent = elContainer;
}
if ( options.title ) {
const elDiv = document.createElement( 'div' );
elDiv.style.position = 'absolute';
elDiv.style.top = '0px';
elDiv.style.color = 'white';
elDiv.style.padding = '3px';
elDiv.innerHTML = options.title;
elContainer.appendChild( elDiv );
}
options = new Options( options );
/**
* Save scale, position and rotation to the userData.default of the mesh
* @param {THREE.Object3D} mesh
*/
options.saveMeshDefault = function ( mesh ) {
mesh.userData.default = mesh.userData.default || {};
mesh.userData.default.scale = new THREE.Vector3();
mesh.userData.default.scale.copy( mesh.scale );
mesh.userData.default.position = new THREE.Vector3();
mesh.userData.default.position.copy( mesh.position );
mesh.userData.default.rotation = new THREE.Euler();
mesh.userData.default.rotation.copy( mesh.rotation );
}
//point size
const defaultPoint = {},
//uses only if stereo effects does not exists
mouse = new THREE.Vector2();
var renderer,
//перенес в options.dat
//mouseenter = false,//true - мышка находится над gui или canvasMenu
//В этом случае не надо обрабатывать событие elContainer 'pointerdown'
//по которому выбирается точка на canvas.
//В противном случае если пользователь щелкнет на gui, то он может случайно выбрать точку на canvas.
//Тогда открывается папка Meshes и все органы управления сдвигаются вниз. Это неудобно.
//И вообще нехорошо когда выбирается точка когда пользователь не хочет это делать.
fOptions,//canvasMenu, axesHelper,// INTERSECTED = [], scale = options.scale, colorsHelper = 0x80,
rendererSizeDefault, cameraPosition,//gui, fullScreen,
//point size
pointSize,
stats,
//https://www.khronos.org/webgl/wiki/HandlingContextLost
requestId;
canvas = elContainer.querySelector( 'canvas' );
if ( !canvas ) {
canvas = document.createElement( 'canvas' );
elContainer.appendChild( canvas );
}
function isFullScreen() {
if ( options.canvasMenu ) return options.canvasMenu.isFullScreen();
if ( options.canvas ) return options.canvas.fullScreen !== false;
return true;
}
//https://www.khronos.org/webgl/wiki/HandlingContextLost
const elImg = elContainer.querySelector('img');
if ( elImg ) elContainer.removeChild( elImg );
if ( typeof WebGLDebugUtils !== 'undefined' )
canvas = WebGLDebugUtils.makeLostContextSimulatingCanvas( canvas );
//https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/webglcontextlost_event
canvas.addEventListener( "webglcontextlost", function ( event ) {
event.preventDefault();
if ( requestId !== undefined )
window.cancelAnimationFrame( requestId );
else console.error( 'myThreejs.create.onloadScripts: requestId = ' + requestId );
clearThree( scene );
//Не могу выполнить npm run build Получаю ошибку
//(babel plugin) SyntaxError: D:/My documents/MyProjects/webgl/three.js/GitHub/commonNodeJS/master/myThree/myThree.js: "raycaster" is read-only
// raycaster = undefined;
rendererSizeDefault.onFullScreenToggle( true );
alert( lang.webglcontextlost );
}, false );
canvas.addEventListener( "webglcontextrestored", function () {
console.warn( 'webglcontextrestored' );
init();
animate();
}, false );
//
init();
animate();
function init() {
// CAMERA
// camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 10 );
camera = new THREE.PerspectiveCamera( options.camera.fov || 70,
options.camera.aspect || window.innerWidth / window.innerHeight,
options.camera.near || 0.01,
options.camera.far || 10 );
camera.position.copy( options.camera.position );
camera.scale.copy( options.camera.scale );
//для возврата созданной камеры обратно в код, который вызвал new MyThree
//В частности это используется для создания точки, за которой будет следить камера
options.camera = camera;
options.point.sizePointsMaterial = 100;//size of points with material is not ShaderMaterial is options.point.size / options.point.sizePointsMaterial
//добавляю camera.userData.default что бы изменять положение камеры во время проигрывания
if ( options.cameraTarget ) {
options.cameraTarget.camera = camera;
options.playerOptions.cameraTarget.init( options.cameraTarget, options );
}
// SCENE
scene = new THREE.Scene();
scene.background = new THREE.Color( 0x000000 );
scene.fog = new THREE.Fog( 0x000000, 250, 1400 );
scene.userData.optionsSpriteText = {
textHeight: 0.04,
//fov: camera.fov,
/*
rect: {
displayRect: true,
borderRadius: 15,
},
*/
}
group = new THREE.Group();
scene.add( group );
const gl = new FrustumPoints( camera, group, canvas, {
options: options,
} ).gl;
//
renderer = new THREE.WebGLRenderer( {
antialias: true,
canvas: canvas,
context: gl,
} );
//если не выполнить эту команду то в http://localhost/anhr/commonNodeJS/master/fermatSpiral/Examples/
//холст будет не на весь экран потомучто там не используется меню
renderer.setSize( window.innerWidth, window.innerHeight );
options.renderer = renderer;
options.cursor = renderer.domElement.style.cursor;
if ( options.stereoEffect !== false ) {
options.stereoEffect = options.stereoEffect || {};
options.stereoEffect.rememberSize = true;//remember default size of the canvas. Resize of the canvas to full screen for stereo mode and restore to default size if no stereo effacts.
}
new StereoEffect( renderer, options );
options.eventListeners = new Options.raycaster.EventListeners( camera, renderer, { options: options, scene: scene, } );
function removeTraceLines() {
group.children.forEach( function ( mesh ) {
if ( ( mesh.userData.player === undefined ) || ( mesh.userData.player.arrayFuncs === undefined ) || ( typeof mesh.userData.player.arrayFuncs === "function" ) )
return;
mesh.userData.player.arrayFuncs.forEach( function ( vector ) {
if ( vector.line === undefined )
return;
vector.line.remove();
vector.line = new Player.traceLine( options );
} );
} );
}
//Light
const pointLight1 = new pointLight( scene, {
options: options,
position: options.pointLight && options.pointLight.pointLight1 && options.pointLight.pointLight1.position ? options.pointLight.pointLight1.position :
new THREE.Vector3( 2 * options.scale, 2 * options.scale, 2 * options.scale ),
} );
const pointLight2 = new pointLight( scene, {
options: options,
position: options.pointLight && options.pointLight.pointLight2 && options.pointLight.pointLight2.position ? options.pointLight.pointLight2.position :
new THREE.Vector3( -2 * options.scale, -2 * options.scale, -2 * options.scale ),
} );
//
//dat-gui JavaScript Controller Library
//https://github.com/dataarts/dat.gui
if ( ( options.dat.gui ) ) {
//for debugging
if ( typeof WebGLDebugUtils !== "undefined" )
options.dat.gui.add( {
loseContext: function ( value ) {
canvas.loseContext();
//https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/webglcontextlost_event
//gl.getExtension( 'WEBGL_lose_context' ).loseContext();
},
}, 'loseContext' );
//Close gui window
if ( options.dat.gui.__closeButton.click !== undefined )//for compatibility with Safari 5.1.7 for Windows
options.dat.gui.__closeButton.click();
}
new Player( group, {
onSelectScene: function ( index, t ) {
options.boPlayer = true;
if ( options.frustumPoints !== undefined ) options.frustumPoints.updateCloudPoints();
if ( options.onSelectScene !== undefined ) return options.onSelectScene( index, t );
// return true;//Сдедующий шаг проигрывателя выполняется только после посторения всех вершин без временной задержки
return false;//По умолчанию сдедующий шаг проигрывателя выполняется немедленно
},
options: options,
cameraTarget: { camera: camera, },
onChangeScaleT: function ( scale ) {
if ( options.player !== undefined )
options.player.onChangeScale( scale );
removeTraceLines();
},
} );
if ( options.player ) new options.player.PlayController();// gui );//, getLanguageCode );
if ( options.dat.gui ) {
fOptions = options.dat.gui.addFolder( lang.settings );
if ( options.player )
options.player.gui( fOptions );
}
//Settings for all SpriteText added to scene and child groups
if ( fOptions )
SpriteTextGui( scene, options, {
//settings: { zoomMultiplier: 1.5, },
folder: fOptions,
options: {
//rotation: 0,
//textHeight: 0.1 * scale,//0.05,
textHeight: 0.05,
//Camera frustum vertical field of view, from bottom to top of view, in degrees. Default is 50.
//Вертикальное поле обзора камеры, снизу вверх, в градусах.
//Если добавить эту настройку, то видимый размер текста не будет зависить от изменения camera.fov.
//Тогда textHeight будет вычисляться как options.fov * textHeight / 50
//Если не определить поле textHeight (см. выше) то textHeight = 0.04,
fov: camera.fov,
//sizeAttenuation: false,//true,//Whether the size of the sprite is attenuated by the camera depth. (Perspective camera only.) Default is false.
}
} );
if ( options.stereoEffect ) {
options.stereoEffect.gui( {
folder: fOptions,
onChangeMode: function ( mode ) {
switch ( mode ) {
case StereoEffect.spatialMultiplexsIndexs.Mono:
break;
case StereoEffect.spatialMultiplexsIndexs.SbS:
case StereoEffect.spatialMultiplexsIndexs.TaB:
break;
default: console.error( 'myThreejs: Invalid spatialMultiplexIndex = ' + mode );
return;
}
if ( options.frustumPoints !== undefined )
options.frustumPoints.updateGuiSelectPoint();
},
} );
}
function getRendererSize() {
var style = {
position: renderer.domElement.style.position,
left: renderer.domElement.style.left,
top: renderer.domElement.style.top,
width: renderer.domElement.style.width,
height: renderer.domElement.style.height,
},
sizeOriginal = new THREE.Vector2();
renderer.getSize( sizeOriginal );
return {
onFullScreenToggle: function ( fs ) {
arrayContainers.display( elContainer.parentElement, !fs );
},
};
};
rendererSizeDefault = getRendererSize();
renderer.setSize( ( options.canvas !== undefined ) && ( options.canvas.width !== undefined ) ? options.canvas.width : canvas.clientWidth,
( options.canvas !== undefined ) && ( options.canvas.height !== undefined ) ? options.canvas.height : canvas.clientHeight );
//CanvasMenu вызываю после renderer.setSize
//потому что если задан options.canvas.fullScreen = true,
//то CanvasMenu изменяет размер renderer до fullScreen
new CanvasMenu( renderer, {
fullScreen: {
fullScreen: options.canvas.fullScreen,
camera: camera,
arrayContainersLength: function() { return arrayContainers.length; },
onFullScreenToggle: function ( fullScreen ) {
rendererSizeDefault.onFullScreenToggle( fullScreen );
//скрыть controllers.w.position.elSlider of arrayFuncs типа colorpicker если canvas на весь экран
//иначе colorpicker будет виден в canvas
function onFullScreenToggle( group, fullScreen ) {
//если не делать этот setTimeout и если canvas по умолчанию на весь экран, то сквозь canvas будет видна палтра elSlider
//которую я рисую на веб станице если в настройках точек будет указана
setTimeout( function () {
function recursion( children ) {
children.forEach( function ( mesh ) {
recursion( mesh.children );
if ( mesh instanceof THREE.Group ) {
onFullScreenToggle( mesh, fullScreen );
return;
}
if ( ( mesh.userData.player === undefined ) || ( mesh.userData.player.arrayFuncs === undefined ) || ( typeof mesh.userData.player.arrayFuncs === "function" ) )
return;
mesh.userData.player.arrayFuncs.forEach( function ( vector ) {
if ( vector.controllers && vector.controllers.w && vector.controllers.w.position && vector.controllers.w.position.elSlider )
vector.controllers.w.position.elSlider.style.display = fullScreen ? 'block' : 'none';
if ( vector.line === undefined )
return;
vector.line.remove();
vector.line = new Player.traceLine( options );
} );
} );
}
recursion( group.children );
}, 0 );
}
onFullScreenToggle( scene, fullScreen );
},
},
options: options,
} );
//use orbit controls allow the camera to orbit around a target. https://threejs.org/docs/index.html#examples/en/controls/OrbitControls
options.createOrbitControls( camera, renderer, scene );
if ( fOptions ) {
new GuiSelectPoint( options, {
cameraTarget: {
camera: camera,
orbitControls: options.orbitControls,//controls,
},
//displays the trace of the movement of all points of the mesh
pointsControls: function ( fPoints, dislayEl, getMesh ) { },
//displays the trace of the point movement
pointControls: function ( fPoint, dislayEl, getMesh ) { },
} );
if ( options.guiSelectPoint ) options.guiSelectPoint.add();
}
defaultPoint.size = options.point.size;
const pointName = options.dat ? options.dat.getCookieName('Point') : 'Point';
if ( options.dat ) options.dat.cookie.getObject( pointName, options.point, options.point );
// three.options = options;//See Options constructor
three.group = group;
if ( createXDobjects ) createXDobjects( group, options );
//вызываю после createXDobjects для того что бы была возможность редактировать настройки AxesHelper. Например в классе nD
new AxesHelper( scene, options );
if ( options.frustumPoints ) options.frustumPoints.create( renderer );
//На случай когда указана точка, за которой следит камера и когда Player не создан
if ( !options.player ) {
Player.selectPlayScene( group, { options: options } );//, Player.getTime(), 0 );
}
options.boPlayer = false;
//default setting for each 3D object
group.children.forEach( function ( mesh ) {
options.saveMeshDefault( mesh );
} );
if ( options.dat.gui ) {
AxesHelperGui( options, fOptions );
new MoveGroupGui( group, options, {
folder: fOptions,
} );
//OrbitControls gui
if ( options.orbitControls !== false ) {
new OrbitControlsGui( options, fOptions );
}
//camera gui
new CameraGui( camera, options, fOptions );
// light
// const scales = options.axesHelper === false ? options.scales : options.axesHelper.options.scales;
pointLight1.controls( { group: group, folder: fOptions, folderName: lang.light + ' 1' } );
pointLight2.controls( { group: group, folder: fOptions, folderName: lang.light + ' 2' } );
//point
const folderPoint = new FolderPoint( options.point, function ( value ) {
if ( value === undefined )
value = options.point.size;
if ( value < 0 )
value = 0;
group.children.forEach( function ( mesh ) {
if ( ( mesh.type !== 'Points' ) || mesh.userData.boFrustumPoints )
return;
if ( mesh.material.uniforms === undefined )
mesh.material.size = value / options.point.sizePointsMaterial;//PointsMaterial
else mesh.material.uniforms.pointSize.value = value;//shaderMaterial
} );
folderPoint.size.setValue( value );
options.point.size = value;
options.dat.cookie.setObject( pointName, options.point );
}, options, {
folder: fOptions,
defaultPoint: defaultPoint,
} )
//Frustum points
if ( options.frustumPoints )// && options.dat.guiFrustumPoints )
options.frustumPoints.gui( fOptions );
options.restoreSceneController( camera, scene );
}
//https://github.com/mrdoob/stats.js/
if ( options.stats !== undefined ) {
try {
stats = new Stats();
elContainer.appendChild( stats.dom );
} catch ( e ) {
console.error( e + ". Please import Stats from '../../../three.js/dev/examples/jsm/libs/stats.module.js';" );
}
}
window.addEventListener( 'resize', onResize, false );
}
function onResize() {
var size;
if ( isFullScreen() )
size = new THREE.Vector2( window.innerWidth, window.innerHeight );
else {
size = new THREE.Vector2();
renderer.getSize( size );
}
camera.aspect = size.x / size.y;
camera.updateProjectionMatrix();
renderer.setSize( size.x, size.y );
if ( options.frustumPoints !== undefined )
options.frustumPoints.update();
}
function onObjectMouseDown( position, intersection ) {
if ( ( options.axesHelper !== undefined ) && ( intersection.object.type === "Points" ) )
options.axesHelper.exposePosition( position );
else alert( 'You are clicked the "' + intersection.object.type + '" type object.'
+ ( intersection.index === undefined ? '' : ' Index = ' + intersection.index + '.' )
+ ' Position( x: ' + position.x + ', y: ' + position.y + ', z: ' + position.z + ' )' );
}
function animate() {
if ( stats !== undefined )
stats.begin();
requestId = requestAnimationFrame( animate );
render();
if ( stats !== undefined )
stats.end();
}
function render() {
if ( !options.stereoEffect || !options.stereoEffect.render )
renderer.render( scene, camera );
else options.stereoEffect.render( scene, camera );
if ( cameraPosition === undefined )
cameraPosition = new THREE.Vector3();
if ( pointSize === undefined )
pointSize = options.point.size;
if (
!cameraPosition.equals( camera.position ) ||
( pointSize != options.point.size ) ||
( ( options.frustumPoints !== undefined ) && options.frustumPoints.animate() )
) {
cameraPosition.copy( camera.position );
pointSize = options.point.size;
group.children.forEach( function ( mesh ) {
if ( mesh instanceof THREE.Points === false )
return;
if ( mesh.geometry.attributes.size === undefined ) {
mesh.material.size = pointSize / options.point.sizePointsMaterial;
return;
}
if ( options.point.opacity !== undefined )
mesh.material.uniforms.opacity.value = options.point.opacity;
//scale
var scale = myPoints.getGlobalScale( mesh );
var cameraPosition = new THREE.Vector3( camera.position.x / scale.x, camera.position.y / scale.y, camera.position.z / scale.z );
scale = ( scale.x + scale.y + scale.z ) / 3;
//set size of points with ShaderMaterial
//https://threejs.org/docs/index.html#api/en/materials/ShaderMaterial
//Example https://threejs.org/examples/?q=points#webgl_custom_attributes_points2
//points with ShaderMaterial
for ( var i = 0; i < mesh.geometry.attributes.position.count; i++ ) {
var position = getObjectPosition( mesh, i ),//getObjectLocalPosition( mesh, i ),
position3d = new THREE.Vector3( position.x, position.y, position.z ),
distance = position3d.distanceTo( cameraPosition ),
y = 1;
//дальние точки очень маленькие
// angle = cameraPosition.angleTo( position3d ),
// cameraFov = ( Math.PI / 180 ) * 0.5 * camera.fov,
// y = 1 - 0.4 * ( angle / cameraFov );
mesh.geometry.attributes.size.setX( i, Math.tan(
mesh.userData.shaderMaterial.point !== undefined &&
mesh.userData.shaderMaterial.point.size !== undefined ?
mesh.userData.shaderMaterial.point.size : options.point.size
) * distance * scale * y );
mesh.geometry.attributes.size.needsUpdate = true;
}
} );
}
}
/**
* Sets the size of the canvas
* @param {number|object} width width of the canvas.
* <pre>
* If <b>width</b> is object, followed keys is available:
* </pre>
* @param {number} width.width width of the canvas
* @param {number} width.height height of the canvas
* @param {number} height height of the canvas
*/
this.setSize = function ( width, height ) {
if ( typeof width === "object" ) {
height = width.height;
width = width.width;
}
if ( width === undefined ) {
//Используется в treeView.js для открытия ветки с холстом
const target = { set: function( width, height ) {
renderer.setSize( width, height );
}};
renderer.getSize( target );
return;
}
renderer.setSize( width, height );
}
arrayCreates.shift();
var params = arrayCreates.shift();
if ( params === undefined )
return;
myThreejs.create( params.createXDobjects, params.options );
}
}
MyThree.release = 'v1.3';
//Localization
const lang = {
defaultButton: 'Default',
settings: 'Settings',
webglcontextlost: 'The user agent has detected that the drawing buffer associated with a WebGLRenderingContext object has been lost.',
light: 'Light',
opacity: 'Opacity',
};
switch ( getLanguageCode() ) {
case 'ru'://Russian language
lang.defaultButton = 'Восстановить';
lang.name = 'Имя';
lang.settings = 'Настройки';
lang.webglcontextlost = 'Пользовательский агент обнаружил, что буфер рисунка, связанный с объектом WebGLRenderingContext, потерян.';
lang.light = 'Свет';
lang.opacity = 'Непрозрачность';
break;
}
/** @namespace
* @description Creating the new [THREE.Points]{@link https://threejs.org/docs/index.html?q=poi#api/en/objects/Points} and adding it into group.
* @see <a href="../../myPoints/jsdoc/index.html" target="_blank">MyPoints</a>.
*/
MyThree.MyPoints = MyPoints;
/** @namespace */
MyThree.StereoEffect = {
/**
* Enumeration of available stereo modes.
* @see <a href="../../StereoEffect/jsdoc/module-StereoEffect.html#~spatialMultiplexsIndexs" target="_blank">StereoEffect.spatialMultiplexsIndexs</a> for details.
* @inner
*/
spatialMultiplexsIndexs: StereoEffect.spatialMultiplexsIndexs,
}
/** @namespace
* @description Pure JavaScript color picker.
* @see <a href="../../colorpicker/jsdoc/index.html" target="_blank">ColorPicker</a>.
*/
MyThree.ColorPicker = ColorPicker;
/** @namespace
* @description gets position of the vector in world coordinates, taking into account the position, scale and rotation of the 3D object
* @param {THREE.Object3D} object
* @param {THREE.Vector3} pos local position
* @returns world position
* @see <a href="../../guiSelectPoint/jsdoc/module-GuiSelectPoint.html#~getWorldPosition" target="_blank">getWorldPosition</a>.
*/
MyThree.getWorldPosition = getWorldPosition;
/** @namespace
* @description Limits angles of rotations of the mesh between 0 and 360 degrees.
* @param {THREE.Euler} rotation angles for limitation
*/
MyThree.limitAngles = function ( rotation ) {
function limitAngle( axisName ) {
while ( rotation[axisName] > Math.PI * 2 )
rotation[axisName] -= Math.PI * 2
}
limitAngle( 'x' );
limitAngle( 'y' );
limitAngle( 'z' );
}
/** @namespace
* @description 3D objects animation.
* @see <a href="../../Player/jsdoc/index.html" target="_blank">Player</a> class.
*/
MyThree.Player = Player;
/** @namespace
* @description class for [THREE]{@link https://github.com/anhr/three.js} and [dat.GUI(...)]{@link https://github.com/anhr/dat.gui} variables.
* @see <a href="../../jsdoc/three/index.html" target="_blank">three</a> class.
*/
MyThree.three = three;
/** @namespace
* @description Options.
* @see <a href="../../jsdoc/Options/index.html" target="_blank">Options</a> class.
*/
MyThree.Options = Options;
window.__myThree__ = window.__myThree__ || {};
if ( window.__myThree__.boMyThree )
console.error( 'myThree: duplicate myThree. Please use one instance of the myThree class.' )
window.__myThree__.boMyThree = true;
import Intersections from '../intersections/intersections.js'
/** @namespace
* @description Creates an intersection line for graphic objects.
* @see <a href="../../intersections/jsdoc/index.html" target="_blank">Intersections</a>.
*/
MyThree.Intersections = Intersections;
import TreeView from '../treeView/treeView.js';
MyThree.TreeView = TreeView;
export default MyThree;