https://linen.dev logo
すでに焼きこんだ面をスクリプト側でuv指定する
# forum
r
は?という感じですが方向幕の座標をいちいちとるのめんどくさいのでオブジェクト分けした面のUVデータをスクリプト制御してできれば簡単になるのでは?と画策しており、いくつかの方法を考えてみたのですが実際に構文に起こす方法がわからず(そもそもできるかどうかの判断も怪しいですが)お力を借りたい次第です。 なんかここ行けそう!って部分ありましたら助言お願いします! ・オブジェクト分けしたモデルのUVを調節する 例(new Parts("rollpos"))とかで適当にスクリプト上でオブジェクト分けしといてそのUVを調節する方法の場合、材質設定はどうなるのか、renderWithTextureなどの部分はどう処理すればいいのかわからず… ・オブジェクトのposを入手する 例によって(new Parts("rollpos"))とかでオブジェクト分けした後通常のテッセレーターの手順でrenderWithTexture(pos,uv , ....)とやるときのposをうまい具合に引用できないかなとおもうも具体的な処理方法がわからず… 応用できればLCDや速度計などといった可変部分がある画面設定がより楽になれるような気がするんですよね
u
わかる、俺もやりたかった項目 GL11メソッドあたり(openGLかLWJGL周り?)にありそうな気はしている UVに関してのメソッドで、頂点位置かオブジェクト単体指定でいけないかな
GL11.glPushMatrix()  →ここにかきそう  →renderer.parts() GL11.glPopMatrix() こうなりそう
h
パーツから座標を拾って、それをもとにスクリプト側で描画する実装になると思います E259で実験的に実装してたりするので、もし参考にしたい場合はscript/hi03_lib/lib_CustomAnimator1.0.jsとscripts/hi03_e259/render_e259-2.jsをご参照ください(流用可) ー以下実装の流れ(四角形のみ)ー 1.事前にinitからmodeObj(par2)をグローバル変数などで参照できるようにする 2.initで定義したパーツとmodelObjを使って面を拾う
Copy code
javascript
        var objects = Java.from(パーツ.getObjects(modelObj.model));//このmodelObjはpar2
        //Java.from()はJavaの配列風オブジェクトをJavascriptの配列に変換 → forEachとか使用できるようになる
        var faceList = [];
        objects.forEach(function (groupObject) {//GroupObject[]
            var faces = Java.from(groupObject.faces);
            faces.forEach(function (face) {//Face[]
                faceList.push(face);//すべてのFaceを集める
            });
        });
3.faceListを回して座標を取得/整理をする
Copy code
javascript
var preVertexList = [];
faceList.forEach(function (face) {//Face[]
  //ここに4以降の内容
}
4.faceが持つverticesは三角形に分割された頂点(三角形x2=6頂点)なので、重複する頂点を削除する(四角形の場合)
Copy code
javascript
            var vertices = Java.from(face.vertices);
            var uniqueVertices = [];
            //重複する頂点を除去(四角形は三角形x2=頂点x6)
            vertices.forEach(function (vertex) {
                var isDup = uniqueVertices.some(function (uniqueVertex) {
                    return vertex.equals(uniqueVertex);//重複チェック
                });
                if (!isDup) uniqueVertices.push(vertex);
            });
            //四角形以外は処理しない
            if (uniqueVertices.length !== 4) return;
続く↓
tessellatorは左上→左下→右下→右上の順で座標を追加するため、順番を整理する必要がある 5.面の法線ベクトルを利用してZ軸を基準(XY平面上)に頂点を整列させる
Copy code
javascript
//法線ベクトル
            var normalVertex = face.faceNormal;
            if (!normalVertex) face.calculateFaceNormal(Packages.jp.ngt.ngtlib.renderer.model.VecAccuracy.LOW);
            var normalVec = normalVertex.toVec();
            var pitch = normalVec.getPitch();
            var yaw = normalVec.getYaw();
            //頂点をベクトル化 & Z軸に整列
            var rotatedList = [];
            for (var i = 0; i < 4; i++) {//四角形のみなので4
                var vx = uniqueVertices[i].getX();
                var vy = uniqueVertices[i].getY();
                var vz = uniqueVertices[i].getZ();
                var pos = new Packages.jp.ngt.ngtlib.math.Vec3(vx, vy, vz).rotateAroundY(-yaw).rotateAroundX(-pitch);
                rotatedList.push({
                    x: pos.getX(),//XY平面上に回転した後の座標
                    y: pos.getY(),
                    z: pos.getZ(),
                    vx: vx,//回転前の元の座標
                    vy: vy,
                    vz: vz
                });
            }
6.Z軸からの見かけで上下をソートして分離→左右をソート
Copy code
javascript
            //上下をソートする
            rotatedList.sort(function (v1, v2) {
                if (v1.y === v2.y) return v1.x - v2.x; //yが同じならxの小さいほうを先
                return v2.y - v1.y;
            });
            //上下を分離
            var topVertices = rotatedList.slice(0, 2);
            var bottomVertices = rotatedList.slice(2, 4);
            //左右をソートする
            topVertices.sort(function (v1, v2) { return v1.x - v2.x; });
            bottomVertices.sort(function (v1, v2) { return v1.x - v2.x; });
続く↓
7.順番を入れ替え、Z軸に整列する前の元の座標の配列に変換
Copy code
javascript
            //並べ替え
            var result = [
                topVertices[0],//左上
                bottomVertices[0],//左下
                bottomVertices[1],//右下
                topVertices[1]//右上
            ];
            //座標変換
            result = result.map(function (vertices) {
                return [vertices.vx, vertices.vy, vertices.vz];
            });
            preVertexList.push(result);
これでpreVertexListには面を構成する頂点座標の3次元配列ができます preVertexList = [ [ [x1, y1, z1], [x2, y2, z2], [x3, y3, z3], [x4, y4, z4], ], [...] ]
tessellatorで面を描画する方法はざっくりこんな感じです
Copy code
javascript
        //UV座標を用意する
        var u0 = ◯;
        var u1 = ◯;
        var v0 = ◯;
        var v1 = ◯;

        var NGTTessellator = Packages.jp.ngt.ngtlib.renderer.NGTTessellator;
        var tessellator = NGTTessellator.instance;
        tessellator.startDrawingQuads();
        for (var i = 0; i < preVertexList.length; i++) {
            tessellator.addVertexWithUV(preVertexList[i][0][0], preVertexList[i][0][1], preVertexList[i][0][2], u0, v0);
            tessellator.addVertexWithUV(preVertexList[i][1][0], preVertexList[i][1][1], preVertexList[i][1][2], u0, v1);
            tessellator.addVertexWithUV(preVertexList[i][2][0], preVertexList[i][2][1], preVertexList[i][2][2], u1, v1);
            tessellator.addVertexWithUV(preVertexList[i][3][0], preVertexList[i][3][1], preVertexList[i][3][2], u1, v0);
        }
        tessellator.draw();
もしかしたら複数材質がある場合はrenderer.currentMatIdで絞らないとだめかもです(うろ覚え if (renderer.currentMatId === 0) {...} とすれば0番目の材質のときだけ実行されます
翌々考えたら座標を算出するところまではinit内で完結できるのでpar2のグローバル化はいらなかったですね...
u
おぉ〜すげえ現実解だ
これ、条件分岐で分けて他の材質に対してフィルタかけてるわけだけど たしかRTMのスクリプトの動作、とくに描画スクリプトの動作は、材質の個数分、各材質ごとに実行されるから、条件分けで跳ね除けられる って認識でいいんでしたっけ? (各材質、各状態 ≒ pass毎にスクリプトを回す? → passでフィルタしてあげると、LightやAlphablendの場合分けができたはず)
h
1フレームで材質の数*passの数だけ実行されるのでそうですね
u
1fpsってのが意外とミソなんですよね 注意点 renderは可能な限り受動的に動くようにしないと(mathとか使わないようにしないと)、すぐに重くなりがち
r
おーこんなやり方があったとは… 試験的にすでに組み込まれたパックもあるとのことでそっちも参考にしつつ導入してみます!
3 Views