Обработка тайлов на SVG. Видны прорези между ними, что делать?
Всем привет. Перейду сразу к делу. Решил создать тестовую tilesheet картинку, разрезать её на тайлы и засетать в SVGшку. Создать что-то типа "карты" для игры.
Выглядит картинка вот так:
На пустом месте в будущем будут остальные тайлы. Но не суть.
Проблема в следующем, когда я размещаю тайлы и стыкую их впритык, точно попиксельно, то получается вот такое:
Проблема в прорезях между ними.
Аттрибут shape-rendering="crispEdges" помог справится с такой же проблемой когда я ставил так черные векторные rectы, их тоже видно на картинке выше (угол из чёрных ректов). Для данного случая, как видно на картинке, я попытался засетать свойство для тэга image
image-rendering: pixelated;
Вроде, это немного улучшило их вид, но всё равно прорези остались. В реакте это выглядит примерно вот так (если конечно это вам необходимо):
return ( <g key={index}> {new Array(posY).fill(null).map((_, y) => { return new Array(posX).fill(null).map((_, x) => { const add = y > 0 ? y * posX : 0 const currentTileId = matrix[x + add] || 0 return ( <svg x={x * cell.x} y={y * cell.y} width={cell.x} height={cell.y} data-tile={currentTileId} viewBox={`${(currentTileId * 64)} ${0} ${cell.x} ${cell.y}`} > <image style={{ imageRendering: "pixelated" }} href={image} /> </svg> ) }) })} </g> ) |
return ( <g key={index}> {new Array(posY).fill(null).map((_, y) => { return new Array(posX).fill(null).map((_, x) => { const add = y > 0 ? y * posX : 0 const currentTileId = matrix[x + add] || 0 return ( <svg x={x * cell.x} y={y * cell.y} width={cell.x} height={cell.y} data-tile={currentTileId} viewBox={`${(currentTileId * 64)} ${0} ${cell.x} ${cell.y}`} > <image style={{ imageRendering: "pixelated" }} href={image} /> </svg> ) }) })} </g> )
Учтите, код ещё крайне сырой, например тайлы по оси Y на тайлшите еще не считываются на viewBox, и там стоит просто 0, а я лишь решаю проблемы по мере их поступления.
В общем вопрос тот же: можно ли хоть как-то избавиться от этих прорезей? Читал, что это возможно связано с сглаживанием на картинках. Возможно стоит попробовать какие-то альтернативные методы вставки тайлов в svg? Canvas не рассматриваем, слишком много нужно переделать.
UPD:
Масштабирование 1920x1080 на общем вьюбоксе. Т.е. пропорция 16/9. Вьюбокс смещен по x y на -960(+32) -540(+32) чтобы центрировать игрока. Также для svg добавил свойство aspect-ratio 16/9 чтобы постоянно поддерживать данную пропорцию.
Сделал предположение, что необходимо с помощью пропорции изменить высоту для одного тайла. 64 * 1080 / 1920 = 36.
Изменение размеров тайлов на 64x36 не помогло.
UPD2:
Сделал jsfiddle чтобы можно было рассмотреть проблему.
snippet
На таком приближении прорези видно на хроме, а вот на фаерфокс, только лишь одна.
UPD3:
Сделал еще один jsfiddle, приблизил и сместил немного игрока, чтобы можно было рассмотреть проблему.
snippet
Пожалуйста, очень надеюсь на вашу помощь!
Дополнительно:
А попробуйте использовать rect, а не image. Ещё можно сделать svg стэк, и использовать через use.
По поводу use, укажите пример кода пожалуйста, что вы имели ввиду.
SVG stacking for reduce page load time & request count
Stack — спрайт здорового человека
SVG-стеки
<g class="map" shape-rendering="crispEdges">
При использовании тэга:
Без использования:
в вашем случае эти кубики надо собирать в одном svg
Вы имеете вложенность svg? От неё ничего не зависит. + это вполне позволимо. Я убирал обёртку svg и резал тайлы через clipPath - это не помогло.
Но в свг чуточку понимаю..
Проблема у вас в коде
Это похоже на известную проблему с рендерингом разных штук в браузерах. Тут два связанных момента - с одной стороны есть вопрос подгонки размеров элементов под пиксельную сетку на экране, и потенциальные ошибки с округлениями значений и "дырками" или "нахлестами" в 1px между сущностями на экране, а с другой - собственно сглаживание, когда у нас появляются промежуточные цвета, смягчающие переходы от одних к другим. Иногда, как в таких ситуациях, мы можем воспринимать их как неуместные.
С размерами мы еще можем попытаться что-то сделать. Например распространенный костыль состоит в том, чтобы по возможности иметь размеры элементов в целом количестве пикселей. Т.е. не давать браузеру округлять на свой вкус. А вот сглаживание мы не можем выключить просто так. Вы нашли атрибут shape-rendering, но если внимательно почитать в стандарте, что он предполагает, то там будут исключительно рекомендательные высказывания:
the user agent might turn off anti-aliasing
или
might adjust line positions and line widths to align edges with device pixels
Но "might" не означает "must". На практике сглаживание или не отключается полностью, или отключается, но границы по пикселям смещаются так, что становится еще хуже, чем было, или еще какая фигня происходит. В разных браузерах все по-разному и поведение немного меняется со временем, так что старые костыли могут переставать работать. В CSS есть свойства, связанные со словом rendering, и они такие же мутные в своих формулировках.
На практике это означает, что единственный вариант взять контроль над рендерингом в свои руки - это рисовать все на канвасе. И хотя вы говорите, что "канвас не рассматриваем", именно он и будет надежным вариантом решить такого рода проблемы раз и навсегда.
-
иметь размеры элементов в целом количестве пикселей. Т.е. не давать браузеру округлять на свой вкус.
Ну, я вроде так и сделал :(
Можете глянуть jsfiddle'ы - вьюбокс главного оборачивающего всё это дело SVG тэга - подпадает под 16/9 пропорции с целыми пиксельными значениями. Сдвиг и размеры каждого тайла тоже целые.
Я ещё немного пошаманю, и если не получится, похоже действительно придется всё это дело переносить на канвас. - PantyDev,
Ну, я вроде так и сделал
Там контекст всего текста в том, что есть два связанных момента. Один решить можно, хоть и костыльно, а второй - нет. Вы может быть и решили половину задачи, которая теоретически поддается решению, но вторую половину в текущих реалиях браузерного разнообразия нельзя решить.
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос







Для того чтобы устранить прорези между тайлами на SVG, можно использовать несколько методов:
1. Использование атрибута shape-rendering="crispEdges" для элементов . Этот атрибут указывает браузеру рисовать границы элементов без сглаживания, что поможет устранить прорези между тайлами.
```php
```
2. Использование атрибута vector-effect="non-scaling-stroke" для элементов . Этот атрибут указывает браузеру не масштабировать обводку элемента, что также поможет избежать прорезей между тайлами.
```php
```
3. Использование атрибута shape-rendering="optimizeSpeed" для элемента . Этот атрибут указывает браузеру оптимизировать отрисовку SVG для повышения производительности, что также может помочь устранить прорези между тайлами.
```php
<!-- Ваши тайлы SVG -->
```
Попробуйте применить эти методы к вашему SVG коду, чтобы устранить прорези между тайлами и добиться желаемого визуального эффекта.