/**Decide which operations except from hole apply **/ private void generateNoHoleOperation(Polyline p, ExtrusionOperations op) { //Check each different operation one by one int duration; if (op.directionOperation().needGenerate()) { Vector3 newDirection = generateDirection(p); if (newDirection != Vector3.zero) //Valid direction found { duration = generateFromRange(directionExtrBase, directionExtrDesv); op.directionOperation().forceOperation(duration, newDirection); op.directionOperation().setWait(duration + generateFromRange(directionKBase, directionKDesv)); IntersectionsController.Instance.addActualBox(); IntersectionsController.Instance.addPolyline(p); //op.setCanIntersect (-1); op.setCanIntersect(IntersectionsController.Instance.getLastBB()); } } if (op.scaleOperation().needGenerate()) { duration = generateFromRange(scaleExtrBase, scaleExtrDesv); op.scaleOperation().forceOperation(duration, Mathf.Pow(generateScale(), 1 / (float)duration)); op.scaleOperation().setWait(duration + generateFromRange(scaleKBase, scaleKDesv)); } if (op.rotateOperation().needGenerate()) { duration = generateFromRange(rotationExtrBase, rotationExtrDesv); op.rotateOperation().forceOperation(duration, generateRotation() / duration); op.rotateOperation().setWait(duration + generateFromRange(rotationKBase, rotationKDesv)); } if (op.stalagmiteOperation().needGenerate()) { //TODO:Generate all types of stalagmites, add more than one stalagmite at a time int type = Random.Range(0, 17); duration = generateFromRange(stalgmExtrBase, stalgmExtrDesv); if (type < 7) { op.stalagmiteOperation().forceOperation(duration, ExtrusionOperations.stalgmOp.Stalagmite); } else if (type < 13) { op.stalagmiteOperation().forceOperation(duration, ExtrusionOperations.stalgmOp.Stalactite); } else { op.stalagmiteOperation().forceOperation(duration, ExtrusionOperations.stalgmOp.Pillar); } op.stalagmiteOperation().setWait(duration + generateFromRange(stalgmKBase, stalgmKDesv)); } /*if (op.pointLightOperation().needGenerate()) { * op.pointLightOperation().forceOperation(1,true); * op.pointLightOperation().setWait(1 + generateFromRange (pointLightKBase, pointLightKDesv)); * }*/ //TODO: add stones, grass,... }
/**Clone creator **/ public ExtrusionOperations(ExtrusionOperations original) { distance = new Operation <float> (original.distance); direction = new LerpOperation(original.direction); scale = new Operation <float> (original.scale); rotate = new Operation <float> (original.rotate); hole = original.hole; stalagmite = new Operation <stalgmOp>(original.stalagmite); //pointLight = new Operation<bool> (original.pointLight); canIntersect = original.canIntersect; }
//public int pointLightKBase = 12; //public int pointLightKDesv = 5; /** Generates a new operation instance, as it was the beggining of a tunnel **/ public ExtrusionOperations generateNewOperation(Polyline p) { ExtrusionOperations op = new ExtrusionOperations(); op.distanceOperation().forceOperation(1, DecisionGenerator.Instance.generateDistance(false)); op.directionOperation().forceOperation(0, p.calculateNormal(), p.calculateNormal()); op.setCanIntersect(IntersectionsController.Instance.getLastBB()); //op.scaleOperation().forceOperation (operationK,Mathf.Pow(2.0f,1/(float)operationK)); //Generate extrusion wait for each operation op.directionOperation().setWait(generateFromRange(directionKBase, directionKDesv)); op.scaleOperation().setWait(generateFromRange(scaleKBase, scaleKDesv)); op.rotateOperation().setWait(generateFromRange(rotationKBase, rotationKDesv)); op.stalagmiteOperation().setWait(generateFromRange(stalgmKBase, stalgmKDesv)); //op.pointLightOperation ().forceOperation (1, true); //op.pointLightOperation().setWait (1+generateFromRange (pointLightKBase, pointLightKDesv)); return(op); }
/**It creates a new polyline from an exsiting one, applying the corresponding operations**/ protected Polyline extrude(ExtrusionOperations operation, Polyline originPoly) { //Create the new polyline from the actual one Polyline newPoly = new Polyline(originPoly.getSize()); Vector3 direction = operation.directionOperation().apply(); float distance = operation.distanceOperation().apply(); //Generate the UVS of the new polyline from the coordinates of the original and on the same //same direction that the extrusion, as if it was a projection to XZ plane //Vector2 UVincr = new Vector2(direction.x,direction.z); Vector2 UVincr = new Vector2(0.0f, 1.0f); UVincr.Normalize(); UVincr *= (distance / UVfactor); for (int i = 0; i < originPoly.getSize(); ++i) //Generate the new vertices //Add vertex to polyline { newPoly.extrudeVertex(i, originPoly.getVertex(i).getPosition(), direction, distance); //Add the index to vertex newPoly.getVertex(i).setIndex(actualMesh.getNumVertices() + i); //Add UV newPoly.getVertex(i).setUV(originPoly.getVertex(i).getUV() + UVincr); } //Apply operations, if any if (operation.scaleOperation().needApply()) { newPoly.scale(operation.scaleOperation().apply()); } if (operation.rotateOperation().needApply()) { newPoly.rotate(operation.rotateOperation().apply()); } //Check there is no intersection if (IntersectionsController.Instance.doIntersect(originPoly, newPoly, operation.getCanIntersect())) { return(null); } return(newPoly); }
/**Decide which operations apply to the next extrusion **/ public void generateNextOperation(Polyline p, ExtrusionOperations op, int numExtrude, float tunnelProb, int holesCountdown) { //Change the distance always, in order to introduce more irregularity op.distanceOperation().forceOperation(1, generateDistance(false)); //Decide to make hole or not if (!op.holeOperation()) { op.forceHoleOperation(makeHole(numExtrude, tunnelProb, holesCountdown)); } //Decide which operations generate and apply on next extrusions generateNoHoleOperation(p, op); //Distance for hole case if (op.holeOperation()) { op.distanceOperation().forceOperation(1, generateDistance(true)); } //TODO: Distance for stalagmite case? //Update the wait counter op.decreaseWait(); }
public override IEnumerator generate(Polyline originPoly, float holeProb) { createDataStructure (gatePolyline); --maxHoles; Polyline newPoly; int actualExtrusionTimes, noIntersection; noIntersection = -1; while (isDataStructureEmpty()) { //new tunnel(hole) will be done, initialize all the data //Case base is implicit, as the operation generation takes into account the maxHoles variables in order to stop generating holes initializeDataStructure(ref noIntersection, ref originPoly); Geometry.Mesh m = initializeTunnel(ref originPoly); actualExtrusionTimes = 0; ExtrusionOperations operation = DecisionGenerator.Instance.generateNewOperation (originPoly); operation.setCanIntersect (noIntersection); //Add first polyline to the intersection BB IntersectionsController.Instance.addPolyline (originPoly); if (showGeneration) { gameObject.GetComponent<CaveGenerator> ().updateMeshes (this); gameObject.GetComponent<CaveGenerator> ().updateActualPolyline(originPoly.calculateBaricenter(), originPoly.calculateNormal()); yield return new WaitForSeconds(holeTime); } //Generate the tunnel while (actualExtrusionTimes <= maxExtrudeTimes) { ++actualExtrusionTimes; //In case the hole is finally not done, same operation will need to be applied ExtrusionOperations actualOpBackTrack = new ExtrusionOperations(operation); //Generate the new polyline applying the operation newPoly = extrude (operation, originPoly); if (newPoly == null) { //DecisionGenerator.Instance.generateNextOperation (ref operation, actualExtrusionTimes, holeProb); //operation = DecisionGenerator.Instance.generateNewOperation (originPoly); continue; } //Make hole? if (operation.holeOperation ()) { noIntersection = -1; operation.setCanIntersect (noIntersection); Polyline polyHole = makeHole (originPoly, newPoly); if (polyHole != null) {//Check the hole was done without problems addElementToDataStructure (polyHole, IntersectionsController.Instance.getLastBB () + 1); --maxHoles; } else { //No hole could be done, reextrude //Force to have little extrusion distance actualOpBackTrack.distanceOperation().forceOperation(1, DecisionGenerator.Instance.generateDistance (false)); //It can't be null if with bigger extrusion distance it wasn't already: if //with bigger distance it didn't intersect, it can't intersect with a smaller one newPoly = extrude (actualOpBackTrack, originPoly); operation = actualOpBackTrack; actualMesh.addPolyline (newPoly); } operation.forceHoleOperation (false); } else { //Adds the new polyline to the mesh, after all the changes previously done actualMesh.addPolyline (newPoly); } //Triangulate from origin to new polyline as a tube/cave shape actualMesh.triangulatePolylines (originPoly, newPoly); //Make stalagmite? if (!actualOpBackTrack.holeOperation() && operation.stalagmiteOperation ().needApply()) { makeStalagmite (operation.stalagmiteOperation().apply(), originPoly, newPoly); } //Make light? /*if (operation.pointLightOperation().needApply()) { operation.pointLightOperation().apply(); makePointLight(originPoly,newPoly); }*/ //Set next operation and continue from the new polyline originPoly = newPoly; //Add actual polyline to the next intersection BB ang get nexxt operation IntersectionsController.Instance.addPolyline(originPoly); DecisionGenerator.Instance.generateNextOperation(originPoly, operation,actualExtrusionTimes,holeProb, maxHoles); if (showGeneration) { gameObject.GetComponent<CaveGenerator> ().updateMeshes (this); gameObject.GetComponent<CaveGenerator> ().updateActualPolyline(originPoly.calculateBaricenter(), originPoly.calculateNormal()); yield return new WaitForSeconds(extrusionTime); } } //Duplicate last polyline, in order to avoid ugly results when smoothing a closed tunnel after hole originPoly = actualMesh.duplicatePoly (originPoly); IntersectionsController.Instance.addActualBox (); actualMesh.closePolyline(originPoly); holeProb -= 0.001f; } finished = true; gameObject.GetComponent<CaveGenerator> ().updateMeshes (this); }
public override IEnumerator generate(Polyline originPoly, float holeProb) { //Hole is done, update the counter --maxHoles; //Case base is implicit, as the operation generation takes into account the maxHoles variables in order to stop generating holes if (showGeneration) { //New hole, wait a bit to see the change gameObject.GetComponent <CaveGenerator> ().updateActualPolyline(originPoly.calculateBaricenter(), originPoly.calculateNormal()); yield return(new WaitForSeconds(holeTime)); } //TODO: change maxExtrudeTimes as holes are done (eg, random number between a rank) //Generate the actual hallway/tunnel Geometry.Mesh m = initializeTunnel(ref originPoly); ExtrusionOperations actualOperation = DecisionGenerator.Instance.generateNewOperation(originPoly); //Add initial polyline to the BB IntersectionsController.Instance.addPolyline(originPoly); for (int i = 0; i < maxExtrudeTimes; ++i) { //In case the hole is finally not done, same operation will need to be applied ExtrusionOperations actualOpBackTrack = new ExtrusionOperations(actualOperation); //Generate the new polyline applying the corresponding operation Polyline newPoly = extrude(actualOperation, originPoly); if (newPoly == null) //Intersection produced //TODO: improve this //DecisionGenerator.Instance.generateNextOperation(originPoly, ref actualOperation,i,holeProb); //actualOperation = DecisionGenerator.Instance.generateNewOperation (originPoly); { continue; } //Make hole? if (actualOperation.holeOperation()) { Polyline polyHole = makeHole(originPoly, newPoly); if (polyHole != null) //Check the hole was done without problems { IntersectionsController.Instance.addPolyline(newPoly); IntersectionsController.Instance.addActualBox(); actualOperation.setCanIntersect(IntersectionsController.Instance.getLastBB()); //Avoid intersection check with own extrusion BB if (showGeneration) { yield return(StartCoroutine(generate(polyHole, holeProb - 0.001f))); //Wait a bit to let the camera return the actual tunnel gameObject.GetComponent <CaveGenerator> ().updateActualPolyline(originPoly.calculateBaricenter(), originPoly.calculateNormal()); yield return(new WaitForSeconds(holeTime)); } else { StartCoroutine(generate(polyHole, holeProb - 0.001f)); } //IntersectionsController.Instance.addPolyline (originPoly); actualMesh = m; } else //No hole could be done, reextrude will smaller distance //Force to have little extrusion distance { actualOpBackTrack.distanceOperation().forceOperation(1, DecisionGenerator.Instance.generateDistance(false)); //It can't be null if with bigger extrusion distance it wasn't already: if //with bigger distance it didn't intersect, it can't intersect with a smaller one newPoly = extrude(actualOpBackTrack, originPoly); actualOperation = actualOpBackTrack; actualMesh.addPolyline(newPoly); } actualOperation.forceHoleOperation(false); } else { //Adds the new polyline to the mesh, after all the changes previously done actualMesh.addPolyline(newPoly); } //Triangulate from origin to new polyline as a tube/cave shape actualMesh.triangulatePolylines(originPoly, newPoly); //Make stalagmite? if (!actualOpBackTrack.holeOperation() && actualOperation.stalagmiteOperation().needApply()) { makeStalagmite(actualOperation.stalagmiteOperation().apply(), originPoly, newPoly); } //Make light? /*if (actualOperation.pointLightOperation().needApply()) { * actualOperation.pointLightOperation().apply(); * makePointLight(originPoly,newPoly); * }*/ //Set next operation and continue from the new polyline originPoly = newPoly; //Add actual polyline to the next intersection BB and get next operation IntersectionsController.Instance.addPolyline(originPoly); DecisionGenerator.Instance.generateNextOperation(originPoly, actualOperation, i, holeProb, maxHoles); if (showGeneration) { gameObject.GetComponent <CaveGenerator> ().updateMeshes(this); gameObject.GetComponent <CaveGenerator> ().updateActualPolyline(originPoly.calculateBaricenter(), originPoly.calculateNormal()); yield return(new WaitForSeconds(extrusionTime)); } //else do nothing } //Duplicate last polyline, in order to avoid ugly results when smoothing a closed tunnel after hole originPoly = actualMesh.duplicatePoly(originPoly); //Finally, close the actual hallway/tunnel IntersectionsController.Instance.addActualBox(); actualMesh.closePolyline(originPoly); if (m == proceduralMeshes [0]) { finished = true; gameObject.GetComponent <CaveGenerator> ().updateMeshes(this); } else if (showGeneration) { gameObject.GetComponent <CaveGenerator> ().updateMeshes(this); } }