Amazon EC2を使って、3Dレンダリングをしてみたメモ
米国東部ヴァージニアリージョンにEC2コンピュータクラスタを作成
プレイスメントグループにインスタンス(マスター・スレーブ)を作成
- AMIにWindows Server 2008 R2を選択
- Administratorパスワードを取得
- リモートデスクトップ接続する
- ファイアウォールの設定で、ポート8000(blenderの通信ポート)を開放する
- blenderをインストールする(NetworkRenderアドインを設定しておくこと)
blenderで処理
- マスター用サーバーでblenderを起動し、マスターの開始ボタンを押す
- マスター用サーバーのIPアドレス(プライベートアドレス)を確認する
- スレーブ用サーバーでblenderを起動し、マスター用サーバーのアドレスを設定し、スレーブの開始ボタンを押す
- クライアント用サーバーでblenderを起動し、処理するファイルを開いた後、マスター用サーバーのアドレスを設定する
- クライアントの「Send job」ボタンを押す
- サーバーモニターでFinishedになったら「Get Animation」ボタンを押す
- レンダリング結果は、クライアントで設定したPathに格納される
注意事項
bake処理はコア数が増えても並列処理できないので、マイクロインスタンスで十分。
クラスタコンピュートの場合(Twitterから転載)
↓
約30sec/1フレーム。
30fpsで5minの動画だと9000枚必要なので、9000*0.5minで4500min=75h。
75h*$3=$225。
$240/$3=80台を並列に並べれば約1hでレンダリング完了。
逆に1台でがんばっても、レンダリング時間がのびるだけで$225かかる。
ただし、ネットワーク転送に時間がかかる+分散処理に限界があるのでは?(未検証)
GPUインスタンスの場合(Twitterから転載)
↓
13.94sec/1フレーム。
0.25min*9,000フレーム=2,250min、2,250min/60min≒38h、38h*$2.6=$98.8。
スポットインスタンスなら38h*$1=$38。
ただし、ネットワーク転送に時間がかかる+インスタンス起動数に上限があるので注意。
結論
何度かベンチしてみたところ、AWSだと、どの方法でもだいたい$8/500フレーム程度が限界。
ユーロ建てだと高くつく、または、自前でサーバーを構築しないといけない場合は、GPUインスタンスのオンデマンド*1(マスター用)と、GPUインスタンスのスポット*n(スレーブ用)で処理する。
一般的なレンダリング処理だけなら、レンダーファーム(RenderFlowだと5ユーロ/500フレーム)を利用する。
Unityのtoon shaderでalpha抜き
Shader "Custom/NewShader 2" {
Properties {
_Color ("Main Color", Color) = (0.5,0.5,0.5,1)
_MainTex ("Base (RGB)", 2D) = "white" {}
_Ramp ("Toon Ramp (RGB)", 2D) = "gray" {}
}
SubShader {
Tags {"Queue"="Transparent" "RenderType"="Transparent"}
Blend SrcAlpha OneMinusSrcAlpha
LOD 200
CGPROGRAM
#pragma surface surf ToonRamp
sampler2D _Ramp;
// custom lighting function that uses a texture ramp based
// on angle between light direction and normal
#pragma lighting ToonRamp exclude_path:prepass
inline half4 LightingToonRamp (SurfaceOutput s, half3 lightDir, half atten)
{
#ifndef USING_DIRECTIONAL_LIGHT
lightDir = normalize(lightDir);
#endif
half d = dot (s.Normal, lightDir)*0.5 + 0.5;
half3 ramp = tex2D (_Ramp, float2(d,d)).rgb;
half4 c;
c.rgb = s.Albedo * _LightColor0.rgb * ramp * (atten * 2);
c.a = s.Alpha;
return c;
}
sampler2D _MainTex;
float4 _Color;
struct Input {
float2 uv_MainTex : TEXCOORD0;
};
void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
Fallback "Diffuse"
}
railsアプリ開発(もっと読む改善)
Ajaxでinsert,deleteすると、kaminariでは取得開始がずれます。
うまく回避する方法がわからなかったので、sessionを使って「もっと読む」を実装してみました。
index.html.erb
<% if @count_memos == 0 %>
<span>もうありません</span>
<% else %>
<%= link_to 'more', load_more_path , :remote => true, :id => "load_more_link" %>
<% end %>
index.js.erb
$('#posts').append("<%= escape_javascript(render :partial => @memos)%>");
<% if @count_memos == 0 %>
$('#load_more_link').hide();
<% end %>
memos_controller.rb
def showlist
# ユーザーのmemoを取得
@memos = Memo.where("user_id =? and id < ?", current_user.id,last_memo.id).order('id desc').limit(5)
# sessionに保存
session[:last_memo_id] = @memos.last.id
# 最終ページであるかの判断
@count_memos = Memo.count(:conditions => ["user_id =? and id < ?", current_user.id,@memos.last.id])
# 画面表示
render 'contents/index.js.erb'
end
application_controller.erb
# 読み込み最終行設定
helper_method ::last_memo
private
def last_memo
@last_memo ||= Memo.find(session[:last_memo_id]) if session[:last_memo_id]
end
railsアプリ開発(もっと読む)
kaminariで「もっと読む」を実装してみた。
Ajaxで書き換えた部分についてはhelperが効かないようなので、js.erbで最終ページか否かを判断しました。
index.html.erb
<div id="posts">
<%= render @memos %>
</div>
<%= link_to_next_page @memos, 'more', :remote => true, :id => "load_more_link" %>
index.js.erb
$('#posts').append("<%= escape_javascript(render :partial => @memos)%>");
<% if @memos.last_page? %>
$('#load_more_link').hide();
<% else %>
$('#load_more_link').replaceWith("<%= escape_javascript(link_to_next_page @memos, 'more', :remote => true, :id => 'load_more_link' )%>");
<% end %>
railsアプリ開発(application.css)
requireの順番
bootstrap_responsiveは、最後に読み込む
以下のコードで読み込み順番を指定する
*= require bootstrap.min
*= require_self
*= require default
*= require bootstrap-responsive.min
*= require_tree .
railsアプリ開発(paperclip)
imagemagickインストール
# yum install ImageMagick ImageMagick-devel
CentOS6系なのでyum、最新を使用する場合はソースからコンパイル
paperclipインストール
# vi Gemfile
gem "paperclip", "~> 3.0"
# vi config/enviroments/development.rb
Paperclip.options[:command_path] = "/usr/bin/"
model更新
attr_accessible :avatar
has_attached_file :avatar, :styles => { :thumb => "50x50>" }
migration追加
class AddAvatarToUsers < ActiveRecord::Migration
def self.up
add_attachment :users, :avatar
end
def self.down
remove_attachment :users, :avatar
end
end
URLからアップロード
require 'open-uri'
user.avatar = open(auth["info"]["image"])
アップロード時のファイル名指定
before_post_process :transliterate_file_name
def transliterate_file_name
extension = 'jpg'
filename = self.nickname
self.avatar.instance_write(:file_name, "#{filename}.#{extension}")
end
メモ
has_attached_file :avatar,
:path => ":rails_root/public/system/:attachment/:id/:style/:filename",
:url => "/system/:attachment/:id/:style/:filename"