libGDX 3D теневые артефакты

1

У меня возникают проблемы с 3D-тенями libgdx. В моей игре я реализовал экспериментальный DirectionalShadowLight. И все работает отлично на рабочем столе, однако, когда я запускаю его на Android, на земле много артефактов.

Изображение (левый-андроид, правый рабочий стол):

Изображение 174551

Я взял код рендеринга почти непосредственно из тестов в репозиториях libgdx github.

    Gdx.gl.glClearColor(ExtendedEnvironment.FarBackgroundColor.r,ExtendedEnvironment.FarBackgroundColor.g,ExtendedEnvironment.FarBackgroundColor.b,1);
    Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);

    terrain.prepareForShadows();

    environment.shadowLight.begin(new Vector3(cam.position.x+10,0,0), cam.direction);
    shadowBatch.begin(environment.shadowLight.getCamera());

    ball.draw(shadowBatch, null);
    terrain.draw(shadowBatch, null);

    shadowBatch.end();
    environment.shadowLight.end();

    terrain.recoverFromShadows(ball.getPosition().x);

Тебе не очень нравится. Также учитывая, что он работает на рабочем столе, я думаю, что что-то не так с самой теневой реализацией. Есть ли что-нибудь, что я могу сделать, чтобы исправить это? Учитывая, что я никогда не касался шейдера в моей жизни. Может быть, какой-то простой хак? Если бы не кто-нибудь мог рекомендовать другую рабочую теневую реализацию для libgdx?

Спасибо.

EDIT: дополнительный код:

BlendingAttribute  blendAttribute = new BlendingAttribute(1f)
IntAttribute intAttribute = IntAttribute.createCullFace(GL20.GL_FRONT);


 public void prepareForShadows(){

    batchedCubesInstance.materials.first().remove(blendAttribute.type);
    batchedCubesInstance.materials.first().remove(intAttribute.type);


}

public void recoverFromShadows(float posX){

    batchedCubesInstance.materials.first().set(blendAttribute);
    batchedCubesInstance.materials.first().set(intAttribute);

}

    //creating the batchedMesh:

    ModelBuilder builder = new ModelBuilder();
    builder.begin();
    MeshPartBuilder mpb = builder.part("cubes", GL20.GL_TRIANGLES, (Usage.Position | Usage.Normal | Usage.Color), new Material(
            IntAttribute.createCullFace(GL20.GL_FRONT),//For some reason, libgdx ModelBuilder makes boxes with faces wound in reverse, so cull FRONT
            blendAttribute = new BlendingAttribute(1f), //opaque since multiplied by vertex color
            new DepthTestAttribute(true), //don't want depth mask or rear cubes might not show through
            ColorAttribute.createDiffuse(Color.WHITE) //white since multiplied by vertex color
            ));

    for (int i=0; i < NUMCUBES; i++){

        mpb.box(1, 1, 1); 

    }
    batchedCubes = builder.end();
    batchedCubesInstance = new ModelInstance(batchedCubes);

Изображение 174551

  • 0
    что делает terrain.prepareForShadows(); а terrain.recoverFromShadows делать? похоже, что ваша местность вообще не должна отбрасывать тени, поэтому не визуализируйте их в shadowLight.
  • 0
    Эти методы удаляют blendingAttribute из моей пакетной модели, чтобы разобраться с тем фактом, что тени не поддерживают полупрозрачный материал. Я пытался отодвинуть всю землю, прежде чем рендерить тени, но это ничего не изменило. Кроме того, эти артефакты, кажется, появляются на всем, не только на земле. (Я добавил картинку и немного кода)
Показать ещё 9 комментариев
Теги:
libgdx
3d
shadows

1 ответ

7
Лучший ответ

Проблема, которую вы испытываете, называется тенью акне (в отличие от peter panning), которая вызвана ошибками точности с плавающей запятой. Они более заметны на мобильных устройствах, чем на рабочем столе, поскольку точность на рабочем столе чаще всего лучше. Существует несколько способов избежать теневых угрей. Один из них - убедиться, что ближняя и дальняя плоскости камеры находятся как можно ближе друг к другу. Поэтому не используйте очень маленькое cam.near и очень высокое значение cam.far. DepthShader (который используется для создания буфера глубины) пытается избежать теневых угрей, только имея задние лица, отбрасывающие тени. Для этого используется отбраковка лицевой поверхности.

Тем не менее, вы также отбрасываете лицевую грань для обычного рендеринга (вы делаете только обратную сторону моделей). Это приводит к тому, что видимые грани и грани используются для генерации буфера глубины одинаковыми. Отсюда тень акне.

Вы можете решить эту проблему, используя отбрасывание задней поверхности при создании теневой карты. Однако это слишком усложнит ваш код и может вызвать другие (будущие) проблемы. Вместо этого вы должны стараться держать передние грани видимыми гранями, тем самым удаляя IntAttribute.createCullFace(GL20.GL_FRONT). Обратите внимание, что по умолчанию обратные лица отбираются, вам не нужно указывать это.

Удаление атрибута cull face может привести к другим проблемам в вашем обычном рендеринге (в противном случае у вас его не было бы там в первую очередь). Это, скорее всего, потому, что вершинная обмотка ваших моделей неверна. Вы говорите, что создаете их, используя:

for (int i=0; i < NUMCUBES; i++){
    mpb.box(1, 1, 1); 
}

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

Если по какой-то причине вы не хотите исправлять обмотку вершин, вы можете вызвать Gdx.gl.glFrontFace​(GL20.GL_CW); для замены вершинной обмотки, используемой против часовой стрелки, по часовой стрелке. Обратите внимание, однако, что это может вызвать другие (будущие) проблемы, потому что чаще всего используется значение по умолчанию (против часовой стрелки).

  • 0
    Большое спасибо за подробное объяснение. Моя проблема решена сейчас!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню