Создание стерео картинки

Создание стерео картинки

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

Немного теории.

Как человек воспринимает объем?  Чем ближе расположен рассматриваемый объект, тем больше наблюдатель «сводит» глаза. Т.о. если рассматриваемый объект расположен на бесконечно удаленном расстоянии, то глаза будут смотреть на него «параллельно».

Рис.1

Теперь рассмотрим как достигнуть иллюзию объема на плоской картинке. Итак, у нас имеется человек с двумя глазами (рис.1): левый глаз O1 и правый O2,а так же плоскость проекции стерео изображения D1D2. Пусть рассматриваемый объект B расположен на расстоянии h от наблюдателя. Тогда для того чтоб «увидеть» его на картинке необходимо совпадение рисунка в точках B1 и B2. Получается мы держим перед собой плоский рисунок и смотрим как бы «сквозь» него. Левый глаз видит точку B1, правый B2, изображения для них на листе совпадают и создается иллюзия того, что на самом деле мы видим объект B, расположенный за плоскостью листа. Т.о. чем больше расстояние между точками B1 и B2,в которых совпадает изображение, тем «дальше» воспринимается объект B.

Теперь выведем пару расчетных формул, которые пригодятся для просчета стерео изображения. Пусть a – расстояние между глазами, H – расстояние до максимально удаленного объекта, h – расстояние до объекта h_max – расстояние от максимально удаленного объекта до плоскости проекции стерео изображения. Из подобия треугольников BB1B2 и BO1O2 следует B1B2/BE= O1O2/BF. B1B2=d , O1O2=a, BF=h, BE=BF-EF, EF=AF-AE=H-h_max, BE=h-(H-h_max). Итого d/(h-H+h_max))=a/h.

Пожалуй теории пока достаточно, можно перейти к практике. Для этого понадобится Photoshop и 3dsMAX. В Photoshop’е создадим текстуру, из которой в последствии будет построено стерео изображение. Несколько рекомендаций: чем больше на текстуре деталей, тем лучше получиться окончательный вариант (с однотонными вообще ничего не получиться); высота текстуры должна совпадать с высотой изображения (поэтому сразу надо определить размер финального стерео изображения); а ширина зависит от того, где вы собираетесь в дальнейшем использовать полученную картинку. На рис.1 величина d_max как раз соответствует ширине текстуры, поэтому в реальности (на экране монитора или после распечатки) она не должна превышать расстояния между глазами a. В тоже время чем больше пикселей по ширине будет в исходной текстуре, тем более качественным получиться окончательный результат. У меня получилась вот такая текстура:

 
Рис.2

Ширина ее 100 пикселей, а высота 600 (в итоге рассчитываю получить стерео изображение размером 800 на 600 пикселей). Хотя лучше сделать ее так, чтоб она тайлилась по горизонтали. Далее создаем или открывает любой 3D-объект в MAX’е. Я для этого использовал модель осы:

 
Рис.3

Для результата не пригодятся ни материалы, ни сторонние рендеры, ни источники света. Поэтому если все это имеется в сцене, то назначаем на все стандартный материал, удаляем все источники света и используем Default Scanline Renderer. Теперь можно приступить к написанию скрипта. Для этого в меню Max’а выбираем MAXScript->New Script и откроется окно редактирование скриптов. Наш скрипт будет иметь свой собственный интерфейс. Это можно реализовать двумя способами: на панели Utilites или в отдельном окне. Выберем первый вариант и создадим новую скрипт-утилиту:

utility stereoImg "Stereo Image"

-- утилита создания стерео изображения

(

)

 

Сохраним ее с названием stereoImg.ms и отправим ее на просчет. Для этого надо в меню редактора скриптов выбрать Tools->Evaluate All или нажать комбинацию клавиш Ctrl+E. После этого наша утилита приобрела свой интерфейс (рис.4) и единственное что можно с ней сделать – это открыть и закрыть.

 
Рис.4

Разберем что же мы сделали: utility – зарезервированное слово с помощью которого создаются новые скрипт-утилиты, stereoImg – имя переменной, с помощью которой можно осуществлять контроль над утилитой, “Stereo Image” – символьная строка, именно она отображается в списке утилит (рис.4-3), далее в круглых скобках идет тело утилиты. Более подробную информацию по созданию скрипт-утилит и MAXScript’у можно найти в файле помощи MAX’а (в основном меню Help->MAXScript Reference). Для добавления комментариев используется «--», после него компилятор игнорирует все символы до конца строки . Пора наполнить нашу утилиту кнопками и другими элементами пользовательского интерфейса. Будем ориентироваться на следующий вариант:

 
Рис.5

Итак, список необходимых элементов: две группы Texture и Render. В группе Texture имеется метка, в которой будет отображаться информация о текстуре, и кнопка, запускающая диалог открытия файла с текстурой. В группе Render – спиннер (определяет ширину рендера), метка (информация о высоте рендера), спиннер (качество стерео изображения), индикатор процесса, кнопка выбора объекта и «самая главная» кнопка запускающая скрипт на просчет. Для этого в тело утилиты надо добавить следующие строки:

    fn fltr_cam obj = superClassOf obj == camera -- функция возвращает истину если obj камера (для фильтра выбора)

    group "Texture:"

   -- параметры текстуры

   (

       label l_T_img "no texture" -- информация о размере

       button b_T_img "Load texture bitmap" -- загрузка текстуры

   )

   group "Render:"

   -- параметры рендеринга

   (

       spinner s_R_w "width:" range:[0,1500,0] type:#integer width:82 across:2 -- ширина

       label l_R_h "height:0" -- высота

       spinner s_R_prec "quality of stereo image" range:[1,10,4] type:#integer width:80 align:#right -- качество стерео изображения

       progressBar prb_R_status value:0 -- прогресс рендера

       pickbutton pb_R_cam "Pick camera" filter:fltr_cam across:2 -- выбор камеры

       button b_R_stereo "<GO>"  -- запуск рендера

   )

 

Здесь: group – зарезервированное слово для создание группы, после него следует название группы, и в круглых скобках элементы группы; label – для создания метки, потом название переменной для управления меткой и срока (выводимый на форму текст); button – для создания кнопки, потом название переменной для управления кнопкой и строка (отображается на кнопке). Это основная структура для создания элементов пользовательского интерфейса. Но некоторые элементы имеют так же дополнительные параметры. Для spinner’а – range:<точка в 3d-пространстве> (первая координата определяет нижний предел изменения значения, вторая – верхний, третья – начальное значение), type:#integer (тип значения – целое число, так же может принимать значение #float – вещественное число и #worldunits – число в размерности текущих координат MAX’а). Для progressBarvalue:<первоначальное значение>. Для pickbuttonfilter:<ссылка на функцию фильтра>, функция фильтра имеет один параметр – объект и возвращает true, если объект может быть выбран, и false в противном случае. Для определение такой функции используется зарезервированное слово fn потом идет название функции, параметр и после «=» логическое выражение, которое возвращает функция. Параметры width:, across: и align: могут использоваться при создании любых элементов и отвечают за компоновку элементов на форме: первый – ширина (если требуется отличная от создаваемой по умолчанию), второй – количество элементов в одной строке (по умолчанию каждый новый элемент создается в новой строке), третий – выравнивание.

В самом начале тела утилиты (перед описанием пользовательских элементов) определим локальные переменные, необходимые для создания стерео изображения:

    -- определение локальных переменных

   local T_img = undefined -- текстура

   local width, height, d_max -- ширина и высота рендера, ширина текстуры

 

Осталось прописать обработчики событий от элементов пользовательского интерфейса. Описание всех событий должно быть следующим образом: on<имя элемента> <название события> <список аргументов>do(<обработка события>). Для начала опишем поведение MAX’а на нажатие кнопки загрузки текстуры. Что должно происходить:  открыться окно диалога выбора файла, после выбора файла текстуры она загружается в MAX, выводиться на форму информация о размере текстуры и ее название, далее инициируются локальные переменные и настраиваются глобальные параметры рендера.

    on b_T_img pressed do

   -- загрузка текстуры

   (

       T_file_name = getOpenFileName types:"bitmap(*.bmp)|*.bmp" -- диалог открытия файла

       if T_file_name != undefined then -- если все файл бы выбран

       (

           T_img = openBitMap (T_file_name) -- загрузка картинки

           b_T_img.caption = filenameFromPath T_file_name -- на кнопку имя файла картинки

           l_T_img.caption = "width: " + (T_img.width as String) + " height:" + (T_img.height as String) -- вывести информацию о картинке

           d_max = T_img.width -- обновление всех локальных переменных

           height = T_img.height

           width = 4*height/3 as Integer -- определение ширины рендера так чтоб в итоге получились пропорции 3:4

           s_R_w.value = width -- отображение информации о разрешении рендера

           l_R_h.caption = "height:" + height as String

           renderWidth = width -- настройка глобальных параметров рендера (ширина, высота)

           renderHeight = height

       )

   )

 

Определим вид, который мы желаем получит на стерео изображении. Для этого нам понадобиться камера. Если в сцене уже имеются камеры с «нужным» видом – отлично, можно использовать их. Если нет, то необходимо создать камеру. Проще всего перейти к виду Perspective, где выбрать необходимый ракурс. После чего создать камеру из вида: в главном меню Create->Cameras->CreateCameraFromView или Crtl+C. Вспомним теорию, там были такие параметры как H – расстояние до максимально удаленного объекта и h_max – расстояние от плоскости проецирования до максимально удаленного объекта. Чтоб не вводить их вручную, будем брать их из свойства камеры, а именно из Clipping Planes. Выберем необходимую камеру, на панели Modify раскроем свиток Parameters, ставим галочку возле Clip Manually. Осталось только настроить Near Clip и Far Clip. Плоскость Near Clip соответствует плоскости проекции стерео изображения, а Far Clip – расстояние до максимально удаленного объекта. Рекомендации: объекты, по которым будет строиться стерео изображение, должна располагаться между Far Clip и Near Clip, Near Clip равно приблизительно половине Far Clip, объекты должны быть расположены подальше от Near Clip и вплотную к Far Clip. Хотя можно этим пренебречь и в дальнейшем экспериментировать с Clipping Planes, для получения более желаемого результата. Т.о. вид настроен, осталось «объяснить» скрипту, что мы будем работать с этой камерой, для этого напишем обработчик нажатия кнопки выбора камеры:

    on pb_R_cam picked cam do

   -- выбор камеры

   (

       pb_R_cam.caption = pb_R_cam.object.name -- на кнопку имя камеры

   )

 

После этого ссылка на камеру содержится в pb_R_cam.object.Так же необходимо скрипту отреагировать на изменение пользователем ширины рендера:

    on s_R_w changed val do

   -- обработка изменения ширины рендера

   (

       width = s_R_w.value

       renderWidth = width

   )

 

Осталось обработать последнее событие – нажатие «самой главной» кнопки. Опять придется заняться теорией на основе полученной ранее формулы: d/(h-H+h_max))=a/h. Здесь a, H и h_max – констаны. Последние две получаються из Clipping Planes камеры. Определим a, для этого подставим вместо h величину H – крайний случай, когда объект находиться на максимальном расстоянии. Отсюда a=d_max*H/h_max. И последняя формула: d=a*(h-H+h_max)/h – по ней вычисляется расстояние между точками d, изображения в которых совпадают, для того чтоб создавалась иллюзия, что рассматриваемый объект расположен на расстоянии h от наблюдателя.

    on b_R_stereo pressed do

   -- просчет стерео изображения

   (

       -- рендер глубины

       DOF_img = render camera:pb_R_cam.object outputwidth:width outputheight:height channels:#(#zDepth)

       unDisplay DOF_img

       -- создание битмапы для будущего стерео изображения

       OUT_img = bitmap (width+d_max) height color:black

       -- заполнение первой полосы текстурой

       for x = 0 to (d_max-1)do

       (

           for y = 0 to (height-1) do

           (

               c =(getPixels T_img [x,y] 1)[1] -- берем пиксель из текстуры

               setPixels OUT_img [x,y] #(c) -- и вставляем в будущее стерео изображение

           )

           prb_R_status.value =(100 * x / d_max)as integer -- обновление прогресса текущей операции

       )

       prb_R_status.value = 0

       -- отрисовка стерео изображения

       H = pb_R_cam.object.farclip -- расстояние от глаз до максимальной глубины

       h_max = pb_R_cam.object.farclip - pb_R_cam.object.nearclip -- расстояние от плоскости проецирования до макс. глубины

       a = d_max*H/h_max -- расстояние между глазами

       -- построчное построение стерео изображения

       for y = 0 to (height - 1)do

       (

           for x = 0 to (width - 1) do

           (

               -- берем из рендера глубины расстояние от камеры до ближайшей точки

               dist = - (getChannel DOF_img [x,y] #zDepth)[1]

               if dist > H then dist = H -- не должно быть больше макс. глубины

               d =(a*(dist+h_max-H)/(dist)+.5)as integer -- вычисляем расстояние на котором должны совпадать пиксели стерео изображения

               setPixels OUT_img [x+d_max,y](getPixels OUT_img [x+d_max-d,y] 1) -- и дубируем пиксели согласно этому расстоянию

           )

           prb_R_status.value =(100 * y / height) as integer

       )

       prb_R_status.value = 0

       display OUT_img -- открываем окно с финальным стерео изображением

   )

 

Рассмотрим подробнее принцып работы обработчика нажатия «самой главной» кнопки. В переменную DOF_img сохраняется ссылка на рендер из выбранной камеры. Параметр channels:<массив каналов> метода render указывает какие каналы необходимо отрендерить дополнительно, в нашем случае обязателен только один канал: #zDepth - расстояние от камеры до места пересечения объекта с лучом, выходящим из камеры и проходящим через заданную точку рендера h (в скрипте – это переменная dist). Метод unDisplay <ссылка на изображение> закрывает окно с изображением, если оно открыто, этот метод противоположен display <ссылка на изображение>. Затем создается новое изображение шириной большей, чем ширина рендера на ширину текстуры и слева заполняется полосой текстуры (рис.6).

 
Рис.6

Потом идет построчное сканирование канала глубины (с проверкой на то, чтоб расстояние не превысило Far Clip камеры). На основе этой величины h (в скрипте dist) и полученных ранее формул вычисляется расстояние между повторяющимися пикселами. Таким образом идет построение стерео изображения, попутно обновляется прогресс вычислений. И в конце концов на экран выводиться окончательный результат (рис.7).

 
Рис.7

Ниже приведен полный листинг скрипт-утилиты с некоторыми улучшениями:

utility stereoImg "Stereo Image"

-- утилита создания стерео изображения

(

   -- определение локальных переменных

   local T_img = undefined -- текстура

   local width, height, d_max -- ширина и высота рендера, ширина текстуры

   fn fltr_cam obj = superClassOf obj == camera -- функция возвращает истину если obj камера (для фильтра выбора)

 

   group "Texture:"

   -- параметры текстуры

   (

       label l_T_img "no texture" -- информация о размере

       button b_T_img "Load texture bitmap" -- загрузка текстуры

   )

 

   group "Render:"

   -- параметры рендеринга

   (

       spinner s_R_w "width:" range:[0,1500,0] type:#integer width:82 across:2 -- ширина

       label l_R_h "height:0" -- высота

       spinner s_R_prec "quality of stereo image" range:[1,10,4] type:#integer width:80 align:#right -- качество стерео изображения

       progressBar prb_R_status value:0 -- прогресс рендера

       pickbutton pb_R_cam "Pick camera" filter:fltr_cam across:2 -- выбор камеры

       button b_R_stereo "<GO>"  -- запуск рендера

   )

 

   on b_T_img pressed do

   -- загрузка текстуры

   (

       T_file_name = getOpenFileName types:"bitmap(*.bmp)|*.bmp" -- диалог открытия файла

       if T_file_name != undefined then -- если все файл бы выбран

       (

           T_img = openBitMap (T_file_name) -- загрузка картинки

           b_T_img.caption = filenameFromPath T_file_name -- на кнопку имя файла картинки

           l_T_img.caption = "width: " + (T_img.width as String) + " height:" + (T_img.height as String) -- вывести информацию о картинке

           d_max = T_img.width -- обновление всех локальных переменных

           height = T_img.height

           width = 4*height/3 as Integer -- определение ширины рендера так чтоб в итоге получились пропорции 3:4

           s_R_w.value = width -- отображение информации о разрешении рендера

           l_R_h.caption = "height:" + height as String

           renderWidth = width -- настройка глобальных параметров рендера (ширина, высота)

           renderHeight = height

       )

   )

 

   on pb_R_cam picked cam do

   -- выбор камеры

   (

       pb_R_cam.caption = pb_R_cam.object.name -- на кнопку имя камеры

   )

 

   on s_R_w changed val do

   -- обработка изменения ширины рендера

   (

       width = s_R_w.value

       renderWidth = width

   )

 

   on b_R_stereo pressed do

   -- просчет стерео изображения

   (

       if (height == undefined) or (width == 0) then

       (

           messageBox "No texture or invalid size"

           return 0

       )

       if pb_R_cam.object == undefined then

       (

           messageBox "Pick camera first"

           return 0

       )

       -- рендер глубины

       DOF_img = render camera:pb_R_cam.object outputwidth:width outputheight:height channels:#(#zDepth)

       unDisplay DOF_img

       -- создание битмапы для будущего "расширенного" стерео изображения

       -- причем ширина умножается на точность

       prec = s_R_prec.value -- точность (коэф. качества)

       OUT_img = bitmap ((width+d_max)*prec) height color:black

       -- заполнение первой полосы текстурой

       for x = 0 to (d_max-1)do

       (

           for y = 0 to (height-1) do

           for i = 0 to (prec-1) do

           (

               c1 =(getPixels T_img [x,y] 1)[1] -- берем пиксель из текстуры

               c2 = (getPixels T_img [x+1,y] 1)[1]

               if c2 == undefined then c2 = (getPixels T_img [0,y] 1)[1]

               c = c1*(1.*(prec-i)/prec)+ c2*(1.*i/prec) -- линейно сглаживаем растяжение

               setPixels OUT_img [x*prec+i,y] #(c) -- и вставляем в будущее стерео изображение

           )

           prb_R_status.value =(100 * x / d_max)as integer -- обновление прогресса текущей операции

       )

       prb_R_status.value = 0

       -- отрисовка "расширенного" стерео изображения

       H = pb_R_cam.object.farclip -- расстояние от глаз до максимальной глубины

       h_max = pb_R_cam.object.farclip - pb_R_cam.object.nearclip -- расстояние от плоскости проецирования до макс. глубины

       a = d_max*H/h_max -- расстояние между глазами

       -- построчное построение стерео изображения ("расширенное")

       for y = 0 to (height - 1) do

       (

           for x = 0 to (width - 1) do

           for dx = 0 to (prec - 1) do

           (

               -- берем из рендера глубины расстояние от камеры до ближайшей точки (тут тоже идет линейное сглаживание)

               dist = (- (getChannel DOF_img [x,y] #zDepth)[1]*(prec-dx) - (getChannel DOF_img [x,y] #zDepth)[1]*dx)/prec

               if dist > H then dist = H -- не должно быть больше макс. глубины

               d =(prec*a*(dist+h_max-H)/(dist)+.5)as integer -- вычисляем расстояние на котором должны совпадать пиксели стерео изображения

               setPixels OUT_img [x*prec+dx+d_max*prec,y](getPixels OUT_img [x*prec+dx+d,y] 1) -- и дубируем пиксели согласно этому расстоянию

           )

           prb_R_status.value =(100 * y / height) as integer

       )

       prb_R_status.value = 0

       -- получение из "расширенного" "нормальное" стерео изображение

       FIN_img = bitmap (width+d_max) height color:black -- создание битмапы для финального стерео изображения

       for y = 0 to (height - 1) do

       (

           for x = 0 to (width + d_max - 1) do

           (

               c = black

               for i = 0 to (prec-1) do

                   c +=(getPixels OUT_img [x*prec+i,y] 1)[1]/prec -- получение сренего арифметического цвета

               setPixels FIN_img [x,y] #(c) -- и сохранение его в финальное стрео изображение

           )

           prb_R_status.value =(100 * y / height) as integer

       )

       prb_R_status.value = 0

       display FIN_img -- открываем окно с финальным стерео изображением

   )

)

Изменение здесь только в алгоритме просчета стерео изображения. Добавилась проверка «от дурака»: просчет не начнется, если не была выбрана текстура и камера. Так же тут был реализован алгоритм «улучшенного» расчета стерео изображения с использованием спиннера «качество». В двух словах в чем это заключается: изображение сначала линейно растягивается и просчет ведется тоже «растянуто», а потом полученный результат сжимается до первоначального размера. Разницу можно увидеть на рис.7, рис.8, рис.9.

 
рис.8

 
рис.9

На рис.7 качество выставлено в единицу, а на рис.8 и рис.9 – 4 и 8 соответственно. Конечно чем выше качество, тем больше время просчета.

Вот и все. Теперь у нас имеется скрипт-утилита, с помощью которой можно из любого 3D-объекта получить стерео изображение. Очень надеюсь что урок был понятен (для этого надо дружить с геометрией :) и полезен (по крайней мере тем, что можно действительно посмотреть свои модели «в объеме»).

623 0 850 61
50
2008-02-08
такой скрипт был написам мильёон лет назад
2008-02-08
А какое у этого колдунаства практическое применение кроме пресловутых тетрадок?
2008-02-08
а я не вижу осы (
2008-02-08
а я не вижу монитор )
2008-02-08
to Алексей Ага и програмки есть, которые это делают, но описание как это делаеться я не встречал. to ViewPort Применение: в рекламе, полиграфии, а еще есть идея написать игрушку на этом принцыпе, такой точно еще не было. А вообще это урок, а не скрипт отдельно. Я надеюсь, что он натолкнет кого-то к изучению MAXScript.
2008-02-08
хороший урок! спасибо автору! вопрос: можно ли сделать анимированной эту стрекозу?=)
2008-02-08
Мне такие тетрадки в малолетстве моем нравились и урок понравился, актуальность, что правда, 1
2008-02-08
урок класний картинками тоже страдал 2 года назад но некогда не думал что сделать это можна в максе урок понятний 4, но актуальность колеблица между 1 и 3
2008-02-08
Забавный, сложенный, интересный и доходчивыи урок, Гранд Мерси AShimу. Примесь настольгии по ушедшему детству к современным технологиям, это уже похоже на то, чем можно торговать сейчас. Вот вам и ответ на вопросы актуальности и практичности поднятой автором темы, кто-то придумает игру, с интересным геймдевом, и мы будем играть в нее как дети !!!
2008-02-08
Отличный урок! Молодец! Лично я теперь точно познакомлюсь с макс скриптом! Ты напиши урок по созданию какого-нибудь актуального скрипта и тогда приз 100% твой! Скрипты это же не паханная нива!
2008-02-08
Сорри за ошибку, игры бывают конечно-же с интересным или не интересным, а бывает и с откровенно ......(нехорошим) ГЕЙМПЛЕЕМ. (Specially for Varven:-)
2008-02-08
Автору, респект! Я и не знал что в скрипте можно такие вещи вытворять. модная штука. обязательно буду его учить. спасибо
2008-02-08
Урок супер! Мог бы голосовать, поставил бы 5+ И думать не гадал, что ЭТО можно сделать в родном и любимом 3dMAXе)))
2008-02-09
Просто супер. Я всегда любил подобные рисунки - у меня даже книга есть с набором изображений подобных этому. В общем AShim респект.
2008-02-09
А вот еще для тех кто в этом уроке видет только развлечение. Так вот давно установлено что просмотр таких рисунков улучшает зрение. Кому интересно могу в крациях расписать почему :)
2008-02-10
Что-то не понял, не виходит, Постоянно одна полоска текстуры при рендери, без изменений. Из Clipping Planes параметры нужна кудата прописывать ? И вообще, в скрипт еще самому что-то нужна дописывать или заменить ?
2008-02-10
Ой-ёй-ой... как много букав, я в макс скрипт и не лезу по этому, хотя штука интересная. ----- АВТОР молодец! Сохронил, когда мозг остынет, еще почитаю, жаль склад ума непозволял никогда получать удовольствия от оперирования большим колличеством символов :)
2008-02-11
OstapSLI у меня такая же бяка выходит - это если брать уже конечный листин :( , а если собрать кусочки по ходу - то все ОК :)
2008-02-11
Большое спасибо за отзывы. Я рад, что нашлись люди, которым урок понравился. А если у кого-то что-то не получаеться - пишите в личку, с удовольствием отвечу на все вопросы.
2008-02-11
Vazя Благодарю за то, что постарался ответить. Что ты имеешь в виду "собрать кусочки по ходу" ? Вопрос остается открытым, "в скрипт еще самому что-то нужна дописывать или заменить ???" А кто не хочет разбираться из скриптом есть варант: Stereo Pictures (http://www.softholm.com/download-software-free5681.htm) (качество хромает)
2008-02-12
Прошу прощения, но в финальном листинге скрипта есть ошибка: setPixels OUT_img [x*prec+dx+d_max*prec,y](getPixels OUT_img [x*prec+dx+d,y] 1) необходимо заменить на setPixels OUT_img [x*prec+dx+d_max*prec,y] (getPixels OUT_img [x*prec+dx+d_max*prec-d,y] 1) Поэтому получалась только одна полоса.
2008-02-12
Прошу прощения, но в финальном листинге скрипта есть ошибка: setPixels OUT_img ((x*prec+dx+d_max*prec,y)) (getPixels OUT_img ((x*prec+dx+d,y)) 1) необходимо заменить на setPixels OUT_img ((x*prec+dx+d_max*prec,y)) (getPixels OUT_img ((x*prec+dx+d_max*prec-d,y)) 1) Поэтому получалась только одна полоса. Только в коментах нельзя вставлять квадратные скобки (или я просто не знаю как), поэтому двойные круглые здесь имеються ввиду просто квадратные.
2008-02-12
А теперь (после исправлений), благодарю AShim!
2008-02-16
Молодец! Пять баллов!
2008-02-18
То что здесь рассматривается MAXScript это отлично! Мало кто прибегает к рассмотению написания сценариев вообще как на MAXScript так и на других языках, но толи я "кривой", толи каринка "не такая" - но я не заметил стерео каритнкии, скорей всего я кривой иногда что-то проявляется но иногда нет.
2008-02-22
Впечатляет обьем проделанной работы!! Все написано толково, доступно и очень качественно... Автор молодец :) Данный урок раскрывает потенциал max script. После такого задумываешься, что очень многое можно в нем сделать. Обязательно выучу max script! Спасибо...
2008-02-22
Эх, надо будет каку-то милую барышню визуализировать. =) Хоть будет стимул освоить мега урок по максовским скриптам, без которых невозможно стать настоящим профессионалом 3D.
2008-02-22
Прикольно! Всегда интересовался такими картинками, на тетрадках видел. Класс!
2008-02-25
[b]Арсений[/b], кто тебе такое наговорил? Можно узнать! Хош?
2008-02-29
Класс! Все работает! Я конечно такого еще не смогу - но есть к чему стремиться!
2008-03-10
[b]Rinocrosser[/b], У меня близорукость, прекрасно все вижу, даже с экрана монитора... Просто требуется практика) Спасибо за урок, пошел делать свои картинки =)))
2008-03-21
хых)))это можно сделать..в одной..оч простой прграммке...в максе создать обьект только..потом открыть той прогрой...и вперет)..собсно...именно благодаря этой прогре..я узнал о расширении .max и узнал о 3д максе вообще)
2008-03-26
помогите как кнопки что я нарисовал связать с написаным скриптом а то все вроде сделал а в меню мои кнопки не появляются. Да не смейтесь пишу скрипт первый раз в жизни.
2008-04-18
Спасибо за замечательный урок, AShim! Я его попробую чуть позже, но уже ясно, что такой подход работает просто замечательно. Классический способ генерации стереогрмм - это рендер карты глубины (Z-buffer), по которой потом в другой программе рендрится стереограмма, а тут прямо все сразу в Максе - несомненно удобно. Кстати, вы не возражаете что я перепостил ваш урок в нашем комьюнити, естественно со ссылкой и указанием автора? http://community.livejournal.com/3d_magic_eye/
2008-04-18
у меня на строке: DOF_img = render camera:pb_R_cam.object outputwidth:width outputheight:height channels:#(#zDepth) выскакивает ошибка: -- Unable to convert: undefined to type: Integer у меня 8й Макс, все кажется сделал по инструкции, текстура загружена и камера выбрана. Есть какие-нить идеи насчет ошибки?
2008-04-18
> выскакивает ошибка: > -- Unable to convert: undefined to type: Integer тут я разобрался, по невнимательности пропустил декларации: local T_img = undefined -- текстура local width, height, d_max -- ширина и высота рендера, ширина текстуры Теперь другая фишка, когда нажимаю <>GO у меня вместо стереограммы рендрится обычный вид камеры. Есть какие-нить идеи?
2008-06-01
+ о способах просмотра данных изображений. Лично я натренеровал свои глаза и теперь могу просто левым глазом просматривать правую часть, а правым - левую. И не надо никаких прижиманий монитора к носу или же просмотра сквозь монитор=) +теория. глаза человека устроены так, что сдвинуть их(скосить ">_<") гораздо легче, чем раздвинуть("<_>"). Такова анатомия человека, блин))
2008-06-11
Что то не получается. "3D фон" вижу а предмета нет. Можно написать файл со скриптом отдельно? Без подробных разъяснений. И что бы его скачать как нить можно было?
2008-06-11
[code] utility stereoImg "Stereo Image" -- утилита создания стерео изображения ( -- определение локальных переменных local T_img = undefined -- текстура local width, height, d_max -- ширина и высота рендера, ширина текстуры fn fltr_cam obj = superClassOf obj == camera -- функция возвращает истину если obj камера (для фильтра выбора) group "Texture:" -- параметры текстуры ( label l_T_img "no texture" -- информация о размере button b_T_img "Load texture bitmap" -- загрузка текстуры ) group "Render:" -- параметры рендеринга ( spinner s_R_w "width:" range:[0,1500,0] type:#integer width:82 across:2 -- ширина label l_R_h "height:0" -- высота spinner s_R_prec "quality of stereo image" range:[1,10,4] type:#integer width:80 align:#right -- качество стерео изображения progressBar prb_R_status value:0 -- прогресс рендера pickbutton pb_R_cam "Pick camera" filter:fltr_cam across:2 -- выбор камеры button b_R_stereo "" -- запуск рендера ) on b_T_img pressed do -- загрузка текстуры ( T_file_name = getOpenFileName types:"bitmap(*.bmp)|*.bmp" -- диалог открытия файла if T_file_name != undefined then -- если все файл бы выбран ( T_img = openBitMap (T_file_name) -- загрузка картинки b_T_img.caption = filenameFromPath T_file_name -- на кнопку имя файла картинки l_T_img.caption = "width: " + (T_img.width as String) + " height:" + (T_img.height as String) -- вывести информацию о картинке d_max = T_img.width -- обновление всех локальных переменных height = T_img.height width = 4*height/3 as Integer -- определение ширины рендера так чтоб в итоге получились пропорции 3:4 s_R_w.value = width -- отображение информации о разрешении рендера l_R_h.caption = "height:" + height as String renderWidth = width -- настройка глобальных параметров рендера (ширина, высота) renderHeight = height ) ) on pb_R_cam picked cam do -- выбор камеры ( pb_R_cam.caption = pb_R_cam.object.name -- на кнопку имя камеры ) on s_R_w changed val do -- обработка изменения ширины рендера ( width = s_R_w.value renderWidth = width ) on b_R_stereo pressed do -- просчет стерео изображения ( if (height == undefined) or (width == 0) then ( messageBox "No texture or invalid size" return 0 ) if pb_R_cam.object == undefined then ( messageBox "Pick camera first" return 0 ) -- рендер глубины DOF_img = render camera:pb_R_cam.object outputwidth:width outputheight:height channels:#(#zDepth) unDisplay DOF_img -- создание битмапы для будущего "расширенного" стерео изображения -- причем ширина умножается на точность prec = s_R_prec.value -- точность (коэф. качества) OUT_img = bitmap ((width+d_max)*prec) height color:black -- заполнение первой полосы текстурой for x = 0 to (d_max-1) do ( for y = 0 to (height-1) do for i = 0 to (prec-1) do ( c1 = (getPixels T_img [x,y] 1)[1] -- берем пиксель из текстуры c2 = (getPixels T_img [x+1,y] 1)[1] if c2 == undefined then c2 = (getPixels T_img [0,y] 1)[1] c = c1*(1.*(prec-i)/prec) + c2*(1.*i/prec) -- линейно сглаживаем растяжение setPixels OUT_img [x*prec+i,y] #(c) -- и вставляем в будущее стерео изображение ) prb_R_status.value = (100 * x / d_max) as integer -- обновление прогресса текущей операции ) prb_R_status.value = 0 -- отрисовка "расширенного" стерео изображения H = pb_R_cam.object.farclip -- расстояние от глаз до максимальной глубины h_max = pb_R_cam.object.farclip - pb_R_cam.object.nearclip -- расстояние от плоскости проецирования до макс. глубины a = d_max*H/h_max -- расстояние между глазами -- построчное построение стерео изображения ("расширенное") for y = 0 to (height - 1) do ( for x = 0 to (width - 1) do for dx = 0 to (prec - 1) do ( -- берем из рендера глубины расстояние от камеры до ближайшей точки (тут т
2008-06-11
[code] -- отрисовка "расширенного" стерео изображения H = pb_R_cam.object.farclip -- расстояние от глаз до максимальной глубины h_max = pb_R_cam.object.farclip - pb_R_cam.object.nearclip -- расстояние от плоскости проецирования до макс. глубины a = d_max*H/h_max -- расстояние между глазами -- построчное построение стерео изображения ("расширенное") for y = 0 to (height - 1) do ( for x = 0 to (width - 1) do for dx = 0 to (prec - 1) do ( -- берем из рендера глубины расстояние от камеры до ближайшей точки (тут тоже идет линейное сглаживание) dist = (- (getChannel DOF_img [x,y] #zDepth)[1]*(prec-dx) - (getChannel DOF_img [x,y] #zDepth)[1]*dx)/prec if dist > H then dist = H -- не должно быть больше макс. глубины d = (prec*a*(dist+h_max-H)/(dist)+.5) as integer -- вычисляем расстояние на котором должны совпадать пиксели стерео изображения setPixels OUT_img [x*prec+dx+d_max*prec,y] (getPixels OUT_img [x*prec+dx+d_max*prec-d,y] 1) -- и дубируем пиксели согласно этому расстоянию ) prb_R_status.value =(100 * y / height) as integer ) prb_R_status.value = 0 -- получение из "расширенного" "нормальное" стерео изображение FIN_img = bitmap (width+d_max) height color:black -- создание битмапы для финального стерео изображения for y = 0 to (height - 1) do ( for x = 0 to (width + d_max - 1) do ( c = black for i = 0 to (prec-1) do c += (getPixels OUT_img [x*prec+i,y] 1)[1]/prec -- получение сренего арифметического цвета setPixels FIN_img [x,y] #(c) -- и сохранение его в финальное стрео изображение ) prb_R_status.value =(100 * y / height) as integer ) prb_R_status.value = 0 display FIN_img -- открываем окно с финальным стерео изображением ) ) [/code]
2008-07-02
Интересный урок, спасибо автору! У меня все получилось. :) Только вот я проверяла эту "защиту от дурака" - нажимала без текстуры и без указания камеры. На текстуру стабильно выдает сообщение (ну что ее нет). А на камеру - раз на раз: то делает и без указания камеры, то просит указать камеру. Я заметила, что если перед этой "проверкой" открывать скрипт и заново там нажимать Evaluate All, то "защита от дурака" работает. Я думала, что утилита должна работать без каждого такого "перезапуска"... P.S. Так хотелось этот урок сделать, что пришлось научиться видеть эти стереокартинки, раньше-то у меня это не получалось (только один раз было, и то случайно)!!! На счет точности - я смотрела стереокартинки с разной точностью, пыталась найти разницу, но особо ее не заметила... (может потому что опыта мало - рассматривания стереокартинок, только-только же научилась их видеть?!.) :-D
2009-03-10
Чет у меня ни х.. не получается....(((( если составляю по частям, то он рендерит только текстуру и все. если беру готовый скрипт, то только одну полоску, пробовал исправлять как написано на предыдущей странице, такая же хрень как в первом случае. и если беру скрипт из коментов, то ему чет не нравится в строчке, spinner s_R_w "width:" range: type:#integer width:82 across:2 . че делать, сам чет не доганяю...
2009-11-08
Молодец,всё работает. Причём с первого раза отлично всё получилось. Только все названия я написал по русски.
2010-01-17
Ув. AShim. К Вам вопрос такого характера: Я не очень валаку в скриптах и данный скрипт у меня так и не получилось создать в 3D max 9 v-ray 1.5 RC 3 Возникают постоянные ошибки при его просчете. Не могли бы Вы сами создать уже готовый файл для его реализации и подключения в среду макса через run script/ поскольку не очень опытным пользователям ! Не понятно Ни х... Чего! :-) Если Вас не затруднит очень бы хотелось посмотреть на него в готовом виде. Ошибки возникают. А как их редактировать я, да и думаю что многие пользователи не понимают. За ранее большое спасибо"!!! С Ув. SVM/ svm@gala.net P/S / Буду ждать от Вас ответа.
2010-01-17
Картины получаются !!! - Это факт пробовал смотреть на ту, которую Вы предоставили. Очень круто !!! :-)
2010-01-17
Картины получаются !!! - Это факт пробовал смотреть на ту, которую Вы предоставили. Очень круто !!! :-)
2010-01-20
для тех у кого ничего не получается: [url]http://file.qip.ru/file/116911194/235c9815/stereoImg.html[/url] - файл скрипта для скачивания. и очень важный пункт(надо было выделить в уроке отдельно!!!!): [quote]Выберем необходимую камеру, на панели Modify раскроем свиток Parameters, ставим галочку возле Clip Manually. Осталось только настроить Near Clip и Far Clip. Плоскость Near Clip соответствует плоскости проекции стерео изображения, а Far Clip – расстояние до максимально удаленного объекта. Рекомендации: объекты, по которым будет строиться стерео изображение, должна располагаться между Far Clip и Near Clip, Near Clip равно приблизительно половине Far Clip, объекты должны быть расположены подальше от Near Clip и вплотную к Far Clip. Хотя можно этим пренебречь и в дальнейшем экспериментировать с Clipping Planes, для получения более желаемого результата.[/quote]
2010-01-21
Ув. AShim - судя по всему в скрипте что-то не то, или же я возможно могу ошибаться. Но при запуске через RUN SCRIPT - выдает ошибку --Syntax error: at стерео, expected noButton or hidden --In line: --утилита создни стерео и Я вообще ни чего не понимаю в script, но очень хочется попробывать выполнить свою стерео картинку. Если Вас не затруднит объясните пожалуйста, как возможно сделать это правильно. Возможно что я не так как-то это выполняю. За ранее благодарен. P/S У меня стоит 3d max 9. (пробывал так же через сканлайн). Но ни чего не получается. Спасибо.
2010-01-25
to: _svm поудаляй комменты, т.к. некоторые версии макса русские комменты не понимает.
2020-09-01
Здравствуйте, у вас остался данный код? Просто данная вами ссылка на скачивание не работает, а в новом максе скрипт не запускается, каких либо изменений или замечаний у программы нет
RENDER.RU