Докуметация Cтарт Статьи Форум Лента Вход
Не официальное русскоязычное сообщество

Свет и тень

Опубликованно: 18.05.2017, 23:06
Последняя редакция, Andry: 30.09.2017 18:48

shading-ani

Свет и тень — это две абсолютно разные вещи в 3D-моделях, хоть мы воспринимаем их вместе в реальной жизни:

  • Освещение означает, что объект ярче на стороне, обращенной к направлению источника света, и темнее на противоположной стороне. Вычислительно, это относительно легко.
  • Освещение само по себе еще не означает что объекты бросают тень на пол или другие объекты: Активизация обработки тени — это дополнительный шаг, описанный здесь. Поскольку отбрасывание теней влияет на производительность, тени и окружающее затенение не активируются по умолчанию.
Источник света с заданным направлением или местоположением требуется для всех геометрий с материалами на основе Lighting.j3md. Окружающего освещения недостаточно. В сценах без соответствующих источников света объекты Геометрии с Lighting.j3md не отображаются. Независимо от каких-либо источников света видны только Геометрии с материалами на основе Unshaded.j3md.

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

light-sources

Вы можете добавить несколько типов источников света в сцену, используя rootNode.addLight(mylight).

Доступные источники света в com.​jme3.​light:

  • SpotLight(Прожектор)
  • PointLight(Точечный свет)
  • AmbientLight(Окружающий свет)
  • DirectionalLight(Направленный свет)

Вы управляете цветом и интенсивностью каждого источника света. Обычно вы устанавливаете цвет на белый (new ColorRGBA(1.0f,1.0f,1.0f,1.0f) или ColorRGBA.White), что делает все элементы сцены видимыми в их естественном цвете.

Вы можете использовать свет с другим цветом, кроме белого или более темных цветов. Это влияет на атмосферу сцены и сделает сцену более холодной (например, ColorRGBA.Cyan) или более теплой (ColorRGBA.Yellow), более яркой (более высокие значения) или более темной (более низкие значения).

Вы можете получить список всех источников света, добавленных в Spatial, вызвав getWorldLightList() (включая унаследованные источников света) или getLocalLightList() (только напрямую добавленные источники света) и итерируя результат.

PointLight(Точечный свет)

elephant-pointlights

PointLight имеет местоположение и светит оттуда во всех направлениях, насколько его радиус охватывает. Интенсивность света уменьшается с увеличением расстояния от источника света. PointLight может использоваться для отбрасывания теней вместе с PointLightShadowRenderer (см. Раздел Casting Shadows)

Типичный пример: лампа, лампочка, факел, свеча.

PointLight lamp_light = new PointLight();
lamp_light.setColor(ColorRGBA.Yellow);
lamp_light.setRadius(4f);
lamp_light.setPosition(new Vector3f(lamp_geo.getLocalTranslation()));
rootNode.addLight(lamp_light);

DirectionalLight(Направленный свет)

house-directionallight

У DirectionalLight нет позиции, только направление. Он посылает параллельные лучи света и считается «бесконечно далеким». У вас обычно есть один источник направленного свет на сцену. DirectionalLight может использоваться вместе с тенями.

Типичный пример: солнечный свет.

DirectionalLight sun = new DirectionalLight();
sun.setColor(ColorRGBA.White);
sun.setDirection(new Vector3f(-.5f,-.5f,-.5f).normalizeLocal());
rootNode.addLight(sun);

SpotLight(Прожектор)

spotlight

SpotLight посылает четкий луч или конус света. SpotLight имеет направление, положение, расстояние (диапазон) и два угла. Внутренний угол является центральным максимумом светового конуса, внешний угол — краем светового конуса. Все внешние углы светового конуса не зависят от света.

Типичный пример: Фонарик

SpotLight spot = new SpotLight();
spot.setSpotRange(100f);                           // расстояние
spot.setSpotInnerAngle(15f * FastMath.DEG_TO_RAD); // внутренний световой конус (центральный луч)
spot.setSpotOuterAngle(35f * FastMath.DEG_TO_RAD); // наружный световой конус (край света)
spot.setColor(ColorRGBA.White.mult(1.3f));         // светлый цвет
spot.setPosition(cam.getLocation());               // shine from camera loc
spot.setDirection(cam.getDirection());             // shine forward from camera loc
rootNode.addLight(spot);

Если вы хотите, чтобы прожектор следил за flycam, повторяйте вызовы setDirection(…) и setPosition(…) в цикле обновления и синхронизируйте их с позицией и направлением камеры.

AmbientLight(Окружающий свет)

AmbientLight просто влияет на яркость и цвет сцены во всем мире. Он не имеет никакого направления и никакого местоположения и светит одинаково повсюду. AmbientLight не отбрасывает тени, и он равномерно освещает все стороны геометрии, что делает 3D-объекты неестественно плоскими; Именно поэтому вы обычно не используете один AmbientLight без одного из других источников света.

Типичный пример: Регулируйте общую яркость, оттеняйте всю сцену в теплом или холодном цвете.

AmbientLight al = new AmbientLight();
al.setColor(ColorRGBA.White.mult(1.3f));
rootNode.addLight(al);
Вы можете постепенно увеличивать яркость источника света, умножая светлый цвет на значения более 1,0f.
Пример: mylight.setColor (ColorRGBA.White.mult (1.3f));

Свет следующий за Spatial

Вы можете использовать com.jme3.scene.control.LightControl, чтобы заставить SpotLight или PointLight следовать за Spatial. Это может быть использовано для фонарика, переносимого персонажем, или для фар автомобиля, или для прожектора самолета и.т.д.

PointLight myLight = new PointLight();
rootNode.addLight(myLight);
LightControl lightControl = new LightControl(myLight);
spatial.addControl(lightControl); // Этот Spatial регулирует положение этого света.

Очевидно, что это не относится к AmbientLights, у которых нет местоположения.

BasicShadowRenderer (устарело)

Пример полного кода

Casting Shadows

Для каждого типа источника внешнего света JME3 реализует два способа моделирования геометрий, отбрасывающих тени на другие геометрии:

  • Теневой рендерер (который вы применяете к окну просмотра) и
  • Теневой фильтр (который вы можете добавить к постпроцессору фильтра экрану обзора).
Класс источника света Класс рендеринга теней Класс теневого фильтра
DirectionalLight DirectionalLightShadowRenderer DirectionalLightShadowFilter
PointLight PointLightShadowRenderer PointLightShadowFilter
SpotLight SpotLightShadowRenderer SpotLightShadowFilter
AmbientLight (непригодный) (непригодный)

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

Вычисления теней (cast и receive) оказывают влияние на производительность, поэтому используйте их экономно. В теневых рендерерах вы можете отключить отбрасывание теней и/или получение тени для отдельных геометрий, для частей графа сцены или для всей сцены:

spatial.setShadowMode(ShadowMode.Inherit);     // Это значение по умолчанию для новых spatial объектов.
rootNode.setShadowMode(ShadowMode.Off);        // Отключить тени для всей сцены, кроме случаев, когда они переопределены.
wall.setShadowMode(ShadowMode.CastAndReceive); // Стена может отбрасывать тени, а также получать их.
floor.setShadowMode(ShadowMode.Receive);       // Любые тени, брошенные на пол, будут скрыты им.
airplane.setShadowMode(ShadowMode.Cast);       // Нет ничего выше самолета, чтобы отбрасывать тени на нем.
ghost.setShadowMode(ShadowMode.Off);           // Призрак полупрозрачный: он не отбрасывает теней.

И рендереры тени, и теневые фильтры используют теневые режимы, чтобы определить, какие объекты могут отбрасывать тени. Однако только рендеры тени обращают внимание на теневые режимы, когда определяют, какие объекты получают тени. С теневым фильтром теневые режимы не влияют на то, какие объекты получают тени.

Вот пример приложения, которое демонстрирует как DirectionalLightShadowRenderer, так и DirectionalLightShadowFilter:

Вот фрагмент ключевого кода:

        DirectionalLight sun = new DirectionalLight();
        sun.setColor(ColorRGBA.White);
        sun.setDirection(cam.getDirection());
        rootNode.addLight(sun);

        /* Отбрасывать тени */
        final int SHADOWMAP_SIZE=1024;
        DirectionalLightShadowRenderer dlsr = new DirectionalLightShadowRenderer(assetManager, SHADOWMAP_SIZE, 3);
        dlsr.setLight(sun);
        viewPort.addProcessor(dlsr);

        DirectionalLightShadowFilter dlsf = new DirectionalLightShadowFilter(assetManager, SHADOWMAP_SIZE, 3);
        dlsf.setLight(sun);
        dlsf.setEnabled(true);
        FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
        fpp.addFilter(dlsf);
        viewPort.addProcessor(fpp);

Аргументы конструктора: * ваш объект AssetManager * размер визуализируемых карт теней, в пикселях с каждой стороны (512, 1024, 2048 и.т.д.) * Количество визуализированных карт теней (больше карт теней = лучшее качество, но медленнее)

Свойства, которые вы можете установить: * setDirection(Vector3f) — направление света * setLambda(0.65f) — уменьшить размер разделения * setShadowIntensity(0.7f) — тень тьмы (1 = черный, 0 = невидимый) * setShadowZextend(float) — расстояние от камеры, до которой будут вычисляться тени

Параллельно-разделенная карта теней (устарело)

Полный код примера

shadow

private PssmShadowRenderer pssmRenderer;
...
public void simpleInitApp() {
    ....
    pssmRenderer = new PssmShadowRenderer(assetManager, 1024, 3);
    pssmRenderer.setDirection(new Vector3f(-.5f,-.5f,-.5f).normalizeLocal()); // направление света
    viewPort.addProcessor(pssmRenderer);

Экранное пространство Ambient Occlusion

Полный код примера

Ambient Occlusion относится к теням, которые соединяются у объектов у которых они накладывающиеся друг на друга при окружающем освещении. Screen Space Ambient Occlusion (SSAO) приближается к тому, как свет излучается в реальной жизни.

В JME3 SSAO реализуется путем добавления экземпляра com.jme3.post.SSAOFilter в область просмотра, которая уже имитирует тени, используя другой метод, такой как DirectionalLightShadowRenderer.

FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
SSAOFilter ssaoFilter = new SSAOFilter(12.94f, 43.92f, 0.33f, 0.61f);
fpp.addFilter(ssaoFilter);
viewPort.addProcessor(fpp);

shading-textured-ani


Переведено для jmonkeyengine.ru, оригинал
Автор перевода: Andry

Добавить комментарий

jMonkeyEngine.ru © 2017. Все права сохранены.