Карта сайта   Главная

Слайд-шоу наMaxScript

Содержание

Введение

Рассматривается вариант создания слайд-шоу средствами MaxScript– встроенного языка программирования 3dsMax.В приложении генерируется avi-файл, в который затем добавляется мелодия (используется доступный видеоредактор, например Movavi.Video.Suite.12.0.Portable).

Виды изображений

Используются два вида изображений:

Число фотографий (jpg-файлов) произвольно, число заставок (тоже jpg-файлов) равно пяти.
Все фотографии и заставки помещаются в одну папку. Шаблон имен фотографий – krstnii.jpg; шаблон имен заставок – fldj.jpg, где i – это целое число от 1 до количества фотографий, а j; – это целое число от 1 до 5.
Изображения используются для создания текстуры, которая, в свою очередь, употребляется в качестве диффузионной карты стандартного материала. Материал назначается плоскости.
Размеры заставок и фотографий произвольны, но близкие к квадрату, поскольку плоскость с заставкой – это квадрат (все плоскости с заставками имеют одинаковые размеры – hmm×hmm).
Размеры (h и w) плоскости с фотографией определяются в функции dfnC посредством следующего кода:

function dfnC fNm hm z = (
 -- Открываем файл с фотографией и определяем ее размеры (высоту h и ширину w)
 bm = openBitMap fNm
 h = bm.height
 w = bm.width
 -- Определяем коэффициент С, употребляемый далее для определения
 -- размеров h и w плоскости для текущей фотографии
 c = 1.0
 h2 = h
 if h2> hm then
  while h2 > hm do (
   c = c - 0.01
   h2 = h * c
  )
 else
  while h2 < hm do (
   c = c + 0.01
   h2 = h * c
  )
 c2 = 0.94
 -- Вычисляем размеры h и w плоскости для текущей фотографии
 h = c2 * h * c
 w = c2 * w * c
 -- Создаем плоскость с найденными выше размерами
 pln = plane length:h width:w pos:[0, 0, z]
 -- Создаем стандартный материал с диффузионной картой dMp
 dMp = bitmapTexture fileName:fNm
 mtrl = standard diffuseMap:dMp showInViewport:true diffuseMapEnable:true opacity:100
 #(mtrl, pln) )

Если высота и ширина фотографии существенно различаются, то для определения размеров плоскости потребуется иной код, проверяющий не только высоту фотографии, но и ее ширину:

 …
 -- Выполняется после проверки высоты фотографии
 cс = 1.0
 w2 = w
 if w2> hm then
  while w2 > hm do (
   cc = cc - 0.01
   w2 = w * cc
  )
 else
  while w2< hm do (
   cc = cc + 0.01
   w2 = w * cc
  )
 c= amin c cc
 -- Вычисляем размеры h и w плоскости для текущей фотографии
 h = c2 * h * c
 w = c2 * w * c
 -- Создаем плоскость с найденными выше размерами
 pln = plane length:h width:w pos:[0, 0, z]
 …

Подготовка к анимации

Плоскости с изображениями располагаются одна под другой в виде многослойного пирога (меняется z-координата базовой точки); перед каждой фотографией находится заставка (рис. 1).

Пирог из фотографий и заставок

Рис. 1. Пирог из фотографий и заставок

При создании этого пирога фотографии выбираются случайным образом из общего массива фотографий. Исключение составляют первая, центральная и последняя фотографии слайд-шоу: на первом месте всегда находится образ, хранимый файлом krstn1.jpg, на последнем – образ из предпоследней фотографии, а в центре – образ из последней фотографии. Например, если показывается всего 45 фотографий, то в центре слайд-шоу будет фотография krstn45.jpg, а в его конце – krstn44.jpg.
Фотографии, кроме последней, поворачиваются относительно своего центра на угол, случайно выбираемый из диапазона [-5°, 5°] (рис. 2).

Пирог из фотографий и заставок (вид сверху)

Рис. 2. Пирог из фотографий и заставок (вид сверху)

Порядок воспроизведения пирога следующий (используется вид сверху):

Способы устранения заставки

Использованы следующие способы исчезновения заставки:

  1. Перемещение влево с одновременным обнулением высоты и ширины заставки.
  2. Перемещение вправо с одновременным обнулением высоты и ширины заставки.
  3. Перемещение вверх с одновременным обнулением высоты и ширины заставки.
  4. Перемещение вниз с одновременным обнулением высоты и ширины заставки.
  5. Поворот на 90° по часовой стрелке вокруг нижнего левого угла заставки с одновременным обнулением ее высоты и ширины.
  6. Поворот на 90° против часовой стрелки вокруг нижнего правого угла заставки с одновременным обнулением ее высоты и ширины.
  7. Поворот на 90° против часовой стрелки вокруг верхнего правого угла заставки с одновременным обнулением ее высоты и ширины.
  8. Поворот на 90° по часовой стрелке вокруг верхнего правого угла заставки с одновременным обнулением ее высоты и ширины.
  9. Перемещение по диагонали влево и вниз с одновременным обнулением высоты и ширины заставки.
  10. Перемещение по диагонали вправо и вниз с одновременным обнулением высоты и ширины заставки.
  11. Перемещение по диагонали влево и вверх с одновременным обнулением высоты и ширины заставки.
  12. Перемещение по диагонали вправо и вверх с одновременным обнулением высоты и ширины заставки.
  13. Перемещение влево с одновременным обнулением и ширины заставки.
  14. Перемещение вправо с одновременным обнулением ширины заставки.
  15. Перемещение вверх с одновременным обнулением высоты заставки.
  16. Перемещение вниз с одновременным обнулением высоты заставки.
  17. Обнуление высоты заставки.
  18. Обнуление ширины заставки.
  19. Обнуление высоты и ширины заставки.

После исчезновения заставки открывается очередная фотография.

Источник частиц

На переднем плане слайд-шоу наблюдаются разноцветные частицы сферической формы (рис. 3).

Один кадр слайд-шоу

Рис. 3. Частицы слайд-шоу

В качестве эмиттера выступает плоскость, в которой удалено несколько граней (рис. 4).

Плоскость без нескольких полигонов

Рис. 4. Эмиттер частиц - плоскость без центральных граней

Источник частиц создается функцией mkPF (см. приводимый ниже код).

Код, обеспечивающий создание слайд-шоу

-- Масштабирует фотографию и возвращает массив с материалом и плоскостью,
-- на которую будет наложена текстура с фотографией
function dfnC fNm hm z = (
 bm = openBitMap fNm
 h = bm.height
 w = bm.width
 c = 1.0
 h2 = h
 if h2 > hm then
  while h2 > hm do (
   c = c - 0.01
   h2 = h * c
  )
 else
  while h2 < hm do (
   c = c + 0.01
   h2 = h * c
  )
 c2 = 0.94
 h = c2 * h * c
 w = c2 * w * c
 -- Текстура на основе растрового файла с фотографией
 dMp = bitmapTexture fileName:fNm
 mtrl = standard diffuseMap:dMp showInViewport:true diffuseMapEnable:true opacity:100
 pln = plane length:h width:w pos:[0, 0, z]
 #(mtrl, pln)
)
-- Вспомогательная функция, употребляемая при создании источника частиц
function apActFn pF arrOps hasRP = (
 local evn
 evn = event()
 arrCnt = if hasRP then arrOps.Count - 1 else arrOps.Count
 for k = 1 to arrCnt do evn.AppendAction arrOps[k]
 if hasRP do pF.AppendAction arrOps[arrCnt + 1]
 particleFlow.EndEdit()
 pF.AppendInitialActionList evn
 return evn
)
-- Создает источник частиц
function mkPF ts te spd tp clr h2 w2 ps drctn rt wndFrc = (
 qt = eulerToQuat (eulerAngles 0 -90 0)
 wnd = wind strength:wndFrc decay:0 turbulence:0.1 frequency:0.08 scale:1 rotation:qt
 mlMt = multimaterial()
 mlMt.MaterialList[1].Diffuse = (color 255 255 255) --gray --green
 mlMt.MaterialList[2].Diffuse = yellow
 mlMt.MaterialList[3].Diffuse = red
 mlMt.MaterialList[4].Diffuse = white
 mlMt.MaterialList[5].Diffuse = blue
 bjct = sphere radius:4
 hide bjct
 -- Используем плоскость в качестве эмиттера
 pln = plane length:h2 width:w2 pos:ps lengthsegs:1 widthsegs:12 isSelected:on
 convertToPoly pln
 subobjectLevel = 4
 pln.EditablePoly.SetSelection #Face #{4..9}
 -- Удаляем из плоскости (эмиттера) центральные грани
 pln.EditablePoly.delete #Face
 subobjectLevel = 0
 pF = PF_Source enable_Particles:true quantity_Viewport:100 Emitter_Type:0 Emitter_Length:h2 Emitter_Width:w2 pos:ps
 particleFlow.BeginEdit()
 opBth = birth emit_Start:ts emit_Stop:te amount:12 type:1 rate:1
 opPI = Position_Object Emitter_Objects:#(pln)
 opSpd = speed speed:spd direction:drctn Random_Seed:(random 1000 30000) reverse:on
 opRt = rotation direction:2 Euler_X:15 Euler_Y:15
 opSpn = Spin direction:2 SpinRate:180
 --'3D_Type': 16 - star
 opSh = Shape_Instance Shape_Object:bjct variation:50
 opMFrq = material_Frequency assigned_Material:mlMt mtl_ID_1:20 mtl_ID_2:20 mtl_ID_3:20 mtl_ID_4:20 mtl_ID_5:20
 opFc = force force_Space_Warps:#(wnd)
 opDP = displayParticles color:clr type:6
 -- color 255 255 0
 opRP = renderParticles type:2
 td = 0.99 * te
 tstAT = age_Test test_Type:1 condition_Type:1 test_Value:td variation:0 test_Type:0
 apActFn pF #(opBth, opPI, opSpd, opRt, opSpn, opSh, opMFrq, opDP, opFc, tstAT, opRP) true
 particleFlow.BeginEdit()
 opDlt2 = DeleteParticles type:0
 opDP2 = displayParticles color:clr type:6
 evn2 = apActFn pF #(opDlt2, opDP2) false
 tstAT.SetNextActionList evn2 tstAT
 rotate pF (angleaxis rt [1, 0, 0])
)
-- Главный код создания слайд-шоу
delete $*
pth = "C:\\100byte_\\krstn\\"
xt = ".jpg"
arrMtrls2 = #()
-- Массив с материалами для заставок
for k = 1 to 6 do (
 dMp = bitmapTexture fileName:(pth + "fld" + (k as string) + xt)
 mtrl = standard diffuseMap:dMp showInViewport:true diffuseMapEnable:true
 append arrMtrls2 mtrl
)
-- Массив с именами файлов с фотографиями
arrFls = #()
tst = false
--tst = true
cnt = 38
hm = 240 -- 180
hmm = 1.15 * hm
if tst do cnt = 14
for k = 1 to cnt do append arrFls ("krstn" + k as string)
-- Массив с номерами еще неиспользованных фотографий
arrSd = for k = 2 to cnt - 2 collect k
-- Массивы с материалами (текстурами) и плоскостями для фотографий
arrMtrls = #()
arrPln = #()
-- Массив с плоскостями для заставок
arrPln2 = #()
d = 90.0
dt2 = int (d / 2.62)
dt = int (d - dt2)
cnt2 = int (cnt / 2)
z = 2 * (cnt + 2)
k3 = 0
-- Формируем вышеназванные массивы
for k = 1 to cnt do (
 ndx = 0
 -- Номер используемой заставки
 k3 += 1
 if k3 == 6 do k3 = 1
 -- Находим индекс элемента массива arrSd
 -- Первой показываем фотографию с номером 1,
 -- последней - с номером cnt - 1, где cnt - это число фотографий,
 -- в середине просмотра наблюдаем фотографию с номером cnt
 k2 = if k == 1 then
  1
 else if k == cnt then
  cnt - 1
 else if k == cnt2 then
  cnt
 else (
  -- Определяем индекс случайным образом
  ndx = random 1 arrSd.count
  -- Возвращаем номер текущей фотографии
  arrSd[ndx]
 )
 -- Удаляем номер текущей (использованной) фотографии
 if ndx > 0 do deleteItem arrSd ndx
 arrWH = dfnC (pth + arrFls[k2] + xt) hm (z - 1)
 append arrMtrls arrWH[1]
 append arrPln arrWH[2]
 append arrPln2 (plane length:hmm width:hmm pos:[0, 0, z])
 arrPln2[k].material = arrMtrls2[k3]
 arrPln[k].material = arrMtrls[k]
 --meditMaterials[k] = arrMtrls[k]
 ngl = if k2 == cnt then 0 else random -5.0 5.0
 -- Слегка поворачиваем плоскость с фотографией
 rotate arrPln[k] (angleaxis ngl [0, 0, 1])
 z -= 2
)
k3 += 1
if k3 == 6 do k3 = 1
-- Добавляем последнюю заставку-фотографию (последний элемент слайд-шоу)
append arrPln2 (plane length:hmm width:hmm pos:[0, 0, z])
arrPln2[cnt + 1].material = arrMtrls2[k3]
z -= 2
append arrPln2 (plane length:hmm width:hmm pos:[0, 0, z])
arrPln2[cnt + 2].material = arrMtrls2[6]
hmm2 = 0.5 * hmm
ngl = 90
t = 0
-- Реализуем один и рассмотренных выше способов устранения заставки
for k = 1 to cnt + 1 do (
 z2 = arrPln2[k].pos[3]
 if k == 5 or k == 24 do arrPln2[k].pivot = [-hmm2, -hmm2, z2]
 if k == 6 or k == 25 do arrPln2[k].pivot = [hmm2, -hmm2, z2]
 if k == 7 or k == 26 do arrPln2[k].pivot = [-hmm2, hmm2, z2]
 if k == 8 or k == 27 do arrPln2[k].pivot = [hmm2, hmm2, z2]
 animate on (
  if k == 1 or k == 20 do (
   at time t (arrPln2[k].pos = [0, 0, z2]; arrPln2[k].length = hmm; arrPln2[k].width = hmm)
   t += dt2
   at time t arrPln2[k].pos = [-hmm, 0, z2]
  )
  if k == 2 or k == 21 do (
   at time t (arrPln2[k].pos = [0, 0, z2]; arrPln2[k].length = hmm; arrPln2[k].width = hmm)
   t += dt2
   at time t arrPln2[k].pos = [hmm, 0, z2]
  )
  if k == 3 or k == 22 do (
   at time t (arrPln2[k].pos = [0, 0, z2]; arrPln2[k].length = hmm; arrPln2[k].width = hmm)
   t += dt2
   at time t arrPln2[k].pos = [0, hmm, z2]
  )
  if k == 4 or k == 23 do (
   at time t (arrPln2[k].pos = [0, 0, z2]; arrPln2[k].length = hmm; arrPln2[k].width = hmm)
   t += dt2
   at time t arrPln2[k].pos = [0, -hmm, z2]
  )
  if k == 5 or k == 24 do (
   at time t (rotate arrPln2[k] (angleaxis 0.001 [0, 0, 1]); arrPln2[k].length = hmm; arrPln2[k].width = hmm)
   t += dt2
   at time t (rotate arrPln2[k] (angleaxis ngl [0, 0, 1]))
  )
  if k == 6 or k == 25 do (
   at time t (rotate arrPln2[k] (angleaxis -0.001 [0, 0, 1]); arrPln2[k].length = hmm; arrPln2[k].width = hmm)
   t += dt2
   at time t (rotate arrPln2[k] (angleaxis -ngl [0, 0, 1]))
  )
  if k == 7 or k == 26 do (
   at time t (rotate arrPln2[k] (angleaxis 0.001 [0, 0, 1]); arrPln2[k].length = hmm; arrPln2[k].width = hmm)
   t += dt2
   at time t (rotate arrPln2[k] (angleaxis ngl [0, 0, 1]))
  )
  if k == 8 or k == 27 do (
   at time t (rotate arrPln2[k] (angleaxis -0.001 [0, 0, 1]); arrPln2[k].length = hmm; arrPln2[k].width = hmm)
   t += dt2
   at time t (rotate arrPln2[k] (angleaxis -ngl [0, 0, 1]))
  )
  if k == 9 or k == 28 do (
   at time t (arrPln2[k].pos = [0, 0, z2]; arrPln2[k].length = hmm; arrPln2[k].width = hmm)
   t += dt2
   at time t arrPln2[k].pos = [-hmm, -hmm, z2]
  )
  if k == 10 or k == 29 do (
   at time t (arrPln2[k].pos = [0, 0, z2]; arrPln2[k].length = hmm; arrPln2[k].width = hmm)
   t += dt2
   at time t arrPln2[k].pos = [hmm, hmm, z2]
  )
  if k == 11 or k == 30 do (
   at time t (arrPln2[k].pos = [0, 0, z2]; arrPln2[k].length = hmm; arrPln2[k].width = hmm)
   t += dt2
   at time t arrPln2[k].pos = [hmm, -hmm, z2]
  )
  if k == 12 or k == 31 do (
   at time t (arrPln2[k].pos = [0, 0, z2]; arrPln2[k].length = hmm; arrPln2[k].width = hmm)
   t += dt2
   at time t arrPln2[k].pos = [-hmm, hmm, z2]
  )
  if k == 13 or k == 32 do (
   at time t (arrPln2[k].width = hmm; arrPln2[k].pos = [0, 0, z2])
   t += dt2
   at time t (arrPln2[k].width = 0; arrPln2[k].pos = [-hmm2, 0, z2])
  )
  if k == 14 or k == 33 do (
   at time t (arrPln2[k].width = hmm; arrPln2[k].pos = [0, 0, z2])
   t += dt2
   at time t (arrPln2[k].width = 0; arrPln2[k].pos = [hmm2, 0, z2])
  )
  if k == 15 or k == 34 do (
   at time t (arrPln2[k].length = hmm; arrPln2[k].pos = [0, 0, z2])
   t += dt2
   at time t (arrPln2[k].length = 0; arrPln2[k].pos = [0, hmm2, z2])
  )
  if k == 16 or k == 35 do (
   at time t (arrPln2[k].length = hmm; arrPln2[k].pos = [0, 0, z2])
   t += dt2
   at time t (arrPln2[k].length = 0; arrPln2[k].pos = [0, -hmm2, z2])
  )
  if k == 17 or k == 36 do (
   at time t (arrPln2[k].width = hmm)
   t += dt2
   at time t (arrPln2[k].width = 0)
  )
  if k == 18 or k == 37 do (
   at time t (arrPln2[k].length = hmm)
   t += dt2
   at time t (arrPln2[k].length = 0)
  )
  if k == 19 or k == 38 do (
   at time t (arrPln2[k].width = hmm; arrPln2[k].length = hmm)
   t += dt2
   at time t (arrPln2[k].width = 0; arrPln2[k].length = 0)
  )
  if k == cnt + 1 do (
   at time t (arrPln2[k].width = hmm; arrPln2[k].length = hmm)
   t += dt2
   at time t (arrPln2[k].width = 0; arrPln2[k].length = 0)
  )
  t += dt
  ps2 = arrPln2[k].pos
  at time t (
   if k <= cnt do arrPln[k].pos = [0, 0, arrPln[k].pos[3]]
   if k < 13 or k > 19 and k < 32 then
    (arrPln2[k].length = 0; arrPln2[k].width = 0)
   else
    arrPln2[k].pos = [ps2[1], ps2[2], z2]
  )
  t += 1
  ps2 = arrPln2[k].pos
  at time t (
   if k <= cnt do arrPln[k].pos = [0, 0, -2 * z]
   if k < 13 or k > 19 and k < 32 then
    h = 0
   else
    arrPln2[k].pos = [ps2[1], ps2[2], -2 * z2]
  )
 )
)
--drctn = 0 - Along Icon Arrow
--drctn = 2 - Icon Arrow Out
--drctn = 3 - Random 3D
--drctn = 4 - Random Horizontal
mkPF 0 (t * 160) 15 7 (color 255 255 255) 2 hmm [0, -155, 3 * cnt] 0 -90 0.00
animationRange = interval 0 t
-- Просматриваем анимацию
playAnimation()
backgroundColor = black
useEnvironmentMap = off

Заключение

Рассмотрен один из возможных вариантов организации слайд-шоу. В этом варианте создается пирог из заставок и фотографий и используются различные способы удаление заставок. При этом время присутствия заставки и фотографии на экране находятся в пропорции золотого сечения. В процентном округленном значении золотое сечение - это деление какой-либо величины в отношении 38% и 62%.

Результат с 38-ю фотографиями показан ниже.

Карта сайта   Главная

Рейтинг@Mail.ru