GTSportのユーザーデカール機能でグラデーションが表示されない問題と対処法(追記あり)

はじめに

PS4用のGran Turismo SportではユーザーがSVGファイルを投稿できる、だがその際にグラデーションが適切に表示されない不具合が起きたのでその原因と対処法を記録する。

またこの内容は、2017年11月25日時点のもので、将来的なアップデートにより変化するかもしれない

簡易目次

問題の起きるSVGファイルの例

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" viewBox="0 0 200 200">
<defs>
  <linearGradient id="a">
    <stop offset="0" stop-color="#ff7"/>
    <stop offset="1" stop-color="red"/>
  </linearGradient>
<linearGradient id="b" xlink:href="#a"/>
</defs>

<rect x="10" y="10" width="180" height="80" fill="url(#a)" stroke="#000"/>

<rect x="10" y="110" width="180" height="80" fill="url(#b)" stroke="#000"/>

</svg>

このSVGファイルでは、2個の矩形にそれぞれグラデーションが指定されている。いずれもSVGの仕様に沿って記述されているのでブラウザでは適切に表示される。

現象の確認

デカールアップローダーのページ

デカールアップローダー(要ログイン)のページではブラウザで見ているので、この状態では適切に表示されている。

ゲーム内での表示

しかしゲーム内ではこのように表示されてしまう

上段のものはゲーム内でもグラデーションが表示されるものの、下段の方はゲーム内では真っ黒になってしまう。

問題が発生する要因の簡単な解説

SVGの仕様について説明すると長くなるので、ここでは簡単にまとめる。

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" viewBox="0 0 200 200">
<defs>
  <linearGradient id="a">
    <stop offset="0" stop-color="#ff7"/>
    <stop offset="1" stop-color="red"/>
  </linearGradient>
<linearGradient id="b" xlink:href="#a"/>
</defs>

<rect x="10" y="10" width="180" height="80" fill="url(#a)" stroke="#000"/>

<rect x="10" y="110" width="180" height="80" fill="url(#b)" stroke="#000"/>

</svg>

繰り返しになるが、このSVGファイルは仕様上なんら問題なく記述されている。

しかし下段の矩形のグラデーションに関わる設定でxlink:href属性が使われているのだが、これが要因となって表示の崩れが生じている。

Gran Turismo Sportでは、どうやらxlink:href属性の利用が制限されているようで、本来のSVGの仕様に沿っているのであれば何にも問題の無い記述であるはずなのに、適切に表示されなくなってしまう。

ちなみに(まだ検証中だが)このxlink:href属性の問題はグラデーションだけに限らず他の要素にも影響が多く、SVGファイルにxlink:href属性があればGran Turismo Sportへの投稿で不具合が発生する可能性が高い。

対処方法:Adobe Illustratorの場合

再度繰り返すが、xlink:href属性を利用してグラデーションの設定を記述するのはSVGの仕様上なんら問題が無いどころか、むしろファイルサイズの削減にもつながり利便性が大きい手法なので、当然ながらAdobe IllustratorでSVGファイルを制作する際にも使われることが多い。

しかし、Adobe Illustratorでは2種類のSVGファイル出力方法があるので、それらを理解すれば対処はしやすい

Adobe IllustratorからSVGファイルを出力する方法

Adobe IllustratorからSVGファイルを書き出す方法はいくつかあるが、それらはこのように分けられる

この2つはSVG出力の処理が異なり、前者ではIllustrator9の頃(2001年頃?)に実装された書き出し機能で、後者はIllustrator CC 2015.2以降に追加された新しい機能。

そのため後者では無駄な記述を削り、ファイルサイズを抑えたSVGが出力できるようになったものの、それゆえにxlink:href属性を利用しているので、Gran Turismo Sportでは不具合が出てしまう。

Adobe Illustratorでの対処方法まとめ(追記あり)

というわけで、Adobe Illustratorでは「保存」「別名で保存」「複製を保存」でSVGファイルを出力すればxlink:href属性を使ってグラデーション設定を行わないので、Gran Turismo Sportでもきちんと表示される。


追記ここから

本ページ下部にも追加したが、xlink:href属性の問題とはまた別の要因で、グラデーションが表示されないことが分かった。

「保存」「別名で保存」「複製を保存」でSVGファイルを出力するのは変わらないが、その際には「CSSプロパティ」の項目で「プレゼンテーション属性」を選ぶ必要がある

というのも、「スタイル要素」ではグラデーションが表示されないため。

なお「スタイル属性」「スタイル属性(実体参照)」はグラデーションの表示には問題ないが、ファイルサイズが無駄に大きくなって場合が多いので、お勧めしない。


ただ、「保存」「別名で保存」「複製を保存」の場合はSVGのファイルサイズが大きくなってしまうので、出力後にSVGOSVGOMGの軽量化ツールを使用しておくと良い。

対処方法:Inkscapeの場合

Adobe Illustratorであれば保存方法の変更で済むが、Inkscapeの場合は対処方法が難しく、また説明も複雑になってしまうので対処方法の前に、まずは先にグラデーションの仕組みから解説していく。

SVGでのグラデーションの仕組み

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200">
<defs>
  <linearGradient id="a">
    <stop offset="0" stop-color="#3ae0ff"/>
    <stop offset="1" stop-color="#3f28d1"/>
  </linearGradient>
</defs>

<rect x="10" y="10" width="180" height="180" fill="url(#a)"/>

</svg>

これはシンプルなグラデーションで、rect要素で矩形を描き、塗り(fill)は#aとなっている。これはid="a"としたlinearGradient要素を参照しているためで、図にするとこのようになる。

こうした記述であればGran Turismo Sportでも問題なく使える。


続いて次の例

この例では2つの矩形にそれぞれグラデーションが設定されている。ただグラデーションの向きは異なるものの、配色は共通なのでそのためInkscapeではこのようなグラデーションはこうした方式で記述する。

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
 viewBox="0 0 300 300" width="300" height="300">
<defs>
  <linearGradient id="B">
    <stop offset="0" stop-color="#3ae0ff"/>
    <stop offset="1" stop-color="#3f28d1"/>
  </linearGradient>
  <linearGradient id="C" x1="100%" x2="0%" xlink:href="#B"/>
  <linearGradient id="D" y2="100%" xlink:href="#B"/>
</defs>

<rect x="10" y="10" width="280" height="90" fill="url(#C)"/>

<rect x="10" y="110" width="280" height="180" fill="url(#D)"/>

</svg>

これは図にするとこのようになる。

先程と同じようにrect要素は塗り(fill)をlinearGradient要素に参照する。

id="C"id="D"のlinearGradient要素ではどの方向にグラデーションを塗るのか設定されているが、どの色でグラデーションを作成するかはさらにid="B"のlinearGradient要素を参照している。

今回のような共通の配色であれば、設定をまとめておけば管理もしやすく無駄な記述も抑えてファイルサイズ軽量化にもつながるため、利点も多い。

しかし、このxlink:href属性で参照する部分がGran Turismo Sportでは制限されてしまっている。

以上を踏まえた上で、対策としては

こうした仕様を踏まえた上で、Inkscapeでxlink:href属性での参照を避けたグラデーションを作成するには、

この条件を避けることが肝要になる。

実際にInkscapeではどのようにグラデーションを作成すればよいのか?

グラデーションを作成する

要は同じ配色・透明度のグラデーションがあるからダメなので、全てのグラデーションで色を変えれば問題ない

変更するのは、

RGBそして透明度の数値のいずれかの数値が1違うだけで、別のグラデーションとして処理されるので、面倒な作業ではあるがInkscapeで2個以上のグラデーションを利用する際には、そのたびに色を変更が必要になる。

そしてSVGを書き出す際には

そうしてグラデーションの色をそれぞれ変更した上で、もう一つ必要な作業が適切なSVG出力形式を選ぶこと。

InkscapeではSVGファイルを出力するのに4種類の方法があり

このうち、Gran Turismo Sportでも適切にグラデーションが表示されるような形式でSVGを出力できるのは「最適化 SVG」しかないので、必ずこれを選択しなくてはならない。

Inkscapeでの対応策まとめ

というわけで、改めてInkscapeでの対応策をまとめると

となる。

まとめ

今回はAdobe Illustrator、Inkscapeのみ取り上げたが、それ以外のオーサリングツールでもxlink:href属性が使われている場合には同様の問題が起こると思われる。

また、xlink:href属性はグラデーションだけに限らず様々な要素で使われており、まだ検証し切れていないがそれらでも同じように動作がうまくいかないようなので、ユーザーデカールを制作する際には注意が必要だ。

補足:様々なグラデーションの例

実はInkscapeでの制作では、全てのグラデーションで配色・透明度の変更が必要なのではなく、そのままでも大丈夫な状況もあれば、やはり変更が必要な状況もある。

その違いはかなりややこしいので、いくつか実例を挙げて解説していく。

大丈夫なケース

全く同じグラデーション設定の場合

<svg xmlns="http://www.w3.org/2000/svg" width="200" height="280" viewBox="0 0 200 280">
<defs>
  <linearGradient id="g1">
    <stop offset="0" stop-color="#3ae0ff"/>
    <stop offset="1" stop-color="#3f28d1"/>
  </linearGradient>
</defs>

<rect x="10" y="10" width="180" height="80" fill="url(#g1)" stroke="#000"/>

<circle cx="100" cy="180" r="80" fill="url(#g1)" stroke="#000"/>

</svg>

この場合、図形は矩形と円形で異なるが塗り(fill)は全く同じグラデーション設定が指定されているため、Inkscapeから出力した(最適化SVGで)ときにもxlink:href属性が使われない。

図にするとこのようになる

グループ化してのグラデーション

このSVGでは、矩形と円形の2つの要素があるが塗り(fill)ではグラデーションがつながっている、こうした表現はInkscapeではグループ化をしてグラデーション設定をすることになる。

以下は実際のSVGファイルの中身

<svg xmlns="http://www.w3.org/2000/svg" width="330" height="220" viewBox="0 0 330 220">
<defs>
  <linearGradient id="g2" gradientUnits="userSpaceOnUse">
    <stop offset="0" stop-color="#3ae0ff"/>
    <stop offset="1" stop-color="#3f28d1"/>
  </linearGradient>
</defs>

<g fill="url(#g2)">
  <rect x="10" y="10" width="180" height="80"/>
  <circle cx="230" cy="120" r="80"/>
</g>

</svg>

g要素の子要素として、rect要素・circle要素が配置されている。g要素は画面には直接表示されないが、要素をまとめる働き(グループ化)をする。

そして図にするとこうで、

g要素でまとめて設定することで、子要素のグラデーションをつなげて指定できる。

このケースでも先程と同様にInkscapeでも問題なくSVG出力ができる。

問題があるケース・配色か透明度の変更が必要なケース

グラデーションの種類が違うが、配色・透明度が同じ場合

この例では、線形グラデーションと円形(放射)グラデーションとで全く違うグラデーションのように見えてしまうが、開始色・終了色の配色と透明度がどちらも同じなので、Inkscapeでは同一のグラデーションとして扱われ、xlink:href属性が使われる。

ユーザーデカール制作には困るので、いずれかのグラデーションで変更が必要になる。

グラデーションの位置や長さが異なるが、配色・透明度が同じ場合

グラデーションの長さや位置が異なるケース、この状況も全く違うグラデーションのように見えるが、実態としては開始色・終了色の配色と透明度がどちらも同じなので、Inkscapeでは同一のグラデーションとして扱われ、やはりxlink:href属性が使われる。

ここでのまとめ

以上、Inkscapeでのグラデーション制作における事例をいくつか紹介した。

正直なところ、Inkscapeでの挙動とSVGについての理解の両方が必要となるので、かなりややこしい。上述もしたがグラデーションに限らず、xlink:href属性が使われているとGran Turismo Sportでは何らかの不具合が起きる可能性が高いので、何か問題が起きた場合はその点を疑った方が良く、試行錯誤してなんとか出ない手段を模索してほしい。

参考リンク

追記:「スタイル要素」指定した場合、グラデーションが表示されない問題と対処法

<svg xmlns="http://www.w3.org/2000/svg" width="200" height="100" viewBox="0 0 200 100">
<defs>
  <style type="text/css">
    rect{
      fill: url(#a);
    }
  </style>
  <linearGradient id="a">
    <stop offset="0" stop-color="#ff7"/>
    <stop offset="1" stop-color="red"/>
  </linearGradient>
</defs>

<rect x="10" y="10" width="180" height="80"/>

</svg>

こうした記述の場合、ゲーム内ではグラデーションが表示されない問題があると分かった(thx! @Chinshiko_P

このような状況になるのは、Adobe IllustratorでSVGファイルを出力する際に「CSSプロパティ」で「スタイル要素」を選択した場合。

そのため、書き出す際は「プレゼンテーション属性」を選ぶと良い

「スタイル属性」「スタイル属性(実体参照)」を選んでも問題は無いが、これらの方式は記述量が多くなりがちで大抵の場合ファイルサイズが増える原因になるのでメリットはあまりないため。


またInscapeでは「最適化SVG」を選択すれば、style要素は使わないで書き出せる。

その際に、オプション画面で

となる。