public void CalculateVerticesLoop(IvyParameters ivyParameters, RTIvyContainer rtIvyContainer, GameObject ivyGO)
        {
            float angle = 0f;

            if (!ivyParameters.halfgeom)
            {
                angle = Mathf.Rad2Deg * 2 * Mathf.PI / ivyParameters.sides;
            }
            else
            {
                angle = Mathf.Rad2Deg * 2 * Mathf.PI / ivyParameters.sides / 2;
            }



            Vector3    vertex    = Vector3.zero;
            Vector3    normal    = Vector3.zero;
            Vector2    uv        = Vector2.zero;
            Quaternion quat      = Quaternion.identity;
            Vector3    direction = Vector3.zero;


            Quaternion inverseIvyGORotation = Quaternion.Inverse(ivyGO.transform.rotation);



            for (int i = 0; i < ivyParameters.sides + 1; i++)
            {
                quat      = Quaternion.AngleAxis(angle * i, axis);
                direction = quat * firstVector;

                if (ivyParameters.halfgeom && ivyParameters.sides == 1)
                {
                    normal = -grabVector;
                }
                else
                {
                    normal = direction;
                }

                normal = inverseIvyGORotation * normal;



                vertex  = direction * radius + point;
                vertex -= ivyGO.transform.position;
                vertex  = inverseIvyGORotation * vertex;

                uv = new Vector2(length * ivyParameters.uvScale.y + ivyParameters.uvOffset.y - ivyParameters.stepSize,
                                 1f / ivyParameters.sides * i * ivyParameters.uvScale.x + ivyParameters.uvOffset.x);


                verticesLoop[i] = new RTVertexData(vertex, normal, uv, Vector2.zero, Color.black);
            }
        }
Beispiel #2
0
        public void BuildGeometry()
        {
            if (leavesDataInitialized)
            {
                //Lo primero inicializar
                Initialize();
                //Estos contadores nos servirán para saber por dónde vamos calculándo vértices y triángulos, ya q lo calcularemos todo a buco, sin ir por ramas
                int vertCount        = 0;
                int triBranchesCount = 0;

                //Recorremos cada rama y definimos el primer vértice que tenemos que escribir del array, recogido del vertcount actualizado en la iteración anterior
                for (int b = 0; b < infoPool.ivyContainer.branches.Count; b++)
                {
                    int firstVertex = vertCount;
                    Random.InitState(b + infoPool.ivyParameters.randomSeed);
                    if (infoPool.ivyContainer.branches [b].branchPoints.Count > 1)
                    {
                        //En este contador guardaremos cuántos vértices tiene la rama actual, para en la siguiente tenerlo en cuenta y saber qué vértices hay que
                        //escribir
                        int lastVertCount = 0;
                        //Recorremos cada punto de la rama hasta el penúltimo
                        for (int p = 0; p < infoPool.ivyContainer.branches [b].branchPoints.Count; p++)
                        {
                            //Si no es el último punto, calculamos el ring de vértices


                            BranchPoint branchPoint = infoPool.ivyContainer.branches[b].branchPoints[p];
                            branchPoint.verticesLoop = new List <RTVertexData>();



                            Vector3 centerVertexPosition = (branchPoint.point - infoPool.ivyContainer.ivyGO.transform.position);
                            centerVertexPosition = Quaternion.Inverse(infoPool.ivyContainer.ivyGO.transform.rotation) * centerVertexPosition;
                            float radius = CalculateRadius(branchPoint.length, infoPool.ivyContainer.branches[b].totalLenght);

                            branchPoint.radius = radius;

                            if (p != infoPool.ivyContainer.branches [b].branchPoints.Count - 1)
                            {
                                //En este array, el método nos mete en el index 0 el firstvector, y en el index 1 el axis de rotación del ring
                                Vector3[] vectors = CalculateVectors(infoPool.ivyContainer.branches [b].branchPoints [p].point, p, b);

                                branchPoint.firstVector = vectors[0];
                                branchPoint.axis        = vectors[1];


                                for (int v = 0; v < infoPool.ivyParameters.sides + 1; v++)
                                {
                                    if (infoPool.ivyParameters.generateBranches)
                                    {
                                        //BranchPoint branchPoint = infoPool.ivyContainer.branches[b].branchPoints[p];

                                        float tipInfluence = GetTipInfluence(branchPoint.length, infoPool.ivyContainer.branches[b].totalLenght);
                                        infoPool.ivyContainer.branches[b].branchPoints[p].radius = radius;

                                        Quaternion quat      = Quaternion.AngleAxis(angle * v, vectors[1]);
                                        Vector3    direction = quat * vectors[0];
                                        //Excepción para el cálculo de normales si tenemos el caso de media geometría y 1 lado
                                        if (infoPool.ivyParameters.halfgeom && infoPool.ivyParameters.sides == 1)
                                        {
                                            normals[vertCount] = -infoPool.ivyContainer.branches[b].branchPoints[p].grabVector;
                                        }
                                        else
                                        {
                                            normals[vertCount] = direction;
                                        }

                                        Vector3 vertexForRuntime = (direction * radius) + centerVertexPosition;

                                        verts[vertCount]  = (direction * radius * tipInfluence) + infoPool.ivyContainer.branches[b].branchPoints[p].point;
                                        verts[vertCount] -= infoPool.ivyContainer.ivyGO.transform.position;
                                        verts[vertCount]  = Quaternion.Inverse(infoPool.ivyContainer.ivyGO.transform.rotation) * verts[vertCount];


                                        uvs[vertCount] =
                                            new Vector2(branchPoint.length * infoPool.ivyParameters.uvScale.y + infoPool.ivyParameters.uvOffset.y - infoPool.ivyParameters.stepSize,
                                                        1f / infoPool.ivyParameters.sides * v * infoPool.ivyParameters.uvScale.x + infoPool.ivyParameters.uvOffset.x);

                                        normals[vertCount] = Quaternion.Inverse(infoPool.ivyContainer.ivyGO.transform.rotation) * normals[vertCount];



                                        RTVertexData vertexData = new RTVertexData(vertexForRuntime, normals[vertCount], uvs[vertCount], Vector2.zero, vColor[vertCount]);
                                        branchPoint.verticesLoop.Add(vertexData);



                                        //Vamos actualizando estos contadores para en la siguiente pasada saber por dónde íbamos escribiendo en el array
                                        vertCount++;
                                        lastVertCount++;
                                    }
                                }
                            }
                            //Si es el último punto, en lugar de calcular el ring, usamos el último punto para escribir el último vértice de esta rama
                            else
                            {
                                if (infoPool.ivyParameters.generateBranches)
                                {
                                    verts[vertCount] = (infoPool.ivyContainer.branches[b].branchPoints[p].point);
                                    //Corrección de espacio local
                                    verts[vertCount] -= infoPool.ivyContainer.ivyGO.transform.position;
                                    verts[vertCount]  = Quaternion.Inverse(infoPool.ivyContainer.ivyGO.transform.rotation) * verts[vertCount];
                                    //verts[vertCount] = centerVertexPosition;


                                    //Excepción para las normales en el caso de media geometría y 1 solo lado
                                    if (infoPool.ivyParameters.halfgeom && infoPool.ivyParameters.sides == 1)
                                    {
                                        normals[vertCount] = -infoPool.ivyContainer.branches[b].branchPoints[p].grabVector;
                                    }
                                    else
                                    {
                                        normals[vertCount] = Vector3.Normalize(infoPool.ivyContainer.branches[b].branchPoints[p].point - infoPool.ivyContainer.branches[b].branchPoints[p - 1].point);
                                    }
                                    uvs[vertCount] = new Vector2(infoPool.ivyContainer.branches[b].totalLenght * infoPool.ivyParameters.uvScale.y + infoPool.ivyParameters.uvOffset.y, 0.5f * infoPool.ivyParameters.uvScale.x + infoPool.ivyParameters.uvOffset.x);

                                    normals[vertCount] = Quaternion.Inverse(infoPool.ivyContainer.ivyGO.transform.rotation) * normals[vertCount];



                                    Vector3 vertexForRuntime = centerVertexPosition;


                                    RTVertexData vertexData = new RTVertexData(vertexForRuntime, normals[vertCount], uvs[vertCount], Vector2.zero, vColor[vertCount]);
                                    branchPoint.verticesLoop.Add(vertexData);



                                    //Vamos actualizando estos contadores para en la siguiente pasada saber por dónde íbamos escribiendo en el array
                                    vertCount++;
                                    lastVertCount++;



                                    //Y después de poner el último vértice, triangulamos
                                    TriangulateBranch(b, ref triBranchesCount, vertCount, lastVertCount);
                                }
                            }
                        }
                    }
                    //escribimos en el diccionario el index por donde nos hemos quedado  para después poder
                    //transformar las uvs de cada elemento acorde a su dimensión real
                    int[] fromTo = new int[2] {
                        firstVertex, vertCount - 1
                    };
                    branchesLeavesIndices.Add(branchesLeavesIndices.Count, fromTo);


                    if (infoPool.ivyParameters.generateLeaves)
                    {
                        //infoPool.ivyContainer.branches[b].ClearRuntimeVerticesLeaves();
                        BuildLeaves(b, ref vertCount);
                    }
                }

                //Y pasamos los vértices y tris a la malla
                ivyMesh.vertices = verts;
                ivyMesh.normals  = normals;
                ivyMesh.uv       = uvs;
                ivyMesh.colors   = vColor;
                ivyMesh.SetTriangles(trisBranches, 0);
                //Por cada material, metemos los triángulos de hojas al submesh correspondiente
                for (int i = 0; i < leavesMaterials.Count; i++)
                {
                    ivyMesh.SetTriangles(trisLeaves [i], i + 1);
                }
                ivyMesh.RecalculateTangents();
                ivyMesh.RecalculateBounds();
            }
        }
Beispiel #3
0
        //Aquí se construyen las hojas, este método es llamado rama a rama
        void BuildLeaves(int b, ref int vertCount)
        {
            Mesh chosenLeaveMesh;

            //Se recorren los materiales
            for (int i = 0; i < leavesMaterials.Count; i++)
            {
                Random.InitState(b + infoPool.ivyParameters.randomSeed + i);

                for (int j = 0; j < infoPool.ivyContainer.branches[b].leaves.Count; j++)
                {
                    LeafPoint currentLeaf = infoPool.ivyContainer.branches[b].leaves[j];


                    //Ahora vemos si para el material que estamos iterando, le corresponde el tipo de hoja que tenemos en este punto
                    if (typesByMat[i].Contains(currentLeaf.chosenLeave))
                    {
                        currentLeaf.verticesLeaves = new List <RTVertexData>();
                        //Y vemos qué tipo de hoja corresponde a cada punto a cogemos esa malla
                        chosenLeaveMesh = infoPool.ivyParameters.leavesPrefabs[currentLeaf.chosenLeave].GetComponent <MeshFilter>().sharedMesh;
                        //definimos el vértice por el que tenemos que empezar a escribir en el array
                        int        firstVertex = vertCount;
                        Vector3    left, forward;
                        Quaternion quat;
                        //Aquí cálculos de orientación en función de las opciones de rotación
                        if (!infoPool.ivyParameters.globalOrientation)
                        {
                            forward = currentLeaf.lpForward;
                            left    = currentLeaf.left;
                            //left = Vector3.Cross(currentLeaf.lpForward, currentLeaf.lpUpward);
                        }
                        else
                        {
                            forward = infoPool.ivyParameters.globalRotation;
                            left    = Vector3.Normalize(Vector3.Cross(infoPool.ivyParameters.globalRotation, currentLeaf.lpUpward));
                        }
                        //Y aplicamos la rotación

                        quat = Quaternion.LookRotation(currentLeaf.lpUpward, forward);
                        quat = Quaternion.AngleAxis(infoPool.ivyParameters.rotation.x, left) * Quaternion.AngleAxis(infoPool.ivyParameters.rotation.y, currentLeaf.lpUpward) * Quaternion.AngleAxis(infoPool.ivyParameters.rotation.z, forward) * quat;
                        quat = Quaternion.AngleAxis(Random.Range(-infoPool.ivyParameters.randomRotation.x, infoPool.ivyParameters.randomRotation.x), left) * Quaternion.AngleAxis(Random.Range(-infoPool.ivyParameters.randomRotation.y, infoPool.ivyParameters.randomRotation.y), currentLeaf.lpUpward) * Quaternion.AngleAxis(Random.Range(-infoPool.ivyParameters.randomRotation.z, infoPool.ivyParameters.randomRotation.z), forward) * quat;
                        quat = currentLeaf.forwarRot * quat;



                        //Aquí la escala, que es facilita, incluyendo el tip influence
                        float scale = Random.Range(infoPool.ivyParameters.minScale, infoPool.ivyParameters.maxScale);
                        currentLeaf.leafScale = scale;



                        scale *= Mathf.InverseLerp(infoPool.ivyContainer.branches[b].totalLenght, infoPool.ivyContainer.branches[b].totalLenght - infoPool.ivyParameters.tipInfluence, currentLeaf.lpLength);



                        /*******************/
                        currentLeaf.leafRotation = quat;
                        currentLeaf.dstScale     = scale;
                        /*******************/



                        //Metemos los triángulos correspondientes en el array correspondiente al material que estamos iterando
                        for (int t = 0; t < chosenLeaveMesh.triangles.Length; t++)
                        {
                            int triangle = chosenLeaveMesh.triangles[t] + vertCount;
                            trisLeaves[i].Add(triangle);
                        }
                        //ylos vértices, normales y uvs, aplicando las transformaciones pertinentes, actualizando el contador para la siguiente iteración saber por dónde vamos
                        for (int v = 0; v < chosenLeaveMesh.vertexCount; v++)
                        {
                            Vector3 offset = left * infoPool.ivyParameters.offset.x +
                                             currentLeaf.lpUpward * infoPool.ivyParameters.offset.y +
                                             currentLeaf.lpForward * infoPool.ivyParameters.offset.z;

                            verts[vertCount]   = quat * chosenLeaveMesh.vertices[v] * scale + currentLeaf.point + offset;
                            normals[vertCount] = quat * chosenLeaveMesh.normals[v];
                            uvs[vertCount]     = chosenLeaveMesh.uv[v];
                            vColor[vertCount]  = chosenLeaveMesh.colors[v];

                            normals[vertCount] = Quaternion.Inverse(infoPool.ivyContainer.ivyGO.transform.rotation) * normals[vertCount];
                            verts[vertCount]  -= infoPool.ivyContainer.ivyGO.transform.position;
                            verts[vertCount]   = Quaternion.Inverse(infoPool.ivyContainer.ivyGO.transform.rotation) * verts[vertCount];


                            RTVertexData vertexData = new RTVertexData(verts[vertCount], normals[vertCount], uvs[vertCount], Vector2.zero, vColor[vertCount]);
                            currentLeaf.verticesLeaves.Add(vertexData);

                            currentLeaf.leafCenter = currentLeaf.point - infoPool.ivyContainer.ivyGO.transform.position;
                            currentLeaf.leafCenter = Quaternion.Inverse(infoPool.ivyContainer.ivyGO.transform.rotation) * currentLeaf.leafCenter;

                            vertCount++;
                        }
                        //escribimos en el diccionario el index por donde nos hemos quedado  para después poder
                        //transformar las uvs de cada elemento acorde a su dimensión real
                        int[] fromTo = new int[2] {
                            firstVertex, vertCount - 1
                        };
                        branchesLeavesIndices.Add(branchesLeavesIndices.Count, fromTo);
                    }



                    //for (int p = 0; p < currentBranchPoint.leaves.Count; p++)
                    //{

                    //}
                }


                /*//Después por cada material, recorremos los puntos de la rama
                 * for (int j = 0; j < infoPool.ivyContainer.branches[b].branchPoints.Count; j++) {
                 *
                 *
                 *
                 *
                 *
                 *
                 * }*/
            }
        }
        public void CopyToFixedMesh(int branchIndex, int initSegmentIdx,
                                    int endSegmentIdx, RTBranchContainer branchContainer, RTBranchContainer bakedBranchContainer)
        {
            int numVerticesPerLoop  = ivyParameters.sides + 1;
            int numTrianglesPerLoop = ivyParameters.sides * 6;
            int numLoopsToProcess   = 1;
            int onlyBranchVertices  = (vertCountsPerBranch[branchIndex] - vertCountLeavesPerBranch[branchIndex]);


            int vertexOffset = 0;

            for (int i = 1; i <= branchIndex; i++)
            {
                vertexOffset += vertCountsPerBranch[branchIndex];
            }

            if (processedBranchesVerticesIndicesPerBranch[branchIndex].Count <= 0)
            {
                numLoopsToProcess = 2;
            }
            else
            {
                numLoopsToProcess = 1;
                vertexOffset     += numVerticesPerLoop;
            }


            for (int i = numLoopsToProcess - 1; i >= 0; i--)
            {
                int index = branchContainer.branchPoints.Count - backtrackingPoints - i;

                RTBranchPoint rtBranchPoint = branchContainer.branchPoints[index];

                for (int j = 0; j < rtBranchPoint.verticesLoop.Length; j++)
                {
                    RTVertexData vertexData = rtBranchPoint.verticesLoop[j];
                    processedMeshData.AddVertex(vertexData.vertex, vertexData.normal, vertexData.uv, vertexData.color);

                    processedBranchesVerticesIndicesPerBranch[branchIndex].Add(processedMeshData.VertexCount() - 1);
                }
            }


            int triangleIndexOffset = 0;

            if (branchIndex > 0)
            {
                triangleIndexOffset = lastTriangleIndexPerBranch[branchIndex];
            }

            if (processedBranchesVerticesIndicesPerBranch[branchIndex].Count >= numVerticesPerLoop * 2)
            {
                int initIdx = processedBranchesVerticesIndicesPerBranch[branchIndex].Count - (numVerticesPerLoop * 2);


                for (int i = 0; i < ivyParameters.sides; i++)
                {
                    int v0 = processedBranchesVerticesIndicesPerBranch[branchIndex][i + initIdx];

                    int v1 = processedBranchesVerticesIndicesPerBranch[branchIndex][i + 1 + initIdx];

                    int v2 = processedBranchesVerticesIndicesPerBranch[branchIndex][i + ivyParameters.sides + 1 + initIdx];

                    int v3 = processedBranchesVerticesIndicesPerBranch[branchIndex][i + 1 + initIdx];

                    int v4 = processedBranchesVerticesIndicesPerBranch[branchIndex][i + ivyParameters.sides + 2 + initIdx];

                    int v5 = processedBranchesVerticesIndicesPerBranch[branchIndex][i + ivyParameters.sides + 1 + initIdx];


                    processedMeshData.AddTriangle(0, v0);
                    processedMeshData.AddTriangle(0, v1);
                    processedMeshData.AddTriangle(0, v2);

                    processedMeshData.AddTriangle(0, v3);
                    processedMeshData.AddTriangle(0, v4);
                    processedMeshData.AddTriangle(0, v5);
                }
            }



            if (ivyParameters.generateLeaves)
            {
                int lastVertexLeafProcessed = processedMeshData.VertexCount();
                int numLeavesProcessed      = 0;

                for (int i = initSegmentIdx; i < endSegmentIdx; i++)
                {
                    RTLeafPoint[] leaves = bakedBranchContainer.leavesOrderedByInitSegment[i];
                    for (int j = 0; j < leaves.Length; j++)
                    {
                        RTLeafPoint currentLeaf = leaves[j];

                        if (currentLeaf == null)
                        {
                            continue;
                        }

                        RTMeshData chosenLeaveMeshData = leavesMeshesByChosenLeaf[currentLeaf.chosenLeave];

                        int submesh = submeshByChoseLeaf[currentLeaf.chosenLeave];
                        for (int t = 0; t < chosenLeaveMeshData.triangles[0].Length; t++)
                        {
                            int triangleValue = chosenLeaveMeshData.triangles[0][t] + lastVertexLeafProcessed;
                            processedMeshData.AddTriangle(submesh, triangleValue);
                        }

                        for (int v = 0; v < currentLeaf.vertices.Length; v++)
                        {
                            RTVertexData vertexData = currentLeaf.vertices[v];
                            processedMeshData.AddVertex(vertexData.vertex,
                                                        vertexData.normal, vertexData.uv,
                                                        vertexData.color);

                            processedVerticesIndicesPerBranch[branchIndex].Add(processedMeshData.VertexCount() - 1);

                            lastVertexLeafProcessed++;
                        }
                        numLeavesProcessed++;
                    }
                }
            }
        }
Beispiel #5
0
        public void CreateVertices(IvyParameters ivyParameters, RTMeshData leafMeshData, GameObject ivyGO)
        {
            Vector3    left, forward;
            Quaternion quat;


            //Aquí cálculos de orientación en función de las opciones de rotación
            if (!ivyParameters.globalOrientation)
            {
                forward = lpForward;
                left    = this.left;
                //left = Vector3.Cross(currentLeaf.lpForward, currentLeaf.lpUpward);
            }
            else
            {
                forward = ivyParameters.globalRotation;
                left    = Vector3.Normalize(Vector3.Cross(ivyParameters.globalRotation, this.lpUpward));
            }
            //Y aplicamos la rotación

            quat = Quaternion.LookRotation(this.lpUpward, forward);

            quat = Quaternion.AngleAxis(ivyParameters.rotation.x, left) *
                   Quaternion.AngleAxis(ivyParameters.rotation.y, this.lpUpward) *
                   Quaternion.AngleAxis(ivyParameters.rotation.z, forward) *
                   quat;


            quat = Quaternion.AngleAxis(Random.Range(-ivyParameters.randomRotation.x, ivyParameters.randomRotation.x), left) *
                   Quaternion.AngleAxis(Random.Range(-ivyParameters.randomRotation.y, ivyParameters.randomRotation.y), this.lpUpward) *
                   Quaternion.AngleAxis(Random.Range(-ivyParameters.randomRotation.z, ivyParameters.randomRotation.z), forward) *
                   quat;

            quat = this.forwarRot * quat;



            //Aquí la escala, que es facilita, incluyendo el tip influence
            float scale = Random.Range(ivyParameters.minScale, ivyParameters.maxScale);

            //scale *= Mathf.InverseLerp(infoPool.ivyContainer.branches[b].totalLenght, infoPool.ivyContainer.branches[b].totalLenght - infoPool.ivyParameters.tipInfluence, currentLeaf.lpLength);



            /*******************/
            this.leafRotation = quat;
            //currentLeaf.dstScale = scale;
            /*******************/

            this.leafCenter = this.point - ivyGO.transform.position;
            this.leafCenter = Quaternion.Inverse(ivyGO.transform.rotation) * this.leafCenter;


            if (this.verticesLeaves == null)
            {
                this.verticesLeaves = new List <RTVertexData>(4);
            }
            //this.verticesLeaves.Clear();

            Vector3    vertex               = Vector3.zero;
            Vector3    normal               = Vector3.zero;
            Vector2    uv                   = Vector2.zero;
            Color      vertexColor          = Color.black;
            Quaternion ivyGOInverseRotation = Quaternion.Inverse(ivyGO.transform.rotation);


            for (int v = 0; v < leafMeshData.vertices.Length; v++)
            {
                Vector3 offset = left * ivyParameters.offset.x + this.lpUpward * ivyParameters.offset.y + this.lpForward * ivyParameters.offset.z;

                vertex = quat * leafMeshData.vertices[v] * scale + leafCenter + offset;

                normal = quat * leafMeshData.normals[v];
                normal = ivyGOInverseRotation * normal;

                uv          = leafMeshData.uv[v];
                vertexColor = leafMeshData.colors[v];

                RTVertexData vertexData = new RTVertexData(vertex, normal, uv, Vector2.zero, vertexColor);
                this.verticesLeaves.Add(vertexData);
            }
        }