Форум

Отридеивание интернета :)

07 января 2016 21:49 #6299
Приветствую уважаемое сообщество и создателей!
Решил вести свой WIP по созданию элементов для перевода интернета в третье измерение при помощи замечательного движка Blend4Web. Сразу хочу выразить благодарность за помощь и ответы на мои вопросы!
Итак, расскажу немного о себе, чтобы люди понимали, кто же это тут такие ужасные коды пишет))
По специальности я вообще ни разу не программист, работа моя серая и унылая, я простой инженер-строитель, который целыми днями чертит чертежи, а в свободное от этого нудного занятия время развлекает себя программированием. Имею некоторый опыт программирования под OpenOffice на OBasic, для MicrosoftOffice тоже немного баловался) Еще немного писал на C#. Это все были программки типа там учета материала, сотрудников… в общем ничего интересного:)
Лет эдак 10 назад, то есть примерно с 2003 по 2007 я плотно увлекался 3DMax, и была такая мечта у меня, чтобы интернет стал трехмерным. Тогда это было фантастикой… И вот недавно моя мечта вновь проснулась и я обнаружил, что технологии уже подоспели, и еще тут такой замечательный движок появился. Я стал активно изучать JavaScript, вспоминать как моделить, изучать Blender (еще, видимо, принципы геймдева надо изучить)… в общем поле для деятельности тут широкое:)
так что я буду признателен за любые советы и подсказки :-)

Итак, начнем.

Первое, что я решил реализовать, это меню. Такое, чтобы было динамически создаваемым по данным из БД, чтобы реагировало на наведение мыши, то есть по сути повторить классическое плоское меню (да да ,я велосипедостроитель:))
Я сверстал тестировочный шаблончик, выглядит он так

вот его можно скачать
Menu.7z
что я тут делаю. создал небольшую табличку для имитации массива данных из БД, собираю по ней массив.
 function GetMenuArray(){
 var table = document.getElementById("InputTable");
 var ColumnCount = table.rows[0].cells.length;
 var RowCount = table.getElementsByTagName("tr").length;
 var MenuArray = [];
for (var j=0;j<ColumnCount;j++)
   {
   var SubArray= [];
   for (var row=0;row<RowCount;row++)
   {
   var SellValue = table.rows[row].cells[j].firstElementChild.value;
		SubArray[row] = SellValue;
   }
   MenuArray[j] = SubArray;
   }  
   return MenuArray;
 }

загружаю в сцену два элемента для главного меню и для подменю, по массиву копирую их и заполняю надписями
//Событие на нажатие кнопки LoadMenu
function LoadMainMenuF() {
	LoadMainMenu.disabled = true;
	LoadMainMenu.value = "Reload page";
// m_data.unload(1);	
m_data.load("MainMenu.json", loaded_cb, null, null, true );
 }
 //Событие при загрузке сцены
 function loaded_cb(data_id, success) { 
 var MenuData = GetMenuArray() //собрали массив из таблицы
  // SubMenuArray = [];
 var LoadedMAIN = m_scenes.get_object_by_name("MainMenu_", 1);//получили нужный объект из сцены
  var LoadedSUB = m_scenes.get_object_by_name("SMenu", 1);//получили нужный объект из сцены
 //CanvasTexPrint(LoadedMAIN,"CT",MenuData[0][0]); //пишем на нем первый элемент массива
 // CanvasTexPrint(LoadedSUB,"SMCanvasMat",MenuData[0][1]); 
var LenghtOfObject = 2*m_trans.get_object_bounding_box(LoadedMAIN).max_x;
var LenghtOfLogo = m_trans.get_object_bounding_box(m_scenes.get_object_by_name("Text")).min_x;
   LoadPosition = LenghtOfLogo + LenghtOfObject/2;
   //скачем по массиву
  for (var a = 0;  a < MenuData.length; a++){	  
	 var CopiedMAINName = m_scenes.get_object_name(LoadedMAIN)+a;//имя нового элемента
     var CopiedMAIN = m_obj.copy(LoadedMAIN,CopiedMAINName, true);//получаем копию загруженного элемента, глубокое копирование!
 m_scenes.append_object(CopiedMAIN); //добавляем его в сцену
m_trans.set_translation(CopiedMAIN, LoadPosition, 0, 0); //перемещаем его куда надо
//console.log(m_scenes.get_object_name(CopiedMAIN) + " moved to " +LoadPosition);
 CanvasTexPrint(CopiedMAIN,"CT",MenuData[a][0]); //пишем на нем элемент массива
  m_scenes.show_object(CopiedMAIN);
// var J = 0.3;
 //Добавляем ПОДМЕНЮ
 var SubArray= [];
for (var smc = 1;  smc < MenuData[a].length; smc++){
	 var SubMenuDATA = MenuData[a][smc].split('ссылка:');
	 var CopiedSUBName = CopiedMAINName + "_" + smc + "_" + m_scenes.get_object_name(LoadedSUB);//имя нового элемента
     var CopiedSUB = m_obj.copy(LoadedSUB,CopiedSUBName, true);//получаем копию загруженного элемента, глубокое копирование!
	// console.log(m_scenes.get_object_name(CopiedSUB));
	 
	  m_scenes.append_object(CopiedSUB); //добавляем его в сцену
	  m_trans.set_translation(CopiedSUB, LoadPosition, 0, 0); //перемещаем его куда надо
	  CanvasTexPrint(CopiedSUB,"SMCanvasMat",SubMenuDATA[0]); 
	   m_scenes.show_object(CopiedSUB);
	   var SMenuDataHash = {};
	   SMenuDataHash.name = CopiedSUBName;
	    SMenuDataHash.url = SubMenuDATA[1];
	   SubArray[smc-1] = SMenuDataHash;
	    // SubArray[smc-1] = SubMenuDATA[1];
	    // console.log(SubArray[smc-1].url);
	  // J = J + 0.35;
	   
}
SubMenuArray[a] = SubArray;
LoadPosition = LoadPosition + LenghtOfObject + 0.1 ;
 }
// console.log("Count of Selectable objects: " + m_obj.get_selectable_objects().length);
// console.log(SubMenuArray.length);
   // console.log(SubMenuArray[0][0]);
 }
 //Функция создания надписи на канвас-текстуре
 function CanvasTexPrint (objCanvas,TexName,PrintData){
	  var ctx_image = m_tex.get_canvas_ctx(objCanvas, TexName);
  if (ctx_image) {
        var img = new Image();
        img.src = "Background.png";
        img.onload = function() {
            ctx_image.drawImage(img, 0, 0, ctx_image.canvas.width, 
                    ctx_image.canvas.height);					 
            ctx_image.fillStyle = "rgba(255,255,255,255)";
            ctx_image.font = "60px Arial";
		    ctx_image.shadowColor = "#000";
            ctx_image.shadowOffsetX = 5;
            ctx_image.shadowOffsetY = 5;			
            ctx_image.fillText(PrintData,5, 300);
            m_tex.update_canvas_ctx(objCanvas, TexName);
        }
    }
	 
 }

обрабатываю нажатие на пункт меню
function main_canvas_click(e) {
    if (e.preventDefault)
        e.preventDefault();

    var x = e.clientX;
    var y = e.clientY;
    var canvas_xy = m_cont.client_to_canvas_coords(x, y, _vec2_tmp);
//console.log("x=" + _vec2_tmp[0] + " " + "y=" + _vec2_tmp[1]);
var objPicked = m_scenes.pick_object(_vec2_tmp[0], _vec2_tmp[1]);
if (objPicked){
	InfoBoxText.innerHTML = GetObjectInfo(objPicked);	
	var NameOfOject = m_scenes.get_object_name(objPicked);
		  var NameArray = NameOfOject.split('_');
	//NameArray[0] - MainMenu
	//NameArray[1] - номер MainMenu
	//NameArray[2] - номер SubMenu
	//NameArray[3] - SubMenu
    // if (objME != _previous_MouseBottom_obj) {
		// console.log(NameArray[0]);
    if (NameArray[0] == "MainMenu"){
		for (var c=0;c<SubMenuArray[NameArray[1]].length;c++){
    if(SubMenuArray[NameArray[1]][c].name === NameOfOject){
		window.open(SubMenuArray[NameArray[1]][c].url, "_self");
		// console.log(SubMenuArray[NameArray[1]][c].url);
	}
		}
	}
	}
}

обрабатываю событие наведения мыши на меню
function object_onmousemove(e) {
	
      var xW = e.clientX;
    var yW = e.clientY;
    var canvas_xy = m_cont.client_to_canvas_coords(xW, yW, _vec2_tmp);
     var x = _vec2_tmp[0];
    var y = _vec2_tmp[1];
    var objME = m_scenes.pick_object(x, y); 
	  if (objME) {
		  var NameOfOject = m_scenes.get_object_name(objME);
		  var NameArray = NameOfOject.split('_');
	//NameArray[0] - MainMenu
	//NameArray[1] - номер MainMenu
	//NameArray[2] - номер SubMenu
	//NameArray[3] - SubMenu
    // if (objME != _previous_MouseBottom_obj) {
		// console.log(NameArray[0]);
    if (NameArray[0] == "MainMenu"){
		if (NameArray[1] != _previous_MouseBottom_obj) {
		var MainMenuSelected = m_scenes.get_object_by_name("MainMenu_" + [NameArray[1]] , 1);
		var HegihtMMenu =  m_trans.get_object_bounding_box( m_scenes.get_object_by_name("MainMenu_", 1)).max_y;
		var HegihtSMenu =  m_trans.get_object_bounding_box(m_scenes.get_object_by_name("SMenu", 1)).max_y;
		//Нужно перечислить номера SubMenu
		for (var s=0;s<SubMenuArray[NameArray[1]].length;s++){
			
		 var SubMenuOpen = m_scenes.get_object_by_name(SubMenuArray[NameArray[1]][s].name,1);
		 
		var SmenuJump = (s+1)*(HegihtMMenu + HegihtSMenu);
		//переместить все подменю относительно своего главного меню
  m_trans.set_translation_obj_rel(SubMenuOpen, 0, SmenuJump, 0, MainMenuSelected);
		}
  //Увеличить соответствующее главное меню
 m_trans.set_scale(MainMenuSelected,1.1);
 _Current_MouseBottom_obj = NameArray[1];
		}
		else {
			_previous_MouseBottom_obj = NameArray[1];
		}
		// console.log("_previous_MouseBottom_obj = "+_previous_MouseBottom_obj);
		// console.log("_Current_MouseBottom_obj = "+_Current_MouseBottom_obj);
		 if (_Current_MouseBottom_obj != _previous_MouseBottom_obj) {
			 if(SubMenuArray.length !=0){
	for (var m=0;m<SubMenuArray.length;m++){
	  var MainMenuSelectedCURR = m_scenes.get_object_by_name("MainMenu_"+m, 1);
	 if (m != _Current_MouseBottom_obj){
		//тут надо все подменю убрать в ноль относительно своего главного меню
		for (var c=0;c<SubMenuArray[m].length;c++){
		 var SubMenuOpenC = m_scenes.get_object_by_name(SubMenuArray[m][c].name,1);
     m_trans.set_translation_obj_rel(SubMenuOpenC, 0, 0, 0, MainMenuSelectedCURR);
		}
		 	m_trans.set_scale(MainMenuSelectedCURR,1);
	}
	}	
	}
		 }
  }  
    else  {
		HideALLSubMenu();
	}
	  }
	  else{
		  HideALLSubMenu();
	  }
}
function HideALLSubMenu(){
	if(SubMenuArray.length !=0){
	for (var m=0;m<SubMenuArray.length;m++){
	  var MainMenuSelectedCURR = m_scenes.get_object_by_name("MainMenu_"+m, 1);
	 
		//тут надо все подменю убрать в ноль относительно своего главного меню
		for (var c=0;c<SubMenuArray[m].length;c++){
		 var SubMenuOpenC = m_scenes.get_object_by_name(SubMenuArray[m][c].name,1);
     m_trans.set_translation_obj_rel(SubMenuOpenC, 0, 0, 0, MainMenuSelectedCURR);
		}
		 	m_trans.set_scale(MainMenuSelectedCURR,1);
	}	
  
	}
}

в общем то неплохо получилось… надо бы еще сделать реакцию подменю на наведение мыши (наверное это будет изменение цвета)
Дорогу осилит идущий
07 января 2016 22:24 #6300
Это был первый шаг(который я вымучивал пару месяцев). Теперь я хочу выпустить в мир своего франкенштейна ))
Есть у меня сайтик на базе OpenCart, выглядит он вот так:

(наверно теперь догадались, почему у меня там все зеленое в тестовой страничке первого поста)) Так как дизайнер из меня еще хуже, чем программист, то вот уж такой вот зелененький сайт)) следовательно и свои меню я буду делать зелеными.
Разобравшись в дебрях MVC-модели OpenCarta, переломав ноги в PHP и CSS (для меня это хуже китайской грамоты, потму как китайский я хоть немного знаю), я вживил мою сценку в свой сайт

Если кому то интересно покрутить там - вот тут он, это подопытный кролик на бесплатном хосте, оригинал сайта тут. Не знаю, что будет по этим ссылкам на момент когда вы читаете эти строки, потому я выложил скрины

Первый вопрос к разработчикам (если конечно вы это будете читать все ): Если посмотреть "родное" плоское меню, т обуквы на нем значительно четче, чем на 3D меню… Это особенность канвас тексутры? можно этот как то победить?…
И второй вопрос - планируется ли изменение масштаба объекта по одной оси? и растянется ли при этом надпись на текстуре? Как вы наверно заметили, каждое меню должно быть шириной равной длине слов, ну или по крайней мере удлиннялось, если надпись слишком длинная. Можно конечно это решить многострочной надписью, но все же

теперь мне надо массив, полученный из PHP, прикрутить к своему коду.
для тех кто не знает и кому интересно как передать массив из PHP в Javascript
<script> var CategoriesArrayFomPHP = <?php echo json_encode($categories); ?>;</script>
<script type="text/javascript" src="catalog/view/javascript/b4w_3D-Menu/b4w.min.js"></script>
<script type="text/javascript" src="catalog/view/javascript/b4w_3D-Menu/Menu.js"></script>

то есть объявляем переменную до вызова скриптов движка
Дорогу осилит идущий
08 января 2016 00:46 #6302
Прикрутил массив. это оказалось не так сложно)
заменил
MenuData[a][0] на MenuData[a].name
for (var smc = 1;  smc < MenuData[a].length; smc++){
	 var SubMenuDATA = MenuData[a][smc].split('ссылка:');

заменил на
for (var smc = 0;  smc < MenuData[a].children.length; smc++){
	 var SubMenuDATA = [MenuData[a].children[smc].name,MenuData[a].children[smc].href];

и почемуто он амперсанд стал вставлять мнемоникой… пришлось сделать так
 SMenuDataHash.url = SubMenuDATA[1].replace("&amp;","&");

почему он так делает для меня магия

теперь есть проблема

надо делить текст на две строки…

и еще наверно надо один кубик с надписью смотреть все

Дорогу осилит идущий
08 января 2016 01:51 #6309
Здравствуйте!
Идея очень хорошая, будет очень интересно посмотреть что из этого получится.
Команда Blend4Web
https://twitter.com/AlexKowel
08 января 2016 14:15 #6331

Идея очень хорошая, будет очень интересно посмотреть что из этого получится.
+1
Александр (команда Blend4Web)
08 января 2016 22:18 #6349
Почесал сегодня тыковку и решил переписать код наведения на меню. До этого у меня многократно происходило событие. Это может было бы и не страшно если я просто перемещаю объект set_translation_obj. Но я подумываю анимировать раскрытие меню, и возможно даже закрытие
вот исправленный код
function object_onmousemove(e) {
	
      var xW = e.clientX;
    var yW = e.clientY;
    var canvas_xy = m_cont.client_to_canvas_coords(xW, yW, _vec2_tmp);
     var x = _vec2_tmp[0];
    var y = _vec2_tmp[1];
    var objME = m_scenes.pick_object(x, y);
	
	  if (objME) {
		  var NameOfOject = m_scenes.get_object_name(objME);
		  var NameArray = NameOfOject.split('_');
	//NameArray[0] - MainMenu
	//NameArray[1] - номер MainMenu
	//NameArray[2] - номер SubMenu
	//NameArray[3] - SubMenu
    // if (objME != _previous_MouseBottom_obj) {
		// console.log(NameArray[0]);
    if (NameArray[0] == "MainMenu"){
		 _Current_MouseBottom_obj = NameArray[1];
		if (_Current_MouseBottom_obj != _previous_MouseBottom_obj) {
		var MainMenuSelected = m_scenes.get_object_by_name("MainMenu_" + [NameArray[1]] , 1);
		var HegihtMMenu =  m_trans.get_object_bounding_box( m_scenes.get_object_by_name("MainMenu_", 1)).max_y;
		var HegihtSMenu =  m_trans.get_object_bounding_box(m_scenes.get_object_by_name("SMenu", 1)).max_y;
		//Нужно перечислить номера SubMenu
		for (var s=0;s<SubMenuArray[NameArray[1]].length;s++){
			
		 var SubMenuOpen = m_scenes.get_object_by_name(SubMenuArray[NameArray[1]][s].name,1);
		 
		var SmenuJump = (s+1)*(HegihtMMenu + HegihtSMenu);
		//переместить все подменю относительно своего главного меню
  m_trans.set_translation_obj_rel(SubMenuOpen, 0, SmenuJump, 0, MainMenuSelected);
		}
  //Увеличить соответствующее главное меню
 m_trans.set_scale(MainMenuSelected,1.1);
		}
		else {
		
		}

		 if (_Current_MouseBottom_obj != _previous_MouseBottom_obj) {
			 if(SubMenuArray.length !=0){
	for (var m=0;m<SubMenuArray.length;m++){
	  var MainMenuSelectedCURR = m_scenes.get_object_by_name("MainMenu_"+m, 1);
	 if (m == _previous_MouseBottom_obj){
		//тут надо все подменю убрать в ноль относительно своего главного меню
		for (var c=0;c<SubMenuArray[m].length;c++){
		 var SubMenuOpenC = m_scenes.get_object_by_name(SubMenuArray[m][c].name,1);
     m_trans.set_translation_obj_rel(SubMenuOpenC, 0, 0, 0, MainMenuSelectedCURR);
		}
		 	m_trans.set_scale(MainMenuSelectedCURR,1);
	}
	}	
	}
		 }
		 _previous_MouseBottom_obj = NameArray[1];
  }  
    else  {
		HideALLSubMenu();
		_Current_MouseBottom_obj = null;
		_previous_MouseBottom_obj = null;
	}
	 
	  }
	  else{
		  HideALLSubMenu();
		  _Current_MouseBottom_obj = null;
		_previous_MouseBottom_obj = null;
	  }
}


Теперь попробую менять цвет подменю при наведении мыши на него
Наверняка это set_diffuse_color(obj, mat_name, color), но я еще не пробовал
Дорогу осилит идущий
08 января 2016 23:10 #6354
…я простой инженер-строитель…
Видимо, не такой простой , потому что проект действительно очень интересный и если вы его доведете до ума, то это может получиться довольно серьезная библиотека.
Разработчик Blend4Web
08 января 2016 23:16 #6356

и если вы его доведете до ума
хватило бы ума

это может получиться довольно серьезная библиотека
да, примерно на это я рассчитываю
Дорогу осилит идущий
10 января 2016 02:06 #6388
Сегодня сделал подсвечивание подменю при наведении на него мыши.

Для этого я просто меняю диффузный свет у стандартного материала таким образом
m_material.set_diffuse_color(SubMenuCURRENT_obj,"Material.003", Color_Lighted);

Значения векторов цвета вынес в начало файла как константы. Потом возможно вынесу в отдельный файл, типа CSS будет
var Color_Lighted = m_rgba.from_values(0.1, 1, 0.05, 0);
var ColorDefault = m_rgba.from_values(0.004, 0.376, 0.053, 0);

Код, который отвечает за подсвечивание подменю
//Подсвечиваем подменю
        	for (var cu=0;cu<SubMenuArray[NameArray[1]].length;cu++){
    if(SubMenuArray[NameArray[1]][cu].name === NameOfOject){
		CurrentSubMenu = SubMenuArray[NameArray[1]][cu].name;
		var SubMenuCURRENT_obj = m_scenes.get_object_by_name(CurrentSubMenu, 1);
		if(CurrentSubMenu != previousSubMenu ){
			m_material.set_diffuse_color(SubMenuCURRENT_obj,"Material.003", Color_Lighted);
		  //Убираем подсветку с предыдущего
		  if(previousSubMenu != null){
			  var SubMenuPREVIOUS_obj = m_scenes.get_object_by_name(previousSubMenu, 1);
			m_material.set_diffuse_color(SubMenuPREVIOUS_obj,"Material.003", ColorDefault);
		  }
		}
	    }
		else{
		  if(NameArray[3] != "SMenu"){
			 if(previousSubMenu != null){
			m_material.set_diffuse_color(m_scenes.get_object_by_name(previousSubMenu, 1),"Material.003", ColorDefault);
			previousSubMenu = null;
		CurrentSubMenu = null;
			 }
		  }	
		}
		}
		 previousSubMenu = CurrentSubMenu;

Ну еще немного подправил код, который при наведении мыши (там был кошмар, но работало), но уж не буду его тут приводить, слишком он большой… лучше приложу папку с проектом. Если кому-то вдруг интересно
можно скачать и посмотреть, как работает подсветка. На сайте магазина я тоже обновил, там тоже работает.

Теперь наверно надо решить проблему длинных слов… делить по словам или буквам… сайт многоязычный (в данном случае языка два, но ведь может быть и больше) Русский надо делить по словам, а вот китайский можно по иероглифам… да, тут надо подумать….
Дорогу осилит идущий
13 января 2016 14:21 #6529
Теперь наверно надо решить проблему длинных слов… делить по словам или буквам…

У нас в демке New Year переносятся строчки по словам в поздравительном письме. Там текст разбивается по словам, которые формируют строчку ограниченной длины. Длину печатаемого на канвасе текста можно получить при помощи метода context.measureText().
Команда Blend4Web
 
Пожалуйста, зарегистрируйтесь или войдите под своей учетной записью , чтобы оставлять сообщения.