2019年7月19日 星期五

[筆記]一個日本動畫產業相關的募資計劃New Anime Making System Project

  

  最近從一篇報導日本動畫產業慘況的文章得知日本有個希望能改善目前環境的募資計劃New Anime Making System Project,這篇本來是打算去相關論檀推廣的,但因為在寫這篇時剛好發生京阿尼工作室大火事件,就募資來說京阿尼目前比較需要(京阿尼募款以及線上購買他們商品的方法),而且我這邊也有提到京阿尼,感覺不太好意思這個時間點向人推廣。然後我一直思考到他提的一些方法其實我自己也發現到一些疑問(後面會提),所以我在這邊就先暫時放著不推廣,這邊應該算邊緣人的blog,這樣放著應該不會有什麼問題(就是怕其募資要是沒太大正當性,若推廣了會有誤導人的感覺)。

  先介紹一下他的計劃:

目的

we are planning on increasing production costs to increase wages, and create a flow in which sales profit are returned to animators.

  簡單來講就是他們希望透過產品的製作去增加收入,把那些收入回饋給那些動畫人員。

方法

1.Use the crowdfunding campaign to raise money from anime fans, and pass the money directly to production staff, such as animators.

  1.將募資來的錢直接支付給動畫從業人員。

2.Create a direct flow of money from fans to animators that will allow production staff to have sufficient time and budget to focus on making better anime.

  2.創造一個能從粉絲到動畫從業人員的完整現金流 讓製作方能有足夠預算製作動畫。

3. Run a smaller, independent system so that not only animators are paid through production costs, but also through profits made by the sales profit are returned to animators as royalty.

  3.創造一個獨立的系統 讓從業人員除了收到薪水之外 也能從其他週邊營收管道獲利。這些都是增加從業人員現金流的方式,目的都是改善動畫人的待遇。
 

首先要嘗試的具體行動

By Fall 2019, our first plan is to create the 30-second sample video for the Anime-Kikaku Grand Prix (explained under "Our Goal").

After Fall 2019, the Anime-Kikaku Grand Prix will be hosted as we will ask for submissions for both the Manga and Music category.

  首先他們主要是打算辦一個比賽徵稿,共有兩個獎項,分別是漫畫大賽與音樂大賽,他要為第一名得獎者分別製作兩個動畫,前者當然就是該漫畫的動畫,後者則是音樂MV動畫。

  所以他在辦這比賽前會先繪製一個30秒的短片動畫此處可以看到一些目前的分鏡稿)來顯示他們的功力。twitter也能看到一些目前進度。

成員

  • 川野達朗
    這計劃的主辦人,也是動畫師住屋補助計劃的成員之一。參與過《甲鐵城的卡巴內瑞》動作原畫師,《火影忍者博人傳》電影版原畫與《火影忍者博人傳》 OP4原畫和Story Board。學生時期亦參與製作《文子的告白》的角色設定。會特別提《文子的告白》的原因是剛好這部作品在我學生時期老師很推廣,我個人在當年寫的retas教學提到線條問題所製作的圖片其實也是描著那部動畫的其中一個cut所畫的範例。
     
  • 田中正晃
    這計劃的原畫師。曾參與《進擊的巨人》 第三季的作畫監督。
     
  • 刈谷仁美
    此計劃的原畫師。曾參與過NHK晨間劇《夏空》OP的製作。
     
  • 船隠雄貴
    此計劃的美術監督。曾參與2017年動畫電影《煙花》的美術監督。

  大概就是這樣,由於自己的英文不是說很好,我在了解這篇文章時也透過我朋友的幫忙確認才完成這篇文章。所以英文不錯的朋友如果看到有錯希望能幫忙糾正。

資助前先了解目前日本動畫業界慘況


  其實那篇文章裡還有提到為什麼他們要募資,就是因為日本動畫業界的困境:
"According to a survey conducted by the JAnicA in 2015, an average monthly salary for an animator who is in his/her 20’s around ¥90,000, making the yearly salary about ¥1,100,000. It is not uncommon that the monthly salary for a first year animator is less than 30,000 JPY.

(※) For a typical TV anime series, an animator makes ¥200 by drawing ONE picture.If one draws 300 pictures per month, his monthly salary is only: 300 drawings × ¥200 = ¥60,000.However, drawing 300 sketches is a really challenging task for a new animator.In addition, animators generally do not have time to work a part time job, which makes it even harder to make a stable living."

  而在我之前寫的一篇2D動畫成本計算也提到不少。最大的問題就是日本動畫產業對基層的動畫與原畫師都是用外包制的方式,不像我們對一般的工作認知,是一個月薪的制度。然後最主要的原因是,外包制的方式政府是無法管的,沒辦法制定一個合理價格,基本上罪魁禍首就是他以非常低的價格來決定了那些人的薪水(上面貼文是用一張200日元決定動畫師的薪水,感覺是為了方便計算,我後面一律採取P.A.WORKS提及的一張240日元),而且還很多人接受。到底有多低呢?打個比喻,在我剛提的文章我有計算,以台灣年輕人20-29歲平均月薪2萬8的狀況,台灣若有日本動畫師這產業階級,在我們的產業恐怕是只有月領9千塊的職業。這是用日本2018年20-29歲平均月薪8萬3台幣(來源:日本各行各業的平均年收和年齡分布),日本動畫師月領2萬6台幣(年薪110萬日元)與台灣2013年20-29歲平均月薪2萬8台幣(來源:台灣平均薪資收入薪水查詢歷史資料)所站的比例做的計算。

  另外,動畫師的技術恐怕也不是一般人能踏進的領域。我一直好奇一個合格的2D動畫師,他到底每個月要畫幾張?在該計劃裡有提到:
"However, drawing 300 sketches is a really challenging task for a new animator."

  還有P.A.WORKS的才文
"動畫師的工作通常都由新人擔任,而每月要畫至少350張動畫,第二年則要每月畫至少500張動畫。作畫部長吉原正行表示,如果這種能力辦不到的話,建議離職,所幸目前沒有做不到的新人,因為只要努力都做得到。順帶一提,專業的動畫師每20分鐘完成一張動畫

至於薪水,P.A.WORKS表示,TV作品的動畫單價為220至240日圓(約65至71元新台幣),此外會給研修費、餐費以及住宿費津貼,動畫師一天的目標20張動畫,實際上一天會完成15至16張,最後目標是每月500張,另外針對薪水部分,P.A.WORKS也指出,如果無法負擔生活費,就不會有動畫師的存在,而公司位於鄉下,不用擔心生活費過高。"

  雖然不清楚P.AWORKS這樣講合不合理,但我這個繪力低弱的傢伙,十年前製作自己的動畫OP我是3個月畫495張,也就是一個月165張……這也證明了自己要踏進這個領域是很困難的。雖然也可以說是我太廢啦,但是,也因為我嘗試過,所以我的經驗告訴我,製作2D動畫所需要的技術力不只需要很高的繪力,還要有強大的動態觀察力,最後則是面對一直畫不停手的忍耐力。然而,需要如此高的技術與耐力,卻只能用一張圖220-240日元去兌換。

  P.AWORK還有其他費用補貼,但我個人認為在完全外包,而非公司員工的環境下,應該不會有這樣的費用補貼。畢竟,在【閒聊】由動畫師的待遇討論日本動畫產業之現況"提到:
"根據日本文化廳的調查,一位日本的「動畫師」平均的年收為111.3萬日圓,而一天平均工作時數為11.3個小時,一個月的平均工作時間則是251.3小時;換算成時薪的話,平均每小時只有拿到370日圓"

  平均年收111.3萬日元真的比較像是一張240日元,一天完成15張,我月休八天,算工作22天好了,240*15*22*12=950400……看來純外包制要達到平均水準恐怕不能月休八天了……那改一個月工作26天,所以年薪為240*15*26*12=1123200...嗯,差不多,雖然一個月工作26天算血汗……
  
  當然,一定有人會問,那像京阿尼與吉卜力這樣的公司也是如此嗎?我查了一下資料,他們相較之前提的文章的狀況去比,真的都很佛心,他們是採取月薪制的。而且他們的技術絕對是業界頂尖。但,就算如此佛心,其實給的薪水還是很一般。

  以京阿尼來說,此篇"男女比例 3:7 的女尊男卑?京都动画员工公开工作时间与个人待遇"有提到:

"首先是京阿尼內部一位 22 歲入職未滿 3 年的女性正式員工在企業評價網站上曬出了自己的 2015 年月收入構成:

基本工資  15 萬日元

加班費:3 萬日元

交通補助:2 萬日元

除了月工資和一些補助外,京都動畫在 2015 年還提供 3 次獎金

定期獎金:70 萬日元

年終獎:10 萬日元

於是這位 22 歲的女性正式員工在京都動畫的年收入為 20 萬×12+80 萬=320 萬日元/年
這個待遇在入職未滿 3 年的動畫製作中已經是不錯了

但是對於京阿尼提供的這份待遇妹子也是有吐槽的

京阿尼內部隱性加班時間每個月 35 小時,每天固定的工作時間是 11 個小時,在京阿尼中加班也是一種常態,雖然京都動畫官網招聘說明中寫的是週休兩天,但實際進入京阿尼後每週只休息一天,每個月加班的時間總計有 100 小時(按照 25 個工作日計算平均每天加班 4 個小時)。即便是在法定節假日京都動畫的員工也會像工作日一樣來上班。

  年薪320萬日元,除以12就是大約月薪26.6萬日元。在台灣的話,用剛剛等比例的計算,大概就是一個月薪2萬6台幣並且工時十一小時週休一日的工作。嗯…其實還是蠻血汗的,但比月薪9千台幣這種外包階級來說絕對好上很多……

  而吉卜力則在"宮崎駿復出招募員工卻「被國外網友狠批缺德」!網友:「跟中國製造的iPhone一樣!」"可以看到:
"前陣子,日本動畫大師宮崎駿撤回2013年退休宣言 (又) 宣佈復出。到了5月19日,吉卜力工作室開始正式招募新長篇動畫員工,對象是動畫與背景美術人員,國籍不限但須通日文,最低月薪為20萬日元 (約5.3萬新台幣),上班時間是10點至19點,週休二日 "

  總之這徵才條件一出,宮老就被一堆老美吐嘲了。其實說實在的……雖然可能沒有京阿尼好,但還是一句客氣話…比起外包制的那些,真的好很多。


  而我在"日本動畫工作者的工作待遇差到令人窒息"找到一張圖:

圖上內容轉自——風兒有些喧囂

  雖然那篇文章是提日本動畫師平均年薪只有1百萬日元,完全和這張圖無關,這張圖明明是說攝影有簽契約的薪水,沒講是不是月薪,但上面寫的數字是16萬到18萬日元,怎麼看都覺得和年薪1百萬日元扯不上關係,所以我個人認為這是其他家月薪制的動畫公司給攝影的月薪。攝影雖然不是動畫師,他是製作中期處理串接圖層動畫影片以及特別效果處理,在製作動畫的過程也是不可缺少的一部分,所以還是可以拿來參考一下。

  所以,這樣和20-29歲平均月薪28萬日元來比,真的不能算多。

  當然,薪水不管每個月拿多少,重點是日本的最低薪資制是多少,有沒有違法?還有這樣的薪水到底能不能應付得了每個月的開銷?

  所以這邊"日本最低薪資的秘密?!想去日本工作前一定要搞懂"提供了一些資料:
"相較於台灣統一最低薪資(2019年最低時薪為150元,月薪為23,100元),日本的薪資是受到地區影響的,並沒有全國統一的標準。

目前日本時薪最高的區域為東京的985日圓,而最低時薪則是鹿兒島的761日,大概有200日圓的差距。"

  外包制如果按照之前有份資料顯示其實是時薪370日元,這百分之百違法。但外包因為無法規範,屬於「個人事業主(自僱)」的形式任用,所以並沒有受到日本勞動基準法的保障。其實想想實際的狀況,假設你是一個自己接case的SOHO族,如果你完全靠這維生,一般你接case賺來的錢通常不會開價到低於自己的生活所需,因此這不必規範,且外包一向都算是一個願打一個願挨,也沒辦法有一個準則。然後,日本外包制的SOHO動畫師是完全沒有任何討價還價的空間的,畢竟你不做,他們就丟給其他國家來(那些薪水在日本低歸低,在台灣可是基本水平)。只能說這跟民族性以及大環境的影響有關。

  然後這邊要計算月薪制的那些公司給的月薪合不合法。由於日本只規定時薪,所以這邊要把月薪全都轉成時薪。我用上面看到的最低月薪16萬日元,每天工作8小時(日法定工作時數),每週工作5天,不去計算加班費,一個月4週來算。那就16萬日元/(8*5*4)=1000日元。嗯,所以他們應該都不算違法。應該吧= =a....

  接下來是看他們一個有在外租房子的每月開銷:
單身者
伙食費       1500日圓 X 30天=45000日圓           
房屋租金           70000日圓
電、水、瓦斯費        10000日圓   
手機、網路費         13000日圓
交際費               20000日圓
娛樂、雜支          3000日圓
總計                161000日圓

  嗯……所以月薪只給16萬日元,好像真的不太夠。也難怪該文有提到25歲之前月薪平均22萬日元。這樣去比較,你就能知道外包制的,畫一張圖240日元,每個月畫300-500張,月薪7萬2-12萬日元,真的很難在日本生活……除非你是家裡有人養你。

  當然我這邊還有沒有提到的資料,那就是原畫師的薪水,一個做一段時間的動畫師如果達到某種程度是可以轉職成原畫師的,而原畫師的待遇就相對好很多。但是一部動畫裡是不可能只有原畫的,畫中割的動畫師是絕對有其必要的存在,所以這邊儘量都是講動畫師。原畫師雖然待遇較好,但其實前面【閒聊】由動畫師的待遇討論日本動畫產業之現況內文也有提到,平均月薪是282萬日元/12=23.5萬日元,雖然可以解決每個月16萬日元的開銷,但....和日本人20-29歲平均月薪28萬日元比真的算普通。
  

  不過,真的動畫師只能一張240日元嗎?我個人認為應該還是有高一點的,至少在我之前
2D動畫成本計算底下有人留言日本高標是一張100台幣,也就是差不多350日元。雖然他是被很多人譙啦,但是我確實也有在其他地方徵台灣外包的價錢看到一樣的價碼。只是說,就算提高到了一張350日元,就真的能改善到他們的環境了嗎?每天畫15張,月休若有8天,一個月就是賺350*15*22=115500日元,這樣還是只改善一點皮毛。老實說,就連這個募資提的計算是希望能給動畫師一張500日元,那這樣去計算,500*15*22=165000日元,剛好打平上面提的單身漢的月開銷…但沒人是希望自己是當月光族的……所以我是覺得那募資提的500日元算客氣了。

  當然這些錢在台灣來說都是足夠的數字,但我必須要強調這篇文章是站在日本就業的狀況,除非你有辦法在日本工作然後用在台灣開銷的方式生活。然而,就算對日本人來可能做得到,卻應該會過得很辛苦(比如都要去超商買當天快過期的特價便當)。頂多就是幸運一點是住家裡,不用負擔房租,以上面的計算來說就是16萬日元-7萬日元=9萬日元。如果你能每個月畫500張的話…這樣確實就好很多,所以我想,其實能夠繼續待下去的,除了靠愛外,可能家裡的環境也不差。


  除了外包制低薪的困境,還有就是日本的動畫收益最後落在日本動畫公司的比例是非常少的,這邊【閒聊】由動畫師的待遇討論日本動畫產業之現況"提到:
"動畫師如此低的報酬,主要是因為還要面對較低工資的大陸和韓國的競爭,各種意義上的前途多舛啊。當然,或許會有人詢問說,日本動畫明明賺很大,還年年屢創新高,但動畫師為何會那麼血尿?其實按照統計資料,2013年度所有動畫市場所賺到的錢總共是1兆4913億日圓,但其中卻只有1725億日圓進到了動畫製作公司的口袋,僅僅只有約11%的錢而已,剩下的都被製作委員會其他的廣告代理店和投資公司(出版社和電視台等)給賺走,而目前製作電視動畫,其實能夠回本已經算不錯了,尤其目前主流的深夜動畫要賺錢還是得靠BD/DVD的銷售,但面臨網路時代盜版盛行,實在是......,更不用講說日本又相當的排外,不屑賺外國人的錢,或許前陣子的盜版大掃清和中國大陸的動畫大量代理同步放送,就是一種妥協吧。"

  動畫公司收益只站11%所以要支持您喜歡的動畫請多買他們的BD和設定集。而這原因有人認為是動畫製作委員會的方式讓分配制度產生不公,例如這個"【娛樂研報】日本製作委員會模式過時了麼? ":
"福原接著談到在日本,原作者在法律上有著非常優厚的保護條款,但是動畫製作公司不是製作自己公司的原創作品,所以沒有權利。即使最後作品賣了很多錢,但是在製作委員會的模式下並不能分得這些收入假如動畫家工資一個月30萬日元(年輕的動畫製作者月薪6~7萬),給動畫相關的工作人員給予適當的工資和休息日的話,每一話要花費4000萬日元左右。但是,實際的製作經費只有1500萬日元左右。

本來製作委員會模式既不是承包動畫的全部成本,也不是一次性付錢,一旦公司(實際製作動畫的公司)在製作過程中出現虧損的情況,中間製作動畫成本都需要工作室來墊付。這樣的話,原本籌集到的錢全部用在了製作上。這樣動畫工作室不可能賺錢,當然也不能把錢給創作者。雖然有些理想化,福原表示,我想對委員會說請把作品版稅拿出來交給創作者,這樣的話,動畫工作室有充足的金錢和時間,製作一定會變得更好。"

  但也必須要說日本製作委員會的方式其實是降低投資動畫失敗的風險,所以也有"製作委員會是萬惡之源?消除你對動畫行業的誤解:由動畫製作委員會至周邊銷售、動畫製作者的行業生態 "這樣的文章在解釋有些人對製作委員會的錯誤看法:
首先是影像商品製造商或動畫製作公司等的製作人提出動畫化企劃,向周圍各間認識的公司打招呼說我們有個動畫企劃
看了這個企劃後有意向投資的公司不斷增加的話,就會有一間公司作為骨幹公司站出來說「我們來負責任籌錢」

而這個”責任”的潛在意思就是「如果募集不到目標金額資金的話由我們公司自己出錢承擔包底」

事實上也的確有這種骨幹公司籌錢失敗,結果自己出錢補足差額承擔的情況,因此基本上由影像商品製造商與電影公司擔任骨幹公司的情況較多
因為這種骨幹公司需要有充分的業內資源調動能力與資金能力作為保證,所以能當骨幹公司的企業也是有限的
網上說很多公司想要加入動畫製作委員會,這個倒是真的,對製作委員會來說終極目標就是令委員會全體利益最大化,這取決於委員會內每間公司的營運實力,有一些營運能力不足的公司就算很想加入製作委員會也會被拒絕掉
另外
對於動畫製作公司來說,就算出資進入委員會虧本的可能性也很大,所以對動畫製作公司來說反而會想「不加入製作委員會更好」,收取一筆固定的製作費後就沒有什麼煩惱

這幾年從日本媒體報導來看似乎是出錢進了動畫製作委員會企業就能賺錢,但這是一葉障目,媒體報導的都是大熱門作品,而默默無聞的作品則不被媒體關注"

  不過這個問題我感覺好像有點無解,畢竟製作一部動畫的成本之大,在希望量多,又能降低投資風險的狀況下,這樣的成本控制真的會很難拿捏。所以最後這兩者的衝突讓日本動畫產業似乎只能選擇犧牲底層員工的權益。

  但這邊也不得不佩服京阿尼,他們可以完全不使用製作委員會的方式募資,讓Netflex看上他們進而對他們進行投資。也因為他們可以找到雄厚的資金,所以才能用月薪與分紅的方式來徵才。我個人覺得他們最值得講的地方在這段"日本動畫業界觀察:京都動畫京阿尼的成功之道":
即便是在日本這個擁有上千家動畫公司的國家,能夠完全獨立製作動畫的公司仍然是一隻手能數的出來的稀有物種。所謂完全獨立製作動畫,即公司內部擁有製作動畫的所有環節,而不必把某個環節或直接把某話進行外包。在這一點上,製作了《白箱》的PA做不到,製作了《Fate/Zero》的UFO做不到,京都動畫卻做到了。所以,在觀看某些動畫的時候,經常會看到令人大跌眼鏡的質量突然下滑的“外包回”,但京都動畫的作品卻永遠保持著高超的製作水準。
不得不佩服創始人八田夫婦的眼光。上世紀八十年代,八田英明和八田陽子夫婦從手塚治蟲的蟲Production公司離職後,隨即創立了京都動畫。雖然當時隻充其量算個小手工作坊,但兩人卻確定了許多十分先進的方針。所以到九十年代,社內就已經基本具備了較為完善的製作體制。這個體制直到今天依然是京都動畫賴以生存的根本。當其他公司還在為層層外包和中介吃錢頭疼不已的時候,京都動畫早已不用為作品質量發愁。

  其實我個人認為,京阿尼這樣的體制比這個募資所希望能達到的還更是正確的方向,但很遺憾的是,現今這樣的環境恐怕無法多生出點這樣的公司……因此最近那場大火絕對是對全世界2D動畫迷一個很嚴重的傷害……

  最後再點補充,如果要了解日本2D動畫產業到底還能有多慘,我個人建議溫和點的,可以看看《白箱》;誇張點的可以看看《制作進行黑美》;想看有趣一點的,可以翻翻《Anime95.2》。

  前兩部都是虛構作品,僅供參考而已。不過老實說,如果前兩部動畫提的製作狀況有部分真實,就我個人而言,我以了解遊戲業的制作狀況,去看這些故事中業界的流程,還是會覺得很多不夠有效率的作法。例如負責管理動畫師進度的竟然是制作進行,而不是有經驗的美術主管,這點在一般公司裡都會覺得是件很沒效率的事。一來美術主管通常是最能了解底下員工的人,這樣他才能有效分配工作;二來美術主管通常都是底層上來的,所以當有動畫師有任何職場上的問題時,不管是心理還是技術層面,也總比是門外漢的制作進行有機會提供更正確的解決方向。如果有人是工程師,想想你家PM若是那種總是提出不合理要求的人,而他們還是你的主管的話,他要求的事你一定要做到,那絕對會瘋掉,因為他們根本不懂程式,有些程式上的困難點他們是不懂的。但在剛剛提的那些作品可以看到,這些管理工作,全都是由制作進行來去做。我只能說,這是因為大量外包而不得不的選擇,因為有可能成為美術主管的傢伙都有可能忙得不可開交了,根本沒時間去處理那些外包還管理他們的進度,能做到作畫監督的工作就已經很不錯了。而我剛剛的角度全都是假設所有製作成員都是公司內部員工的狀況,所以公司內部狀況不同,所做的分配當然也會不一樣,在剛剛提到的兩個作品裡,他們的公司感覺得到內部員工是非常少的,蠻大的一部分還是來自外包。

  然後,提一點我個人最有印象的事,就是開會是在凌晨這件事。《Anime95.2》的作者有提到,當他離開動畫公司到一般公司上班時,公司跟他講約兩點開會,他竟然會問是下午兩點還是凌晨兩點……(白箱你去注意,他很多開會時間真的都是晚上……)

  總之我想說的是,這個業界之黑,也難怪離職率有八九成。即便是大家都公認是業界良心的京阿尼……有工作的人都知道,那工時也算血汗,薪水也不是很高(就算不用台灣薪水等比例換算,用是否低於平均薪資大概也能看出)……只是相較其他動畫公司,真的是很佛心。

  然後真要講我上面所有計算有沒有誤導的可能,其實是有可能的,像是因為各地區的生活水平不同,所定制的基本時薪也不同,因此月銷16萬日元是否真適用也得看一下地區。

  還有我拿日本20-29歲與台灣20-29歲平均月薪的地方就是不同年份,最好的狀況應該是要拿同一年份的。加上台灣還有可能有年終獎金,我是認為那些統計資料應該不會包含。但這資料對我不是那麼好查


  
另外我拿去做比例計算的一些月薪,像京阿尼的部分,月薪26.6萬日元這是一個剛進公司未滿3年的薪水,或許20-29歲他們該公司的動畫師平均月薪會高一點。


  再加上我的日本月薪換算台灣月薪的方式其實還得考慮到他們的物價與我們的物價水準去做了解,把這些因素加進去算才會比較準確,但我不清楚這有沒有公式,算是用個人較主觀的判斷。我個人是認為可以這樣算的,因為這樣算的感覺會覺得要將他們所有看到的日元差不多除以10就是台灣的狀況。我之前去日本,買他們的東西都是除以10想成台灣要是也有這樣的商品大概是怎樣水準的價錢.。總之一些誤差還是有可能,但我自認為應該不會到太大……

 

對該募資的一些疑問


  總之,因為個人了解這個業界的殘酷,而我又是那麼喜歡日本的2D動畫,所以我個人是捐了19美,雖然不多,但算是表示了點個人的心意。其實就算剛講的一些佛心公司算血汗,但他們還是用了合理的月薪制度,用了至少能過一個月生活並稍微存點錢的薪水。我是蠻希望日本動畫產業是真的能改善的,真的覺得像這樣的公司應該是最基本的(因此京阿尼相關的募資,我個人也希望有人能多多幫忙,目前看來達標應該是沒問題,但最大的問題是他們損失了許多的人才以及面臨作品的停擺。)……但偏偏這個業界就是很難改變,這種困境我大概聽了十幾年了吧,還是沒有改善……所以看到這個募資,看到他們是想改善這個體制的,但推了應該有三四個月,卻只有這樣少少的募資量(20190719目前才1585美金,離他們的30000美金目標只佔5%),基於同情才想要介紹……說實在的,至少川野達朗參與的Boruto,我個人動畫就看了不少,雖然他只有參與電影版和OP4,但受到這些動畫的感動,我支持他多少還是有個人的理由的。

  只是說,並不是每個人都有受到這些人參與的作品的感動,所以我也必須要稍微客觀一點去描述,這邊其實我是認為還是有非常多的疑問的。

  像他提到的第一點方法是要把募來的錢都給動畫從業人員,但這些動畫從業人員是誰呢?只有這四個成員嗎?那這樣子真的算改善這個行業嗎?

   而第二點說要建立從粉絲的錢到動畫從業人員手上的制度,到底要怎麼做?如果是講用募資方法,那其實又回到第一點的問題,錢是只有到目前這四個人的手裡嗎?如果不是,又要怎麼確切地分配這些資金呢?

  第三點透過製作週邊賺的錢一樣有第一與第二點的問題。

  其實我是大概知道為什麼只能想出目前的作法,或許他們是想建立,透過比賽,選出各粉絲想要看到的作品,然後他們再製作出來。如果這樣的流程可以做很多動畫並且也能養活他們,那他們可能就可以確立了一個新的業界制度。

  但,群眾募資其實是看個人行銷手腕功力,就算你成功了,也不代表其他人能成功或下次自己再募資時一定能成功。那這樣子,是真的能幫助得到這個產業嗎?

  我覺得某種程度也是這個原因所以這個募資才會那麼少,畢竟大家真想幫助,是要幫到真正讓他們感受到困難的人,像之前的住屋補助計劃,至少有給人感覺得到有減輕負擔的感覺。不然就是他們是要買他們真正想要的商品,所以通常成功的群眾募資還會帶了點懷舊情感或市面上難以買到的成份在。

  當然,在無法改變資方的分配不均的狀況下,似乎只能想到這些助益不大的方法,老實說我也能理解。

  另外其實我之前有個疑問 ,就是為什麼這個募資平台不和住屋補助計劃一樣是在日本平台?後來才發現其實他們還是有的,就是這裡"アニメーター低賃金問題に挑む!新たなアニメ製作の仕組み構築へ。只是似乎是沒達標而失敗了,我計算了一下,應該最低會是86*5000+50*15000+9*30000+3*50000+2*100000= 1800000也就是一百八十萬日元。國外那集資網站目標是30000美金,也就是差不多三百二十萬日元。感覺還差一半啊……但都比現在的進度好很多說....我後來發現他2018租屋計劃也是有在國外募款的。有達標,只是我不太懂的是,2019租屋計劃的募資的內容和我貼的New Anime Making System Project實在感覺不太出來太大的差別,目前最明顯的前者目標是兩萬美金後者是三萬美金,還有一個感覺是租屋計劃的延續,但講的目標我感覺又差不多。不曉得是什麼原因,因為假若是一樣的目標,我覺得放在一起可能比較好?雖然可能資金若用在不同的地方分開確實比較好。我在想可能是為了要有所區格所以才這樣?

  還有就是之前明明在國內有籌到那麼多,如果那計劃是失敗的,錢是有退還嗎?假若會退還,他們更應該讓那些人再去支持才是啊,簡單來說就是也用個日文版吧。還是之前的那些人都沒來繼續支持?總是我覺得目前進度之慢實在是很怪....


2019年7月10日 星期三

[啥Web]Live2D網頁化(WebGL化)

 

Live2D WebGL資源


  這次要筆記的是Live2D網頁化的步驟。基本上這個在台灣好像沒啥人討論,中國那邊倒是有不少資源。我個人剛開始研究就是從中國的大大開放的程式碼開始研究的,連live2D官網的都稍微有下載下來開始研究。但很遺憾的是,不是我看不懂就是研究出來不是自己要的。因為中國那些大大太好心了,他們提供的方法都會導致我的live2D亂動...因為我只是希望單純執行我站立動畫,我想他動啥動作再去利用js執行。主要原因是他們多寫了和滑鼠游標有關的系統,加上我又無法把他們寫的看懂。其實後者才是原因,主要是我功力不足,我基本上連官網提供的我也看不懂....所以我曾經一度想放棄....直到我不知道為啥利用live2d-helper這關鍵字找到了kooritea這位大大寫的live2d-helper。因為他提供的範例非常完整所以才終於修改他的達到我要的,而在開始講解我如何使用之前我先列一下我當時找的所有資源:

直接看範例但要先解決跨領域讀取問題


  從剛剛提到的https://github.com/kooritea/live2d-helper 打包下載(右邊綠色的clone&download),你會看到裡面有個demo資料夾,裡面的index.html就是他的範例網頁,而因為他寫的js有寫讀取功能,因此有些瀏覽器為了安全性,會禁止在js單機模式下進行跨領域的讀取。所以有些人直接打開該index.html是看不到任何東西的。我個人是用firefox 56版(所以您可以下載攜帶版),這個版本可以看到。但現在最新的瀏覽器似乎應該都禁止了,所以要嘛就是想辦法灌類似XAMPP建立簡單的local server或找網路的免費空間(如000webhostbyehost...等)將剛剛那一大包上傳,就是有些地方要動一點手腳了。

  我想現在大多數的人應該都有Chrome,所以這邊只講Chrome。對著你的Chrome捷徑右鍵選內容,在目標後面加入以下指令" --disable-web-security --disable-gpu --user-data-dir=~/chromeTemp"(第一格記得要空格),如圖:



  然後打開dist資料夾的index.js,找到以下程式碼:
    request.onload = function(){
        switch(request.status){
        case 200:
            callback(request.response);
            break;
        default:
            console.error("Failed to load (" + request.status + ") : " + path);
            break;
        }
    }
    request.send(null);
修改成:
    request.onload = function(){
        switch(request.status){
            //modified by Nil 為了讓Chrome可以跑   
        //還要在chrome目標後面加上 --disable-web-security --disable-gpu --user-data-dir=~/chromeTemp
         case 0:
             callback(request.response);
             break;   

        case 200:
            callback(request.response);
            break;
        default:
            console.error("Failed to load (" + request.status + ") : " + path);
            break;
        }
    }
    request.send(null);

  就可以在單機的Chrome看了,不過由於這方法算是強制打開,所以記得之後要把程式碼改回來。

  他的範例可以對著人物拖動讓角色眼和滑鼠有互動,並且還有生動的音效@@",可以到這裡看DEMO


輸出模型檔

   
  接下來要做的事情是把自己在live2D裡做好的角色放入他的範例
  
  這邊請先準備好您live2D的模型與動態檔。然後由於我安裝的live 2D Editor是官方最新的3.x版,kooritea大的live2d-helper是要用到2.1的版本檔案,所以我要做的第一件事就是將參數版本降為2.1版


Modeling->Convert Model ID

視窗出現後選擇2.1並按下OK

  這時整個檔案的規格就會變成2.1版的參數。

  然後接著輸出模型檔:

File->Export For Runtime->Export as moc file (For2.1)


Expoer a model setting file(modle,json)一定要打勾


   這時會輸出材質圖檔moc檔與之後很重要會拿來編輯的json檔

 輸出動態檔


  接下來就是打開你的動態檔:
File->Export For Runtime->Export motion file

 參數勾選Export all scenes以及 底下勾選Export as 2.1-format file

   建議在剛剛輸出模型檔的地方建一個motions資料夾(大小寫注意別寫錯,因為我有遇過我的免費網路空間判斷出錯),他會將所有動態輸出mtn檔。

建立自己的模型網頁


  這時候回到在一開始下載的網頁部分。在demo資料夾下的mode資料夾裡新增一個資料夾並將剛剛輸出的檔案都丟進去

  接下來打開demo資料夾下的index.html,找到baseUrl(角色資料夾路徑)與modelUrl(model.json檔路徑),並將資料夾路徑和檔名打對。還有確認model.json檔裡的路徑與對應的.moc檔與材質texture路徑是否正確,不過你model.json檔的輸出沒做任何檔名與位置更改,基本上不必擔心這一塊就是。

  這最基本的live2D網頁化就算成功了。如果你的角色是用live2D預設模型去做的,你會看到你可以對著人物做滑鼠拖動眼睛。所以應該是他本身js有抓到一些參數所以才能讀取眼睛的部分(你可在index.js搜尋PARAM_EYE就會看到相關程式碼)。不然如果完全是自己定義的參數,人物應該不會動就是。

  若出現破圖現象,我的作法是回到editor把圖集裡有透空但被算在範圍的圖拉開,而會明明透空還被算在Texture內的原因我個人推斷是你使用最一開始的模型被你後來多次重複使用的原因。像我這模型最一開始其實不是球兒的模型,我是拿別人畫好的圖去做live2D,只是這次為了DEMO所以我用我自己畫的圖,但因為想節省時間所以就拿之前那個檔案來做,雖然其實要微調的地方也算蠻多的就是,只是動作那裡我就完全沒去調整。

理解建構格式


  在index.html裡可以知道,他透過loadLive2D(JSON格式)來去呼叫建立canvas。所以基本的呼叫格式就是先在html寫一個canvas:
       <canvas id="id_live2D_canvas">
       </canvas>

  然後js再使用以下格式呼叫:
            var live2D;   
    var live2DWidth=640;
            var
live2DHeight=1000;
            var live2DJSON=
            {
              canvasId:'id_live2D_canvas', // canvas的id
              baseUrl: './live2D/Ball', // 资源原始路径
              modelUrl: './live2D/Ball/Ball.model.json', // 自定义model.json路径 方便用于一键换装

              crossOrigin: false, // 是否允许跨域获取数据(前提是http header中已有允许的跨域字段) def:false
              interval: 1, // 自动mation的开始时间点到下一个mation的开始点之间的间隔
              idle: 'idle', // 自动触发的mation
              width: live2DWidth, // html上的width属性优先级更高
              height: live2DHeight,// html上的height属性优先级更高

              globalollowPointer: false, // 全局跟随鼠标 def:false
              scaling: false, // 是否允许使用滚轮放大缩小 def:false
              debug:
              {
                DEBUG_LOG: false,
                DEBUG_MOUSE_LOG : false,
              },
              layout: { // 布局设置 这个优先级最高,然后到model.json(字段正确的话),再到默认
                width: '',
                height: '',
                x: '',
                y: '',
                center_x: '',
                center_y: '',
                top: '',
                bottom: '',
                left: '',
                right: ''
              },
              view: {
                VIEW_MAX_SCALE: 2, // 最大缩放比例
                VIEW_MIN_SCALE: 0.8, // 最小缩放比例
                VIEW_LOGICAL_LEFT: -1,
                VIEW_LOGICAL_RIGHT: 1,
                VIEW_LOGICAL_MAX_LEFT: -2,
                VIEW_LOGICAL_MAX_RIGHT: 2,
                VIEW_LOGICAL_MAX_BOTTOM: -2,
                VIEW_LOGICAL_MAX_TOP: 2
              },
              autoLoadAudio:function()
              {
                //console.log('audio loaded');
              }, // 自动下载音频 def:true
              initModelCallback(waifu)
              {
                //console.log(waifu);
                //console.log('加载完毕');
              }
            };

            live2D=loadLive2d(live2DJSON);

  比較要注意的是畫紅字的地方,除了名字與路徑要打對,初始化的寬度與高度那裡建議用兩個變數去記憶,因為之後會用到。剩下的參數就大家自行設定看看我比較沒有研究就是。

製作DEMO,修改js


  而接下來,要做的是接近我的demo的部分。我要做的內容是一個角色動態控制器,點選按鈕就表現什麼樣的動態。也因此我會把他的程式碼改很大,接下來的部分就需要一些基本的html與js語法概念了,如果文章看到這,您因為不會網頁技術,您其實可以跳到後面我有提到怎麼修改我寫的demo檔。由於我不需要他的拖曳功能,所以我就把他index.js(在我的打包檔有將此檔改名,是放在js/live2d的live2d-helper.js)裡把modelTurnHead這function下的obj.drag = true改為false,並把obj.dragMgr.setPoint(vx,vy)這段程式給註解掉。這樣他的拖曳功能就沒有了。

  然後,要注意的是,如果你更改了canvas的大小,建議modelTurnHead該函式下取的x與y坐標位置也要更改。因為他有提供點擊身體部位做出反應的方法(這個之後會提),因此若這邊沒修改,你更改了canvas的大小他的sx,sy,vx,vy變數會改變,在判斷實際位置會抓錯。而修改方式就是將你縮放的比例用一個變數記住,我是在js開頭就宣告一個叫changeScale=1的變數,他是我之後會提的製作RWD的縮放比例,在他相關的sx,sy與vx,vy變數去除以changeScale來還原我們原本模型正確的位置坐標,也因此modelTurnHead這funtcion下的程式碼我改成這樣:
    obj.drag = false;//20181122 modified by Nil 不要讓角色可拖曳

    var rect = event.target.getBoundingClientRect();

    var sx = transformScreenX(obj,(event.clientX - rect.left)/changeScale);//20181122 modified by Nil 因為rwd進行縮放時會更改他的判斷位置,要還原原本沒被改的大小位置
    var sy = transformScreenY(obj,(event.clientY - rect.top)/changeScale);//20181122 modified by Nil 因為rwd進行縮放時會更改他的判斷位置,要還原原本沒被改的大小位置

    var vx = transformViewX(obj,(event.clientX - rect.left)/changeScale);//20181122 modified by Nil 因為rwd進行縮放時會更改他的判斷位置,要還原原本沒被改的大小位置
    var vy = transformViewY(obj,(event.clientY - rect.top)/changeScale);//20181122 modified by Nil 因為rwd進行縮放時會更改他的判斷位置,要還原原本沒被改的大小位置
    if (obj.debug.DEBUG_MOUSE_LOG)
        console.log("onMouseDown device( x:" + event.clientX + " y:" + event.clientY + " ) view( x:" + vx + " y:" + vy + ")");

    obj.lastMouseX = sx;
    obj.lastMouseY = sy;
    //console.log(changeScale);
    //obj.dragMgr.setPoint(vx, vy);//20181122 modified by Nil 為了不要讓他拖曳亂動

  因為我的模型是預設模型,所以他會自動眨眼,我這邊將thisRef.eyeBlink = new L2DEyeBlink();這段段程式碼註解掉。

  所以如果還可能有其他衝突,可能就要搜尋"PARAM_"開頭的字樣去尋找哪些動作讓他啟動了。

  最後由於這個程式有鎖右鍵,這讓我每次想檢查元素很不方便,所以我也將obj.canvas.addEventListener("contextmenu", mouseEvent, false);那段程式碼註解掉了

製作等比例縮放


  這邊因為為了要讓角色等比例縮放,所以我個人採用了Adobe Animate他HTML5 RWD輸出的方式去做修改,在自己的index.html寫了以下程式:
            var live2DCanvas = document.getElementById("id_live2D_canvas");
            var canvasSizeModified=1.15;
            function makeResponsive()
            {   
 
                window.addEventListener('resize', resizeCanvas);       
                resizeCanvas();    
                function resizeCanvas()
                {          
                    var w = live2DWidth, h = live2DHeight;           
                 
                    var ih=$(window).height();//這邊是依照高度做等比例縮放
                    var pRatio = window.devicePixelRatio || 1, yRatio=ih/h,sRatio=1;         

                    if(h>ih)
                    {              
                        sRatio = yRatio;            
                    }
                             
                    live2DCanvas.width = w*pRatio*sRatio*canvasSizeModified;        
                    live2DCanvas.height = h*pRatio*sRatio*canvasSizeModified;
                    live2DCanvas.style.width =  w*sRatio*canvasSizeModified+'px';              
                    live2DCanvas.style.height = h*sRatio*canvasSizeModified+'px';
                    changeScale=sRatio*canvasSizeModified;//為了live2D點擊位置判斷用
                }
            }
            makeResponsive(); 

  而我是依照整個網頁的高度做等比例縮放,這邊若其他人並非像我是這種一頁式的,可能需要去針對ih這變數去做修改,比如讓ih等於某個物件的高度做等比例縮放。

  要注意裡面有個changeScale,這邊這個變數就是前面我提的,在我的live2d-helper.js的變數,他是用來判斷還原正確的身體部位位置用的。

修改model.json檔


  如果你對前面輸出靜態model時有印象,會有個檔名.model.json的檔案,這個檔案如果你有去觀察他的範例檔,會發現裡面寫了很多東西,他其實包含了點擊部位以及可讓js控制執行的動作檔、該動作檔的fadein與fadeout時間和可發出的音效

  其實這個檔案能做的東西不只我上面提的就是,而我個人除了音效外只研究到剛剛提的部分,所以我提供的打包檔其實沒有用到音效,但我會稍微提一下。

  我基本上就是新增點擊部位名稱與id,這些我一律全都是live2D裡的部位id,如胸部我就叫body_chest,如圖示:

  再來就是新增動態與檔案關聯性,fadeIn與fadeOut時間(單位毫秒)。

  最後這邊提的loop,要給定true或false,為了要讓該角色動作是否要保持循環(例如說話就需要)。這是我個人自己寫的,所以之後會提到還得修改live2d-helper.js檔。

  所以完整的基本json檔如以下格式:
{
    "type": "Live2D Model Setting",
    "name": "Ball",
    "model": "Ball.moc",
    "textures": [
        "Ball.2048/texture_00.png"
    ],

        "hit_areas":
        [
            {"name":"body_chest", "id":"body_chest"},
            {"name":"leg_right", "id":"leg_right"},
            {"name":"leg_left", "id":"leg_left"},
            {"name":"face_base", "id":"face_base"},
            {"name":"body", "id":"body"},
            {"name":"arm_left_up", "id":"arm_left_up"},
            {"name":"arm_left_down", "id":"arm_left_down"}
           
        ],
        "motions":
        {
            "idle":
            [
                {
                    "file":"motions/Ball_1_front_happy_stand_0.mtn",
                    "fade_in":1000,
                    "fade_out":1000,
                    "loop":true
                }
            ],
            "Ball_1_front_unhappy_stand":
            [
                {
                    "file":"motions/Ball_1_front_unhappy_stand_0.mtn",
                    "fade_in":100,
                    "fade_out":100,
                    "sound":"sound/D_Sak_Live2D001.wav",
                    "sound_delay":-1,

                    "loop":true
                },
                {
                    "file":"motions/Ball_1_front_unhappy_stand_1.mtn",
                    "fade_in":100,
                    "fade_out":100,
                    "loop":true
                }
            ]
        }
}

  而要注意的是,他這程式裡把idle預設為站立動態檔,所以這是基本一定要寫入的。另外上面的sound在我的球兒demo檔不會有,但卻可以從kooritea大大的範例檔找到是如何播放音效的。

修改loop


  接下來為了讓前面提的loop能實現,要打開live2d-helper.js修改。

  首先你找到function LAppModel(obj)這個函式,會發現他底下有寫一個timer,那個就是他寫的為將動作做完切回idel這動作用的。我改寫的就是那個地方。

  先在js最上頭新增兩個變數名稱,一個是nowMotionName="idle"一個是nowMotionIndex=0。這是為了要記憶每次動作如果是loop,他在做完該動作後去持續執行用的。所以你會看到我將timer改寫成以下內容:
function LAppModel(obj)
{
    //L2DBaseModel.apply(this, arguments);
    L2DBaseModel.prototype.constructor.call(this);

    this.modelHomeDir = "";
    this.modelSetting = null;
    this.tmpMatrix = [];
    this.obj = obj;
    // this.timmer = setInterval(() => {
    //   if (this.mainMotionManager.isFinished())
    //   {
    //    this.startRandomMotion(this.obj.idle, 1);
      
    //   }
    // },this.obj.interval)
    //modified by Nil 20190706 為了不讓他會自動切回站立動作

    //modified by Nil 20190706 為了加入判斷loop動作
    this.timmer = setInterval(() =>
    {
      if (this.mainMotionManager.isFinished())
      {

           if(this.modelSetting.json.motions!=undefined)
           {
              
               if(this.modelSetting.json["motions"][nowMotionName][nowMotionIndex]["loop"])//如果該動作是循環則繼續
               {
                  
                   this.startMotion(nowMotionName,nowMotionIndex, 3);
               }
               else
               {
                   this.startMotion("idle",0, 3);//沒有loop就切回idle
               }

           }
      }

    },this.obj.interval)

}

  這邊大概提一下流程就是他透過this.mainMotionManager.isFinished()判斷目前動作有無結束,如果動作結束,我再透過this.modelSetting.json["motions"][nowMotionName][nowMotionIndex]["loop"]讀取前面提到的model.json判斷這動作是否循環,如果是循環則透過startMotion繼續執行,不是就回去idle站立動畫。這邊提一下他這程式有兩個方法可以啟動動作,一個是startMotion另一個是startRandomMotion,如果你有注意,在動作種類底下的動作檔是可以放一個以上的,所以我才稱第一個要放的參數名字是叫動作種類,第二個參數就是該動作種類第幾個要播放,第三個參數是優先權,分為1、2、3,我基本上都放3強制執行。因此startRandomMotion的意思就是從該動作種類隨機挑選一個執行,所以他第二個參數不必放要播第幾個,他要放的是優先權。

  最後要去LAppModel.prototype.startMotion = function(name, no, priority, hitArea, callback)
{記住每次執行動作的動作種類名稱(nowMotionName)和動作位置(nowMotionIndex)
。程式碼如下:

LAppModel.prototype.startMotion = function(name, no, priority, hitArea, callback)
{
    // console.log("startMotion : " + name + " " + no + " " + priority);
    var motionName = this.modelSetting.getMotionFile(name, no);
    nowMotionName=name;//modified by Nil 20190706 取得目前動作名稱用
    nowMotionIndex=no;//modified by Nil 20190706 取得目前動作名稱index用


//(略)
}

 

新增點擊部位反應


  前面有提到過,他的modle.json裡有對應live2D裡的身體部位id,也就是hit_areas部份。而你要針對比如點擊身體他會有什麼樣的反應你要在一開始index.html的建置初始呼叫的json格式要修改,需要新增binding,並在底下放入對應的name與函式,總之格式如下:
            var live2DJSON=
            {
              canvasId:'id_live2D_canvas', // canvas的id
              baseUrl: './live2D/Ball', // 资源原始路径
              modelUrl: './live2D/Ball/Ball.model.json', // 自定义model.json路径 方便用于一键换装
              crossOrigin: false, // 是否允许跨域获取数据(前提是http header中已有允许的跨域字段) def:false
              interval: 1, // 自动mation的开始时间点到下一个mation的开始点之间的间隔
              idle: 'idle', // 自动触发的mation
              width: live2DWidth, // html上的width属性优先级更高
              height: live2DHeight,// html上的height属性优先级更高
              globalollowPointer: false, // 全局跟随鼠标 def:false
              scaling: false, // 是否允许使用滚轮放大缩小 def:false
              debug:
              {
                DEBUG_LOG: false,
                DEBUG_MOUSE_LOG : false,
              },
              layout: { // 布局设置 这个优先级最高,然后到model.json(字段正确的话),再到默认
                width: '',
                height: '',
                x: '',
                y: '',
                center_x: '',
                center_y: '',
                top: '',
                bottom: '',
                left: '',
                right: ''
              },
              view: {
                VIEW_MAX_SCALE: 2, // 最大缩放比例
                VIEW_MIN_SCALE: 0.8, // 最小缩放比例
                VIEW_LOGICAL_LEFT: -1,
                VIEW_LOGICAL_RIGHT: 1,
                VIEW_LOGICAL_MAX_LEFT: -2,
                VIEW_LOGICAL_MAX_RIGHT: 2,
                VIEW_LOGICAL_MAX_BOTTOM: -2,
                VIEW_LOGICAL_MAX_TOP: 2
              },
              binding:
              { // 需要自行根据不同模型的model.json将mation绑定到对应的hit_areas 支持hit_areas_custom

                body: function()
                {//點身體

                  live2D.startMotion("Ball_1_front_unhappy_shakeHead",0, 3);
                },
                body_chest: function()
                {//點胸部
                  //console.log(this);
                 live2D.startMotion("Ball_1_front_unhappy_roar",0, 3);
                 
                }
              },

              autoLoadAudio:function()
              {
                //console.log('audio loaded');
              }, // 自动下载音频 def:true
              initModelCallback(waifu)
              {
                //console.log(waifu);
                //console.log('加载完毕');

              }
            };

  而若有看我打包的檔案,我是點擊什麼部位就做出什麼樣的反應,所以我執行的是live2D.startMotion("Ball_1_front_unhappy_shakeHead",0, 3);

  如果還記得前面提的startMotion與startRandomMotion。這邊由於是外部的呼叫,所以要利用之前記憶呼叫建置的變數live2D.startMotion與live2D.startRandomMotion。我demo的按鈕都是在執行該功能而已。
 

讀取中動畫


  其實live2D網頁化放在網路上的讀取的速度有時候會很慢,所以以在使用感觀上我覺得要加讀取中的動畫,只要在前面提到的初始json格式新加一個initModelCallback函式在該函式裡把讀取中的小動畫隱藏就可以,如以下格式:
            var live2DJSON=
            {
              canvasId:'id_live2D_canvas', // canvas的id
              baseUrl: './live2D/Ball', // 资源原始路径
              modelUrl: './live2D/Ball/Ball.model.json', // 自定义model.json路径 方便用于一键换装
              crossOrigin: false, // 是否允许跨域获取数据(前提是http header中已有允许的跨域字段) def:false
              interval: 1, // 自动mation的开始时间点到下一个mation的开始点之间的间隔
              idle: 'idle', // 自动触发的mation
              width: live2DWidth, // html上的width属性优先级更高
              height: live2DHeight,// html上的height属性优先级更高
              globalollowPointer: false, // 全局跟随鼠标 def:false
              scaling: false, // 是否允许使用滚轮放大缩小 def:false
              debug:
              {
                DEBUG_LOG: false,
                DEBUG_MOUSE_LOG : false,
              },
              layout: { // 布局设置 这个优先级最高,然后到model.json(字段正确的话),再到默认
                width: '',
                height: '',
                x: '',
                y: '',
                center_x: '',
                center_y: '',
                top: '',
                bottom: '',
                left: '',
                right: ''
              },
              view: {
                VIEW_MAX_SCALE: 2, // 最大缩放比例
                VIEW_MIN_SCALE: 0.8, // 最小缩放比例
                VIEW_LOGICAL_LEFT: -1,
                VIEW_LOGICAL_RIGHT: 1,
                VIEW_LOGICAL_MAX_LEFT: -2,
                VIEW_LOGICAL_MAX_RIGHT: 2,
                VIEW_LOGICAL_MAX_BOTTOM: -2,
                VIEW_LOGICAL_MAX_TOP: 2
              },
              binding:
              { // 需要自行根据不同模型的model.json将mation绑定到对应的hit_areas 支持hit_areas_custom

                body: function()
                {

                  live2D.startMotion("Ball_1_front_unhappy_shakeHead",0, 3);
                },
                body_chest: function()
                {
                  //console.log(this);
                 live2D.startMotion("Ball_1_front_unhappy_roar",0, 3);
                 
                }
              },
              autoLoadAudio:function()
              {
                //console.log('audio loaded');
              }, // 自动下载音频 def:true
              initModelCallback(waifu)
              {
                //console.log(waifu);
                //console.log('加载完毕');
                isModleFinish=true;
                live2DProgress=1;//確定讀完
                $("#id_loading_img").hide();//將讀取動畫隱藏
              }

            };

  那個 initModelCallback函式裡的程式就代表他建置完成會做的動作。

  這邊如果有注意我還寫了個live2DProgress,其實是我之前勉強算是有研究出來,他的讀取進度。但目前只研究到初始時的進度,換裝時的進度我無法讀取。詳細作法可以去live2d-helper.js搜尋"modified"找進度讀取相關的註解。其實原理就是我得知他在function draw(obj)裡會去嘗試讀取五個地方,而我就是在那五個地方確定有讀取到時就判斷會獲得一個進度點,也因此獲得五個進度點就代表完成。這也意味著每完成一個是完成20%的意思。所以你可以透過自己寫一個timer去判斷目前進度多少%。但這個要搭配在index.html裡的 initModelCallback函式就是,所以其實蠻容易混亂的。


換模型


  基本上換模型就是把前面用來記憶初始json的變數,修改json檔後再重新利用loadLive2D重新呼叫就是。只是我的demo檔我加了一些fadeIn與fadeOut效果。本來是有加入jquery ui有很炫的切換。但因為我canvas的置中方式是絕對路徑加上transform。好像用到transform時jquery UI都會在位置上出問題,所以我就放棄了。

  總之當你要換裝時,可以寫以下程式碼:
           var cheatToogle=false;
            function change()
            {
                      $("#id_loading_img").fadeIn();
                      $( "#id_live2D_canvas" ).fadeOut("slow",function()
                      {
                         if(cheatToogle)
                         {
                           cheatToogle=false;
                           live2DJSON.baseUrl="./live2D/Ball";       
                           live2DJSON.modelUrl="./live2D/Ball/Ball.model.json";

                          
                         }
                         else
                         {
                           cheatToogle=true;
                           live2DJSON.baseUrl="./live2D/Ball_comic";       
                           live2DJSON.modelUrl="./live2D/Ball_comic/Ball.model.json";

                          }
                         var tmpFunc=function()
                         {
                          $("#id_live2D_canvas").fadeIn();
                          $("#id_loading_img").fadeOut();
                         }
                        live2DJSON.initModelCallback=tmpFunc;
                         live2D=loadLive2d(live2DJSON);

                       });
            }

  這邊要提一個我發生的問題,就是換模型後,有些電腦裡我點胸部的功能就消失了,但有些電腦又ok,且這功能我在之前寫的其他網頁時完全沒這問題,所以我就不清楚到底是哪個環結出錯了就是。但也只有點胸部功能失常,其他都好好的就是。

若您不會寫網頁..


  其實我寫這個筆記有個初衷是希望不會寫網頁的live2D人也能分享他的作品,但現在想想,感覺還是有點複雜。最基本的是你將你的檔案覆蓋我輸出的所有live2D檔(但要記得modle.json檔下面打的那一大串要記得保留)。當然你若是想用自己的動作檔名,你可以更改我的檔案,在index.html裡找到:
<img class="img-fluid center-block myBtn btnLive2D"  src="images/style0/btn4-1.png?v=1.0.6" title="眨眼1" id="id_btn_Ball_1_front_happy_blink_0">

  你會發現我有很明顯的規則變化,id_btn_後接著就是動態檔mtn的名字,你直接用我的demo頁改了之後並在modle.json的motion新增你的動作類別和第1個以上的動作檔位置指定,應該就可以變成你要的動作(但要記得第一個動作一定要在"_"後寫0)。至於換圖我想你去images找到相對應圖檔去換應該就可以了。不過我要說我因為是demo用,所以我這網頁寫得還不夠好,沒考慮到平板看的樣子,他的介面會拉長以及按鈕位置會跑掉。


最後補充


  •  
    關於DEMO頁面的角色是我的創作《甘姆》中未來希望會登場的角色-球兒,該demo頁右下角問號按鈕可連至其FB相片說明頁,左下角的C按鈕可以變成黑白漫畫版本。然後如果有注意到黑白漫畫版本的胸部比較詭異,這是因為這個live2D的模板原本不是為了球兒設計的,在製作的過程中調整正面時他變形得很嚴重,我花了很大的力氣才調成現在這樣= ="...至於彩色版為何沒變形,是因為我後來花力氣把一些參數通通都調掉,不讓他轉正面是45度角側面。省了再調整的力氣....至於為啥不把黑白的拿來套再輸出...我其實不太確定還有沒有機會再有地方變形...就懶得做了Orz...
     
  • 其實我覺得這很少人研究也可能跟效能有點差有關,但我實在不知道該怎麼優化,我頂多是做到把輸出的圖片拿去壓縮,剩下就完全沒有頭緒了。不然就是要研究一下3版的phina.js,但這部分我已經很累了,就懶了。只能說希望官方能開發出更有效率也更好使用的工具了。
     
  • 有些地方還可以再優化,比如如果要做兩個模型同時在場上我前面有些寫法會出問題,例如等比例縮放那邊。
     
  • 希望能看到更多的live2D分享,老實說我覺得目前很多遊戲做的動態都太愛亂動了,我個人比較理想的站立動畫應該單純動上半身做呼吸動作就好。當然不做呼吸,只是做單純臉部動作以及偶而一個大動作可能更好,我沒採取的原因是因為原本球兒的動作不是為了我demo做的,所以在製作上還是要符合一下交代……總之雖然自己做的也很普通,但就是希望能看到更多的動態其實是自然的並且有2D動畫質感的。簡單來說,以碧藍幻想這部卡通材質的3D遊戲為例(因為實在找不到我覺得OK的Live2D動畫...很多遊戲都用他來讓站立動畫是亂動的…):

    大約39秒處開始

    他在裡面的站立動畫只有做呼吸,除非是要做比較特別的動作才會有誇張的擺動,但那些擺動都很自然,不是為動而動。  
    而特別擺動畫live2D動畫中我是有注意到一款遊戲做的蠻有2D動畫質感的,是台灣做的天使帝國幻獸之月,如這個:


    雖然一開始有些地方動得還是有點電腦感,但他後面拿劍那邊的動畫真的做得很不錯,很有2D動畫質感。其實我還看過更厲害的,是穿著泳裝拿水槍的希蜜,但youtube找不到,我勉強只找到下面這個影片:

    請直接拉到11:34

    我看到的是有發射水槍的,但很遺憾她沒呈現到希蜜發射水槍的動態就關掉直播了,其實從他搭配一個角色的活潑質感,多少能感受得到他站立動態算做得不錯。雖然我前面說理想上的站立動畫應該只要做呼吸就好,可是如果是為了符合情境,有些角色確實動態上會活潑一點。只是我還是覺得有稍微一丁點不自然感,但水槍發射那動態是真的做得很好,我當時看到的檔案其實算是不能公開的檔案,所以就沒辦法讓大家看。我個人是還蠻希望能用live2D做動態時能達到和我們在看的2D動畫一樣的質感就是。主要是live2D可以和遊戲做很好的結合,他在輸出動畫會比在遊戲引擎裡重新再編排動作來得有效率。所以如果可以在這裡做到和動畫一樣質感的動作,在遊戲中就也能都看得到,我還蠻希望自己能做到或看到有人做到就是。