2013年02月02日

WebGL で作ったモデルを Collada で書き出す

現在名前をSCOLLAGENと変え、GitHubに移行しました。
https://github.com/yamule/SCOLLAGEN


WebGL で作ったポリゴンを Collada に書き出す Javascript を書きました。
Download
元々 Java で書いていたのを Javascript に無理矢理移植したので間違いがあるかもしれません。
ごめんなさいやっぱり無理矢理移植したのでバグがありました。
(2013/Feb/02 Geometry に transform の情報が入っていないバグを修正しました。)

バグ等がありましたら twitter とかで教えて下さい。

例えばこんなこと
http://yamabukisoftworks.rash.jp/scolagen/index.html
ができます。(要 WebGL 対応ブラウザ)
GPLv3 です。

SCOLAGEN.generateFromHash というメソッドにハッシュの配列を渡して下さい。
ハッシュは

hash ={
vertex:[],//全ての点の位置を x,y,z,x,y,z,x,y... という形に展開した一次元配列
vcount:[],//いくつの点で面を作るか示す一次元配列。通常4か3
vindex:[],//面を作るのにどの点を使うか示す一次元配列
color:[]// r,g,b の形で色を示す一次元配列
}

という構成にしてください。
細かい操作はできませんが、GPL なので自由に改変してください。
あとはソースを読んで慮って下さい(ヽ´ω`)

three.js の Scene 以下にオブジェクトをぶち込んでいる場合は


function makeCollada(){
var ar = scene.__objects;
var glen = ar.length;
var geoms = new Array();
//console.log(ar.length);
for(var i = 0;i < glen;i++){
if(ar[i].geometry != null){
if(ar[i].visible == false){
continue;
}
var geo = ar[i].geometry;
//console.log(geo.vertices.length);
var varray = new Array();
var farray = new Array();
var fnumarray = new Array();
var vlen = geo.vertices.length;
var roundnum = 10000000;
for(var j = 0;j < vlen;j++){
varray.push(Math.round(geo.vertices[j].x*roundnum)/roundnum);
varray.push(Math.round(geo.vertices[j].y*roundnum)/roundnum);
varray.push(Math.round(geo.vertices[j].z*roundnum)/roundnum);
}
var flen = geo.faces.length;
for(var j = 0;j < flen;j++){
farray.push(geo.faces[j].a);
farray.push(geo.faces[j].b);
farray.push(geo.faces[j].c);
if(geo.faces[j].d == null){
fnumarray.push(3);
}else{
farray.push(geo.faces[j].d);
fnumarray.push(4);
}
}
var mtcolor = new Array(255,0,0);

if(ar[i].material != null){
if(ar[i].material.color != null){
var r = Math.min(Math.floor(ar[i].material.color.r*256),255);
var g = Math.min(Math.floor(ar[i].material.color.g*256),255);
var b = Math.min(Math.floor(ar[i].material.color.b*256),255);
mtcolor[0] = r;
mtcolor[1] = g;
mtcolor[2] = b;
}
}
var ha ={
vertex:varray,
vindex:farray,
vcount:fnumarray,
color:mtcolor

};
geoms.push(ha);
}
}
var dlc = document.getElementById("dldiv");
if(dlc.childNodes.length > 0){
dlc.removeChild(dlc.childNodes[0]);
}
dlc.appendChild(makeDLLink(SCOLAGEN.generateFromHash(geoms)));
};


function makeDLLink(dat) {
var c = (window.URL || window.webkitURL).createObjectURL(new Blob([dat]))
var ret = document.createElement("a");
ret.setAttribute("href", c);
ret.innerHTML = "Download";
return ret;
};

こんな感じで id="dldiv" とした要素の子に Collada ファイルのダウンロードリンクができると思います。
まあ three.js には Blender で読み込めるようにする機能があるので必要ないっちゃ必要ありません。。。


posted by k_yama at 07:28 | Comment(0) | 備忘録

2012年11月18日

Java で行列演算

いろいろ必要になったのでがーっと書きました。
加算(add)、乗算(multi)、転置行列(t)、逆行列(inv)、共分散(var)(不偏にしたいならば*n/(n-1)を計算してください)
そのあたり
あとはソースを読んで慮ってください(ヽ´ω`)
商用、非商用、使用に制限ありません。

http://yamabukisoftworks.rash.jp/etc/MatrixProcess.java

import java.util.ArrayList;
public class MatrixProcess{

public static double[][] multi(double m,double[][] d1){

int r1 = d1.length;
int c1 = d1[0].length;
double[][] ret = new double[r1][c1];
for(int ii = 0;ii < r1;ii++){
for(int jj = 0;jj < c1;jj++){
ret[ii][jj] = d1[ii][jj]*m;
}
}

return ret;
}

public static double[][] add(double[][] d1,double[][] d2,boolean minus){
if(d1.length != d2.length){
return null;
}
if(d1[0].length != d2[0].length){
return null;
}
int r1 = d1.length;
int c1 = d1[0].length;
double[][] ret = new double[r1][c1];
for(int ii = 0;ii < r1;ii++){
for(int jj = 0;jj < c1;jj++){
ret[ii][jj] = d1[ii][jj]+d2[ii][jj]*((minus)?(-1):(1));
}
}

return ret;
}
public static double[][] add(double[][] d1,double[][] d2){
return add(d1,d2,false);
}
public static double[][] subtract(double[][] d1,double[][] d2){
return add(d1,d2,true);
}

public static double[][] t(double[][] d){

int r = d.length;
int c = d[0].length;
double[][] dat = new double[c][r];

for(int ii = 0;ii < r;ii++){
for(int jj = 0;jj < c;jj++){
dat[jj][ii]=d[ii][jj];
}
}
return dat;
}
public static double[][] multi(double[][] d1,double[][] d2){
if(d1[0].length != d2.length){
return null;
}
int r1 = d1.length;
int c1 = d1[0].length;
int r2 = d2.length;
int c2 = d2[0].length;
double[][] ret = new double[d1.length][d2[0].length];

for(int ii = 0;ii < r1;ii++){
for(int jj = 0;jj < c2;jj++){
ret[ii][jj] = 0;
for(int kk = 0;kk < c1;kk++){
ret[ii][jj] += d1[ii][kk]*d2[kk][jj];
}
}
}


return ret;
}


public static double[][] inv(double[][] d){
//Gauss-Jordan
int r = d.length;
int c = d[0].length;
double[][] e = new double[r][c];
double[][] dat = new double[r][c];
ArrayList al = new ArrayList();
for(int ii = 0;ii < r;ii++){
for(int jj = 0;jj < c;jj++){
e[ii][jj] = ((ii == jj)?(1):(0));
dat[ii][jj]=d[ii][jj];
}
al.add(ii);
}



while(true){
//for(int ii = 0;ii < r;ii++){
ArrayList nex = new ArrayList();
for(Integer ii:al){
double coef = dat[ii][ii];
if(coef == 0){
nex.add(ii);// calc after
continue;
}
for(int jj = 0;jj < c;jj++){
dat[ii][jj] /= coef;
e[ii][jj] /= coef;
}


for(int rr = 0;rr < r;rr++){
if(rr == ii){
continue;
}
double co2 = dat[rr][ii];
for(int jj = 0;jj < c;jj++){
//if(jj == ii){
// System.out.println(dat[ii][jj]);
//}
e[rr][jj] -= e[ii][jj]*co2;
dat[rr][jj] -= dat[ii][jj]*co2;
}
}
}
if(al.size() == nex.size()){
return null;
}
if(nex.size() == 0){
break;
}
al = nex;
}

return e;

}


public static double[][] var(double[][] dat){
int n = dat.length;
int c = dat[0].length;
double[][] ret = new double[c][c];
double ave[] = new double[c];
for(int hh = 0;hh < c;hh++){
ave[hh] = 0;
for(int kk = 0;kk < n;kk++){
ave[hh] += dat[kk][hh];
}
ave[hh] /= n;
}
for(int hh = 0;hh < c;hh++){
for(int jj = 0;jj < c;jj++){
ret[hh][jj] = 0;
for(int kk = 0;kk < n;kk++){
ret[hh][jj] += (dat[kk][hh] - ave[hh])*(dat[kk][jj]-ave[jj]);
}

ret[hh][jj] /= n;
}
}


return ret;

}



public static String getMatrixText(double[] dat){
double[][] dd = new double[1][dat.length];
for(int ii = 0;ii < dat.length;ii++){
dd[0][ii] = dat[ii];
}
return getMatrixText(dd);

}
public static String getMatrixText(double[][] dat){
int r = dat.length;
int c = dat[0].length;
double[][] e = new double[r][c];
StringBuffer sb = new StringBuffer();
for(int ii = 0;ii < r;ii++){
for(int jj = 0;jj < c;jj++){
sb.append(String.valueOf(dat[ii][jj]));
if(jj != c-1){
sb.append("\t");
}
}
sb.append("\n");
}
return sb.toString();
}

public static void main(String[] args){
//double[][] d = {{4,2},{3,1}};
//double[][] d = {{1,-1},{2,3}};
//double[][] d = {{1,1,3,4,5}};
//double[][] d = {{10,4,7},{2,5,8},{3,6,9}};
double[][] d = {{6,3,4},{2,3,6},{2,4,9}};
double[][] d1 = {{1,3,5},{2,4,6}};
double[][] d2 = {{8,4},{2,5},{3,6}};
//System.out.println(getMatrixText(inv(d)));
//System.out.println(getMatrixText(t(d)));
//System.out.println(getMatrixText(multi(d1,d2)));
System.out.println(getMatrixText(var(d2)));
}

}

posted by k_yama at 18:36 | Comment(0) | 備忘録

Java で AStar

最短経路探索に使われる A* (A-Star) 法を Java で実装してみました。
WikiPedia の
http://ja.wikipedia.org/wiki/A*
を見ながら書き書き。
推定値は0なのでダイクストラ法と言うのかな・・・?
大急ぎで作ったので間違えてるかもしれないのでそのときはコメントでお願いします。
忙しくて余りチェックできないので、返信は遅れるかもしれません。
サンプルコードがあったら例え間違っていたとしても、大変参考になった経験が多いので公開しました。
著作権は放棄しません(自分が使用するために障害にならないように)が、商用非商用問わず使用に制限はありません。


X[tab]Y[tab]経路にかかるコスト
X[tab]Z[tab]経路にかかるコスト



となっているファイルを generateNetwork で読み込ませれば、全体経路を作成します。その後 generateShortestPath で最短経路を探してくれるはずです。
あとはソースを見て慮ってください(ヽ´ω`)

http://yamabukisoftworks.rash.jp/etc/AStarNetwork.java

import java.util.*;
import java.util.regex.*;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.File;
public class AStarNetwork{
ArrayList openList = new ArrayList();
ArrayList closeList = new ArrayList();
ArrayList nodes = new ArrayList();



public void addNode(AStarNode as){
nodes.add(as);
}
public void formatVariables(){
for(AStarNode n:nodes){
n.format();
}
openList.clear();
closeList.clear();
}
/**
*
*
*
*/
public AStarResult generateShortestPath(AStarNode startnode,AStarNode goalnode){
formatVariables();
if(nodes.indexOf(startnode) < 0 || nodes.indexOf(goalnode) < 0){
System.out.println(startnode.getLabel()+":"+goalnode.getLabel());
System.out.println("start or goal node was not found in the network.");
return null;
}
openList.add(startnode);
AStarNode current = startnode;
double mincost = 0;
while(true){

if(openList.size() == 0){
System.out.println("There was no route which reach from start to goal.");
return null;
}

mincost = openList.get(0).get_fstar();
AStarNode minnode = openList.get(0);
for(AStarNode as:openList){
if(as.get_fstar() < mincost){
mincost = as.get_fstar();
minnode = as;
}
}
current = minnode;
if(current == goalnode){
break;
}
openList.remove(current);
closeList.add(current);
current.set_gstar(current.get_fstar() - current.get_hstar());

for(AStarEdge aa:current.edges){
AStarNode am = aa.getAnotherNode(current);
if(am == null){
System.out.println("There seems to be error in Edge construction.");
return null;
}
double assumed = current.get_gstar()+am.get_hstar() + aa.getCost();


int oi = openList.indexOf(am);
int ci = closeList.indexOf(am);
if(oi < 0 && ci < 0){
am.set_fstar(assumed);
openList.add(am);
am.setParent(current);
}else if(oi > -1){
if(am.get_fstar() > assumed){
am.set_fstar(assumed);
am.setParent(current);
}
}else if(ci > -1){
if(am.get_fstar() > assumed){
closeList.remove(am);
am.set_fstar(assumed);
am.setParent(current);
openList.add(am);
}
}

}

}

ArrayList ret = new ArrayList();
AStarNode backtracker = goalnode;

ret.add(backtracker);
while(backtracker != startnode){
//System.out.println(backtracker.getLabel());
backtracker = backtracker.getParent();
ret.add(backtracker);
}
return new AStarResult(ret,mincost);

}
public static AStarNetwork generateNetwork(String filename){
try{
BufferedReader br = new BufferedReader(new FileReader(new File(filename)));
String ln = null;
int numbuff = 1000;
ArrayList lines = new ArrayList();
HashMap hm = new HashMap();
while((ln = br.readLine()) != null){
lines.add(ln);
if(lines.size() > numbuff){
generateEdges(lines,hm);
lines.clear();
}
}
if(lines.size() > 0){
generateEdges(lines,hm);
lines.clear();
}
br.close();
Iterator ite = hm.keySet().iterator();
AStarNetwork ret = new AStarNetwork();
while(ite.hasNext()){
String lb = ite.next();
ret.addNode(hm.get(lb));
}

return ret;
}catch(Exception exx){
exx.printStackTrace();

}
return null;
}




/**
* generate edges from ArrayList of String.
* format of String should be [name of adge a][tab][name of edge b][tab][cost(double)].
*
* @param edgelist ArrayList of String.
* @param h if there are nodes already generated.
*
* @return HashMap of already generated nodes.
*/
public static HashMap generateEdges(ArrayList edgelist,HashMap h){

HashMap hm;
if(h == null){
hm = new HashMap();
}else{
hm = h;
}
Iterator ite = edgelist.iterator();
Pattern pat = Pattern.compile("^([^\t]+)[\t]([^\t]+)[\t]([0-9.\\-+Ee]+)");
while(ite.hasNext()){
String ln = ite.next();
Matcher mat = pat.matcher(ln);
if(mat.find()){
String l1 = mat.group(1);
String l2 = mat.group(2);
double d = Double.parseDouble(mat.group(3));
AStarNode n1 = hm.get(l1);
AStarNode n2 = hm.get(l2);
System.out.println(l1+";"+l2+";"+d);
if(hm.get(l1) == null){
hm.put(l1,new AStarNode(l1));
}
if(hm.get(l2) == null){
hm.put(l2,new AStarNode(l2));
}

AStarEdge ed = new AStarEdge(hm.get(l1),hm.get(l2),d);
hm.get(l1).addEdge(ed);
hm.get(l2).addEdge(ed);
}
}
return hm;
}




public AStarNode getNode(String lb){
for(AStarNode as:nodes){
if(as.getLabel().equals(lb)){
return as;
}

}
return null;
}
public static void main(String[] args){
AStarNetwork as = generateNetwork("example.dat");
/* example file contents
1 2 1
1 3 1
3 4 1
4 5 1
2 5 1
*/
AStarResult ar = as.generateShortestPath(as.getNode("1"),as.getNode("5"));
for(AStarNode n: ar.path){
System.out.println(n.getLabel());
}
System.out.println(ar.cost);

}


}
class AStarResult{
ArrayList path;
double cost;
AStarResult(ArrayList al,double c){
path = al;
cost = c;
}
}


class AStarNode{
long id = 0;
String label = "node";
ArrayList edges = new ArrayList();
AStarNode parent = null;
double fstar = 0;
double gstar = 0;
double hstar = 0;

AStarNode(){
}
AStarNode(String l){
setLabel(l);
}

/**
* set 0 to all variables (fstar, gstar and hstar).
*
*/
public void format(){
fstar = 0;
gstar = 0;
hstar = 0;
parent = null;
}


public double get_hstar(){
return hstar;
}
public double get_gstar(){
return gstar;
}
public double get_fstar(){
return fstar;
}



public void set_hstar(double d){
hstar = d;
}
public void set_gstar(double d){
gstar = d;
}
public void set_fstar(double d){
fstar = d;
}



/**
* change label to s.
*
*
*/
public void setLabel(String s){
label = s;
}

public String getLabel(){
return label;
}
/**
* add an edge.
*
*/
public void addEdge(AStarEdge e){
if(!this.hasEdgeTo(e.n1) && !this.hasEdgeTo(e.n2)){
edges.add(e);
}else{
System.out.println("");
}
}


/**
* add an edge to the node n.
*
* @param n aother node
* @param c cost to the node n
*/
public void addEdge(AStarNode n,double c){
edges.add(new AStarEdge(this,n,c));
}
/**
* return true if this node has an edge to the node "n".
*
* @param n target node
*/
public boolean hasEdgeTo(AStarNode n){
for(AStarEdge a:edges){
if(a.n1 == this){
if(a.n2 == n){
return true;
}
}else if(a.n2 == this){
if(a.n1 == n){
return true;
}
}
}
return false;
}

/**
* set parent node.
*/
public void setParent(AStarNode a){
parent = a;
}
/**
* return parent node.
*/
public AStarNode getParent(){
return parent;
}


}


class AStarEdge{
double cost = 1;
AStarNode n1 = null;
AStarNode n2 = null;
AStarEdge(AStarNode nn1,AStarNode nn2,double c){
n1 = nn1;
n2 = nn2;
cost = c;
}

public double getCost(){
return cost;

}
public AStarNode getAnotherNode(AStarNode as){

if(as == n1){
return n2;
}else if(as==n2){
return n1;
}else{
System.out.println("The node is not connected to this edge.");
return null;
}
}

}


posted by k_yama at 14:28 | Comment(0) | 備忘録