Выбрать главу

Мы также определяем два выходных сокета: Height будет содержать рассчитанную высоту и Normal будет содержать соответствующую нормаль в этой же точке. Normal - это то, что Вы должны обычно использовать для получения поверхностного эффекта распространения, но рассчитанная высота может быть полезной, например, чтобы смягчить величину отражательной способности поверхности.

Инициализация заканчивается с определением некоторых переменных экземпляра, которые будут использованы, чтобы определить, нужно ли нам вычислять позицию падения капли заново, как мы увидим в определении функции __call__().

Определение функции __call__() начинается с инициализации множества локальных переменных. Одно примечательное место - то, где мы установили произвольное семя, используемое функциями модуля Noise (выделено в следующем коде). Таким образом, мы убеждаемся, что всякий раз, когда мы пересчитываем точки удара, мы получаем повторяемые результаты, что если мы установили бы количество капель в секунду сначала на десять, а позже на двадцать, и, затем ввернулись к десяти, сгенерированный узор будет тем же. Если Вы хотели бы изменить это, Вы могли бы добавить дополнительный входной сокет, который нужно использовать как вход для функции setRandomSeed():

   def __call__(self):

      twopi = 2*pi

      col = [0,0,0,1]

      nor = [0,0,1]

      tex_coord = self.input.Coords

      x = tex_coord[0]

      y = tex_coord[1]

      a = self.input.a

      c = self.input.c

      Noise.setRandomSeed(42)

      scn               = Scene.GetCurrent()

      context           = scn.getRenderingContext()

      current_frame     = context.currentFrame()

      start_frame       = context.startFrame()

      end_frame         = context.endFrame()

      frames_per_second = context.fps

      time = current_frame/float(frames_per_second)

Следующим шагом нужно определить, должны ли мы вычислять позиции точек удара капель заново. Это необходимо, только если величина входного сокета  drops_per_second была изменена пользователем (Вы могли бы соединить этот вход с некоторым другим нодом, который будет изменять эту величину на каждом пикселе, но это плохая идея), или когда стартовый или конечный кадр анимации изменились, как эти влияния количества капель мы должны вычислять. Этот тест выполняется на выделенной строке следующего кода сравнением вновь полученных величин с сохранёнными в переменных экземпляра:

      drops_per_second = self.input.Drops_per_second

      # вычисление числа капель для генерации

      # в период анимации

      ndrops = 1 + int(drops_per_second * \

               (float(end_frame) – start_frame+ 1)/ \

               frames_per_second )

      if self.drops_per_second != drops_per_second \

      or self.ndrops != ndrops:

         self.drop = [ (Noise.random(), Noise.random(),

            Noise.random() + 0.5) for i in range(ndrops)]

         self.drops_per_second = drops_per_second

         self.ndrops = ndrops

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

Строк оставшейся части полностью выполняются всякий раз при вызове __call__(), но выделенная строка показывает значимую оптимизацию. Поскольку капли, которые еще не упали в текущем кадре, не привносят изменений высоты, мы исключаем их из вычисления:

      speed=self.input.speed

      freq=self.input.freq

      dampf=self.input.dampf

      height = 0.0

      height_dx = 0.0

      height_dy = 0.0

      nabla = 0.01

      for i in range(1+int(drops_per_second*time)):

         dropx,dropy,dropsize = self.drop[i]

         position_of_maximum=speed*time- \

            i/float(drops_per_second)

         damping = 1.0/(1.0+dampf*position_of_maximum)

         distance = sqrt((x-dropx)**2+(y-dropy)**2)

         height += damping*a*dropsize* \

            exp(-(distance-position_of_maximum)**2/c)* \

            cos(freq*(distance-position_of_maximum))

         distance_dx = sqrt((x+nabla-dropx)**2+ \

                            (y-dropy)**2)

         height_dx += damping*a*dropsize* \