Перейти к содержимому
  • 0
Oleshe

Свет и его причуды

Вопрос

У меня есть наработка, идея: у нас есть список с 3 параметрами, цвет света, радиус (длинна) света и интенсивность.

Код:

Скрытый текст

local GUI = require("GUI")
local screen = require("Screen")
local color = require('color')

--------------------------------------------------------------------------------

function round(num)
  return math.ceil(num)
end
local workspace = GUI.workspace()

--------------------------------------------------------------------------------
light = {intensivity=0.1,radius = 30,color = 0xFF0000}
local object

local function idk(x,step)
  return (x-step)/(light.intensivity-step) -- Что-бы значение интенсивности колебалось от 0 до 1, а не было 20
end

workspace.eventHandler = function(_,_,...)
  local args=  {...}
  if args[1] == 'touch' then -- При клике создадим объект
  object = workspace:addChild(GUI.object(args[3], args[4], 50, 10))
  object.draw = function(object)
    local x,y = object.x, object.y
    function set(x,y,intensivity)
      local x,y = round(x), round(y)
      local was = {screen.get(x,y)} -- Получаем цвета старого пикселя ..
      screen.set(x,y,color.blend(was[1],light.color,intensivity),color.blend(was[2],light.color,intensivity),was[3]) -- .. и миксуем его с нашим
    end
    local step = light.intensivity/light.radius -- шаг на 1 радиус, что-бы интенсивность света в конце +- была ровна 0
    for radius = 0, light.radius do
      local calc = radius * step -- Как-бы мерием сколько мы прошли, что-бы понять интенсивность света на этом этапе
      local balance = calc -- Раньше сдесь было доп условие, оно не нужно. Пока-что так.
      local last = 0 -- Затычка для будущего момета с отладкой
      for angle = 1,180 do -- Чем меньше, тем меньше "лучей" мы пустим. Полагаю большое количество не имеет смысла.
        if last ~= balance then     --      -   -  - -- Отладка
          print(idk(balance,step),balance,step,calc) -- Отладка
        end     --       -     -     -      -        -- Отладка
        last = balance   --   -        -  -      -   -- Отладка
        set(math.cos(math.deg(angle))*radius+x,(math.sin(math.deg(-angle))*radius)/1.5+y,idk(balance,step)) -- Ставим пиксели, высоту делим на 1.5 для более мене круга. Интересно как оно себя поведёт. 
      end
    end
  end
    workspace:draw()
  end
end
workspace:draw()
workspace:start()

 

image.png

Пример к коду, недостаток angle в цикле. Недостаток "лучей" для круга. А еще красиво.

image.png.7eeec3f0333886906dec6d313c305ad1.png

Радиус 10

image.png.b742b5577101aa7e41eb9740f3bc499e.png

Радиус 30

Проблема: Как бы ты не изменял интенсивность, результат тот-же. Не правильно считает центр, он заливается сплошным цветом вместо градиента.

Должно-быть: чем больше интенсивность, тем больше должно убавляться света на радиус. Я не знаю что я делаю не так что-б результат получался одинаковым любом случаи. Вся интенсивность почему-то концентрируется в центре. Жэнтэльмены, помогите узнать что я делаю не так.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Рекомендуемые сообщения

1. Высоту можно сразу делить на 2, вроде пиксели в OC 8x4.

2. Логично, что всё концентрируется в центре. Там очень много лучей друг на друга накладываются и перемешиваются до того, что получается сплошной красный цвет. Можно убавлять количество лучей в зависимости от радиуса: for angle = 1,math.max(5,math.ceil(180*radius/light.radius)) do

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
12 часа назад, ProgramCrafter сказал:

for angle = 1,math.max(5,math.ceil(180*radius/light.radius)) do

Практически исправлено.

image.png.6923b3b789cb922d8447f1bf4a994db8.png

Радиус 30

image.png.b124f0bb69f5c7ffcb9adb0636699f53.png

Радиус 10

В 10-м радиусе видно что оно всё еще концентрируется.

Попробовал сделать сначала "карту" того что у нас есть, если мы уже ставили пиксель на это место мы скипнем set тем самым не повторяясь. Производительность по памяти немного будет плакать.

image.png.ffbaeca582d66e94539dce12f29f76cc.png

Радиус 30 интенсивность 10

image.png.587bbd7a181874abda634a817d3d48ad.png

Интенсивность 1 (Реально)

Интенсивность до сих пор не на что не влияет. Есть линий которые не краситься.

18 часов назад, Oleshe сказал:

Должно-быть: чем больше интенсивность, тем больше должно убавляться света на радиус.

Код:

Скрытый текст

object.draw = function(object)
    local x,y = object.x, object.y
    local alr= {} -- "карта" пикселей
    for xx = 1,light.radius+object.x do
      alr[xx] = {}
      for yy = 1,light.radius+object.y do
        alr[xx][yy] = false -- Заполняем "карту" пикселей
      end
    end
    function set(x,y,intensivity)
      local x,y = round(x), round(y)
      local was = {screen.get(x,y)}
      if not alr[x][y] then -- Если не закрасили
        screen.set(x,y,color.blend(was[1],light.color,intensivity),color.blend(was[2],light.color,intensivity),was[3])
        alr[x][y] = true -- Закрасили
      end
    end
    local step = light.intensivity/light.radius
    for radius = 0, light.radius do
      local calc = radius * step
      local balance = calc
      local last = 0
      for angle = 1,math.max(5,math.ceil(180*radius/light.radius)) do
        if last ~= balance then
          print(idk(balance,step),balance,step,calc)
        end
        last = balance
        set(math.cos(math.deg(angle))*radius+x,(math.sin(math.deg(-angle))*radius)/2+y,idk(balance,step))
      end
    end
  end

 

И как кстати сделать больше изменений интенсивности на пиксель что-бы переход был плавнее.7 

Изменено пользователем Oleshe

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
В 07.07.2023 в 21:39, Oleshe сказал:

И как кстати сделать больше изменений интенсивности на пиксель что-бы переход был плавнее.

Взять тир3 видеокарту и монитор.

 

В 07.07.2023 в 21:39, Oleshe сказал:

Интенсивность до сих пор не на что не влияет. Есть линий которые не краситься.

Тогда надо начинать делать по-другому: проходиться по всем пикселям и смотреть, в какой цвет их покрасить, в зависимости от [квадрата] расстояния от центра. (Что-то мне помнится, что освещённость обратно пропорциональна квадрату расстояния до источника света.)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
В 08.07.2023 в 22:56, ProgramCrafter сказал:

Взять тир3 видеокарту и монитор.

Я не знаю и не видел людей которые используют т2 монитор для MineOS. Надеюсь и не увижу.

 

В 08.07.2023 в 22:56, ProgramCrafter сказал:

..  зависимости от [квадрата] расстояния от центра. ..

Как это сделать? Вообще не представляю. Ну, как мы узнаем какая прозрачность нам нужна от квадрата расстояния? Попустить получившуюся цифру через штуку которая делает из 123790  0.543?

image.png.10ad7c6338943e26011f38338b4ea253.png

Вот, это если радиусы в квадрат.

Скрытый текст

local GUI = require("GUI")
local screen = require("Screen")
local color = require('color')

--------------------------------------------------------------------------------

function round(num)
  return math.ceil(num)
end
local workspace = GUI.workspace()

--------------------------------------------------------------------------------
light = {intensivity=5,radius = 30,color = 0xFF0000}
local object

local function idk(x,step)
  return (x-step)/(light.radius^2-step) -- квадратик
end

workspace.eventHandler = function(_,_,...)
  local args=  {...}
  if args[1] == 'touch' then
  object = workspace:addChild(GUI.object(args[3], args[4], 50, 10))
  object.draw = function(object)
    local x,y = object.x, object.y
    local alr= {}
    for xx = 0,light.radius*2+object.x+1 do
      alr[xx] = {}
      for yy = 0,light.radius*2+object.y+1 do
        alr[xx][yy] = false
      end
    end
    function set(x,y,intensivity)
      local x,y = round(x), round(y)
      local was = {screen.get(x,y)}
      if x > light.radius*2 +object.x+1 then
        return
      end
      if not alr[x][y] then
        screen.set(x,y,color.blend(was[1],light.color,intensivity),color.blend(was[2],light.color,intensivity),was[3])
        alr[x][y] = true
      end
    end
    local step = light.intensivity/light.radius
    for radius = 0, light.radius do
      local calc = radius ^ 2 --квадратик
      local balance = calc
      local last = 0
      for angle = 1,math.max(5,math.ceil(180*radius/light.radius)) do
        if last ~= balance then
          print(idk(balance,step),balance,step,calc)
        end
        last = balance
        set(math.cos(math.deg(angle))*radius+x,(math.sin(math.deg(-angle))*radius)/2+y,idk(balance,step))
      end
    end
  end
    workspace:draw()
  end
end
workspace:draw()
workspace:start()

 

Интенсивность так-же не на что не влияет :/. Отличается тем что середина стала пухлее. Может я что-то не так считаю, не знаю.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Теперь лучше уже проходиться не лучами от центра, а просто по всем пикселям экрана. А освещённость откалибровать, например, так: "если интенсивность равна 1, то точка рядом с центром имеет полную освещённость" - тогда формула будет что-то вроде color.blend(was[1], light.color, light.intensivity / math.max(1, radius ^ 2)).

 

P.S. Хочу потом увидеть программу, где это будет использоваться.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Скрытый текст

 

image.png.5da16c8ef9cafdf9b78dcda2c23daed6.png

😋🥰

 

image.png.fd797b0bdecfb7d63f79534f7efb6f41.png

Скрытый текст

local function destantion(point1,point2)
  return math.sqrt((point1[1]-point2[1])^2+(point1[2]-point2[2])^2)
end

workspace.eventHandler = function(_,_,...)
  local args=  {...}
  if args[1] == 'touch' then
  object = workspace:addChild(GUI.object(args[3], args[4], light.radius*2, light.radius*2))
  object.draw = function(object)
    local tmp
    for xx = 0,light.radius*2 do
      for yy = 0,light.radius do
        local was = {screen.get(object.x+xx,object.y+yy)}
        local radius = destantion({object.x + light.radius, object.y + light.radius/2}, {object.x+xx,object.y+yy})
        screen.set(
          object.x + xx,
          object.y + yy,
          color.blend(was[1], light.color, -((light.intensivity / math.max(1, radius ^ 2))-1)), -- -((light.intensivity / math.max(1, radius ^ 2))-1) - Обратное от полученого числа. Если 1 то 0, 0.25 то 0.75, 0.47 то 0.53. Сделано т.к. оно наоборот засасывало цвет в центр, а не высвобождало его.
          color.blend(was[2], light.color, -((light.intensivity / math.max(1, radius ^ 2))-1)),
          was[3]
        )
      end
    end
  end
workspace:draw()
  end
end

 

 

Получил что-то похожее на круг. Теперь интенсивность решает, но радиус перестал. Cтранно красит середину.

Забавно что при повторных кликах "освещение" растёт у каждой точки, даже ранее поставленной. При этом центр становиться чёрным. Пробовал сделать через штуку которая 1234 в 0.5 для того что-бы цвет пофиксить, но оно выдавало в конченом счёте..: бесконечность.

image.png.172749f81323fdccc3c8933e924b71ce.png

Буквально бесконечность.

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

 

8 часов назад, ProgramCrafter сказал:

P.S. Хочу потом увидеть программу, где это будет использоваться.

 

Здесь присобачим как объект света. Подумаем как сделать ограниченное поле освещения, весь фарш и готово. Мы-ж объекты можем там таскать туда-сюда, изменять их на ходу. Удобно вроде сделал. Недавно кстати появились сцены как в унити, но лучше пока с ними не гулять, а то зарежут. В них лучше использовать только базовые объекты (Всё кроме анимации и файлов, скрипты норм работают), остальные хз как поведут.  Добавить объект легче чем создать. Но и там бывают траблы... Этот трабл кстати появился из-за идеи всё упаковывать, что касается определённых сцен (Файлы скрипты, локализация) отдельно друг от друга: в архив. То-же будет и в экспорте. Еще будут "общие файлы" которые будут доступны во всех сценах.

Наверное больше подробностей, чем ожидалось.

Изменено пользователем Oleshe

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить на вопрос...

×   Вы вставили отформатированное содержимое.   Удалить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.


×
×
  • Создать...