質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.13%

ランタイム生成したメッシュがずれた位置に描画される

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 1,488
退会済みユーザー

退会済みユーザー

現在Unity5.6.0 にてランタイムでメッシュを生成し、ロープ状のオブジェクトを作成しようとしています。
メッシュの定義及び描画まではできているのですが座標が( 0, 0, 0 )の時以外だとメッシュの描画位置がずれてしまいます。
詳細は↓画像にて
イメージ説明
画像左の黒い点が座標( 0, 0, 0 ) 真ん中の点が ( 1, 0, 0 )です、オブジェクト自体の座標は ( 1, 0, 0 )の位置にセットしています。
中央のギズモの点群がMeshに設定した頂点群です。
これを見る限り頂点座標は問題なさそうなのですが生成したメッシュの方に何か原因があるのでしょうか?

ランタイムでのメッシュ生成は初めてですので至らないところがありますがソースコードは以下の通りです。
よろしくお願いします。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;



//==============================================================================
//------------------------------------------------------------------------------
// チューブ描画レンダラー.
// http://wiki.unity3d.com/index.php/3D_Physics_Based_Rope
// ↑のページのソースを参考に.
public class TubeRenderer : MonoBehaviour {


    //==============================================================================
    //------------------------------------------------------------------------------
    public class TubeVertex {
        public Vector3 point = Vector3.zero;
        public float radius = 1f;
        public Color color = Color.white;


        //------------------------------------------------------------------------------
        // コンストラクタ.
        public TubeVertex(
                Vector3 _pt,
                float _r,
                Color _color ) {

            point = _pt;
            radius = _r;
            color = _color;
        }
    }


    [SerializeField] private TubeVertex[] vertices;
    public TubeVertex[] Vertices { get { return vertices; } set { vertices = value; } }

    [SerializeField] private bool useMeshCollision = false;
    public bool UseMeshCollision { get { return useMeshCollision; } set { useMeshCollision = value; } }

    [SerializeField] private int crossSegments = 3;
    public int CrossSegments { get { return crossSegments; } set { crossSegments = value; } }

    [SerializeField] private Material material;
    public Material Mat { get { return material; } set { material = value; } }

    [SerializeField] private float floatAtDistance = -1f;
    [SerializeField] private int movePixelsForRebuild = 6;
    [SerializeField] private float maxRebuildTime = 0.1f;
    [SerializeField] private Vector3 lastCamearPosition1;
    [SerializeField] private Vector3 lastCameraPosition2;
    [SerializeField] private Vector3[] crossPoints;
    [SerializeField] private bool isDrawGizmo = false;
    [SerializeField] private bool colliderExists = false;
    [SerializeField] private bool usingBumpmap = false;

    private Mesh mesh;
    private float lastRebuildTime = 0f;
    private int lastCrossSegments;


    //------------------------------------------------------------------------------
    void Start () {
        this.reset();
        mesh = new Mesh();
        var _meshRenderer = gameObject.GetComponent<MeshRenderer>();
        _meshRenderer.material = material;
        if ( material ) {
            if ( material.GetTexture( "_BumpMap" ) )
                usingBumpmap = true;
        }    
    }


    //------------------------------------------------------------------------------
    void LateUpdate() {

        if ( vertices == null || vertices.Length <= 1 ) return;


        if ( crossSegments != lastCrossSegments ) {
            crossPoints = new Vector3[ crossSegments ];
            float _theta = 2f * Mathf.PI / crossSegments;
            for ( int i = 0; i < crossSegments; ++i ) {
                crossPoints[i] = new Vector3( Mathf.Cos( _theta * i ), Mathf.Sin( _theta * i ), 0 );
            }
            lastCrossSegments = crossSegments;
        }


        Vector3[] _meshVertices = new Vector3[ vertices.Length * crossSegments ];
        mesh.vertices = new Vector3[ vertices.Length * crossSegments ];
        Vector2[] _uvs = new Vector2[ vertices.Length * crossSegments ];
        Color[] _colors = new Color[ vertices.Length * crossSegments ];
        int[] _lastVertices = new int[ crossSegments ];
        int[] _theseVertices = new int[ crossSegments ];
        Quaternion _rotation = transform.rotation;

        // 頂点作成.
        for ( int i = 0; i < vertices.Length; ++i ) {

            if ( i < vertices.Length - 1 )
                _rotation = Quaternion.FromToRotation( Vector3.forward, vertices[i].point - vertices[ i + 1 ].point );

            for ( int j = 0; j < crossSegments; ++j ) {
                int _vertexIndex = i * crossSegments + j;
                _meshVertices [ _vertexIndex ] = vertices[i].point + ( _rotation * crossPoints[j] ) * vertices[i].radius;

                _uvs[ _vertexIndex ] = new Vector2( ( 0f + j ) / crossSegments, ( 0f + i ) / vertices.Length );
                _colors[ _vertexIndex ] = vertices[i].color;

                _lastVertices[j] = _theseVertices[j];
                _theseVertices[j] = i * crossSegments;
            }
        }

        // TriangleListを作成.
        // 手前蓋閉め,チューブインデックス追加,先端蓋閉め.
        List<int> _tempList = new List<int>();
        for ( int i = 0; i < crossSegments - 2; ++i ) {
            if ( i < 1 ) {
                _tempList.Add( 0 );
                _tempList.Add( 1 );
                _tempList.Add( 2 );
            } else {
                int _num = i + 1;
                _tempList.Add( _num );
                _tempList.Add( _num + 1 );
                _tempList.Add( 0 );
            }
        }

        for ( int i = 0; i < vertices.Length - 1; ++i ) {
            for ( int j = 0; j < crossSegments; ++j ) {
                int _a = i * crossSegments + j;
                int _b = ( i + 1 ) * crossSegments + j;

                if ( j < crossSegments - 1 ) {
                    _tempList.Add( _a );
                    _tempList.Add( _a + crossSegments );
                    _tempList.Add( _a + 1 );

                    _tempList.Add( _a + crossSegments );
                    _tempList.Add( _a + crossSegments + 1 );
                    _tempList.Add( _a + 1 );
                } else {
                    _tempList.Add( _a );
                    _tempList.Add( _a + crossSegments );
                    _tempList.Add( i * crossSegments );

                    _tempList.Add( _a + crossSegments );
                    _tempList.Add( i * crossSegments + crossSegments );
                    _tempList.Add( i * crossSegments );                
                }
            }
        }

        for ( int i = _meshVertices.Length; ( _meshVertices.Length - crossSegments ) + 2 < i; --i ) {
            if ( _meshVertices.Length <= i ) {
                _tempList.Add( _meshVertices.Length - 1 );
                _tempList.Add( _meshVertices.Length - 2 );
                _tempList.Add( _meshVertices.Length - 3 );
            } else {
                int _num = i - 2;
                _tempList.Add( _meshVertices.Length - 1 );
                _tempList.Add( _num );
                _tempList.Add( _num - 1);
            }
        }
        mesh.Clear();
        mesh.vertices = _meshVertices;
        mesh.triangles = _tempList.ToArray();
        mesh.RecalculateNormals();


        if ( usingBumpmap )
            mesh.tangents = calculateTangents( mesh.vertices );
         mesh.uv = _uvs;

        if ( useMeshCollision ) {
            if ( colliderExists ) {
                gameObject.GetComponent<MeshCollider>().sharedMesh = mesh;
            } else {
                gameObject.AddComponent<MeshCollider>();
                colliderExists = true;
            }
        }
        gameObject.GetComponent<MeshFilter>().mesh = mesh;

    }


    //------------------------------------------------------------------------------
    // ギズモ描画.
    void OnDrawGizmos() {

        if ( !isDrawGizmo ) return;
        if ( vertices != null && 0 < vertices.Length) {

            for ( int i = 0; i < mesh.vertices.Length; ++i ) {
                Gizmos.color = Color.white;
                Gizmos.DrawWireSphere( mesh.vertices[i], 0.02f );
            }

            for ( int i = 0; i < mesh.triangles.Length; ++i ) {
                switch ( mesh.triangles[i] % 3 ) {
                case 0: Gizmos.color = Color.red; break;
                case 1: Gizmos.color = Color.blue; break;
                case 2: Gizmos.color = Color.green; break;
                }
                Gizmos.DrawSphere( mesh.vertices[ mesh.triangles[i] ], 0.01f );
            }
        }

    }




    //------------------------------------------------------------------------------
    // 正接を求める.
    public Vector4[] calculateTangents(
            Vector3[] _verts ) {

        Vector4[] _tangents = new Vector4[ _verts.Length ];
        for ( int i = 0; i < _tangents.Length; ++i ) {
            Vector3 _vertex1 = ( 0 < i ) ? _verts[ i - 1 ] : _verts[i];
            Vector3 _vertex2 = ( i < _tangents.Length -1 ) ? _verts[ i + 1 ] : _verts[i];
            Vector3 _tan = ( _vertex1 - _vertex2 ).normalized;
            _tangents[i] = new Vector4( _tan.x, _tan.y, _tan.z, 1f );
        }
        return _tangents;
    }


    //------------------------------------------------------------------------------
    // 座標をセット.
    public void setPoints(
            Vector3[] _points,
            float _radius,
            Color _color ) {

        if ( _points.Length < 2 ) return;
        vertices = new TubeVertex[ _points.Length ];
        for ( int i = 0; i < _points.Length; ++i ) {
            vertices[ i ] = new TubeVertex( _points[i], _radius, _color );
        }
    }


    //------------------------------------------------------------------------------
    public void reset() {
        vertices = new TubeVertex[]{ new TubeVertex( Vector3.zero, 1f, Color.white ), new TubeVertex( new Vector3( 1, 0, 0 ), 1f, Color.white ) };
    }
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

check解決した方法

0

自己解決解決しました

先ほど張り付けたスクリプトはロープの描画のみを行うクラスだったのですが原因はそのスクリプトに座標を指定するクラスにありました...

構成としては以下の画像の通りです
イメージ説明
イメージ説明

RopeLinePFオブジェクトに
RopeLine.cs : ロープのジョイント作成等の処理及びジョイント座標更新処理
TubeRenderer.cs : ロープのメッシュ描画処理
↑コンポーネントをアタッチしている構成で、各ジョイントはRopeLinePFオブジェクトの子要素にしています。
この時の座標更新処理ですがRopeLine.cs側での座標更新処理にて以下の画像の通りに変更したら解決しました。
イメージ説明
コメントアウトされているのが問題があったバージョンのソース.

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.13%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る