IEnumerator meshAnimationOptimized() { //It is important to create a copy of the vertices and only use "inputMesh.vertices" only once // since this is a get function. Meaning in every call of the function the mesh will be copied. Vector3[] inputVertices = InputMesh.vertices; int numberOfVertices = inputVertices.Length; //We look at our input being 2 dimensional. One dimension is the number of vertices, //the other dimension is the vector x,y,z //We create lines for the first dimension the number of vertices int numberOfVertexCubits = Mathf.CeilToInt(Mathf.Log(numberOfVertices) / Mathf.Log(2)); //The lines are needed to encode the data in a way that encoding of neighbouring vertices only differ in 1 bit int[] linesVertices = QuantumImageHelper.MakeLinesInt(numberOfVertexCubits); //We create lines for the second dimension the vector x,y,z so there are only 3 values (thats where the 3 comes from). //The 2 is to transform the thing to base 2 since we need the logarithm in base 2. int numberOfVectorQubits = Mathf.CeilToInt(Mathf.Log(3) / Mathf.Log(2)); //The lines are needed to encode the data in a way that the encoding of x and y as well as y and z only differ in 1 bit. int[] linesVector = QuantumImageHelper.MakeLinesInt(numberOfVectorQubits); //Creating a circuit big enough to fit in the mesh data int numberOfQubits = numberOfVertexCubits + numberOfVectorQubits; QuantumCircuit circuit = new QuantumCircuit(numberOfQubits, numberOfQubits, true); //Since we work with probabilities, we need the values to be positive (or 0). //Therefore we want to translate the values adding an offset to our values, such that they become positive. //Getting the smallest (most negative) values to use for the displacement //initiate values as 0 float minX = 0; float minY = 0; float minZ = 0; for (int i = 0; i < inputVertices.Length; i++) { if (inputVertices[i].x < minX) { minX = inputVertices[i].x; } if (inputVertices[i].y < minY) { minY = inputVertices[i].y; } if (inputVertices[i].z < minZ) { minZ = inputVertices[i].z; } } //Needed to transform the position of our 2 dimensions mentioned above into a single array. //The indexes look like this: 0_X, 0_Y, 0_Z, 0_?, 1_X, 1_Y, 1_Z.... Where 0,1 etc stand for the vertex number //X,Y,Z stands for the respective coordinates and ? is just a placeholder which is not really needed (but we need to have a power of 2 so 4 values for our 3) int maxHeight = linesVector.Length; for (int i = 0; i < numberOfVertices; i++) { //We use the lines produced above to calculate the new position int index = linesVertices[i] * maxHeight; //We interpret the values as probabilities. And the amplitudes are the square root of the probabilities. circuit.Amplitudes[index + linesVector[0]].Real = Math.Sqrt(inputVertices[i].x - minX); circuit.Amplitudes[index + linesVector[1]].Real = Math.Sqrt(inputVertices[i].y - minY); circuit.Amplitudes[index + linesVector[2]].Real = Math.Sqrt(inputVertices[i].z - minZ); } //We need to normalize the circuit, since probabilities should add up to 1. //We store the factor used for normalization in order to reverse this scaling later. circuit.Normalize(); double normalizationFactor = circuit.OriginalSum; //We don't want to allocate as phew memory as possible in order to minimize garbage collection //Therefore, we reuse the defined arrays double[] realAmplitudes = new double[circuit.AmplitudeLength]; Vector3[] outPutVertices = new Vector3[numberOfVertices]; //Making a copy of the amplitudes of the circuit for (int i = 0; i < circuit.AmplitudeLength; i++) { realAmplitudes[i] = circuit.Amplitudes[i].Real; } //Creating a new mesh, at this point it is just a copy of the input mesh Mesh outputMesh = new Mesh(); outputMesh.name = InputMesh.name + " blurred"; outputMesh.vertices = inputVertices; outputMesh.triangles = InputMesh.triangles; outputMesh.uv = InputMesh.uv; outputMesh.RecalculateNormals(); outputMesh.RecalculateTangents(); MicroQiskitSimulator simulator = new MicroQiskitSimulator(); double[] probs = new double[circuit.AmplitudeLength]; //simulator.GetProbabilities(circuit); ComplexNumber[] amplitudes = new ComplexNumber[circuit.AmplitudeLength]; //Setting the new mesh to the target //We can now just manipulate the vertices of this mesh in order to change it. //No need to create new meshes TargetMesh.sharedMesh = outputMesh; OutputMesh = outputMesh; float rotation = 0.0f; float progress = 0; //Making sure to have no endless loop if (Duration <= 0) { Duration = 1; } //Creating an animation by blurring the mesh step by step //Duration is the duration of the animation, StartRotation and Endrotation give //The starting points and endpoints of the animation the rest is interpolated. while (progress < 1) { //Calculating progress for the animation progress += Time.deltaTime / Duration; //Rotation is interpolated between endRotation and startRtoation depending on progress rotation = progress * EndRotation + (1 - progress) * StartRotation; //Resetting the circuit (deleting the gates) circuit.ResetGates(); //Reusing the circuit by filling in the original values before the calculation again for (int i = 0; i < circuit.AmplitudeLength; i++) { circuit.Amplitudes[i].Real = realAmplitudes[i]; } //Applying the operation to the circuit (the blur effect) ApplyPartialQ(circuit, rotation); //Calculating probabilities simulator.CalculateProbabilities(circuit, ref probs, ref amplitudes); //Filling in the new calculated values into the vertices for (int i = 0; i < numberOfVertices; i++) { int index = linesVertices[i] * maxHeight; //Since we have probabilities already we do not need to square them. //We undo the normalization from above and the translation (offset) from the beginning outPutVertices[i].x = (float)(probs[index + linesVector[0]] * normalizationFactor) + minX; outPutVertices[i].y = (float)(probs[index + linesVector[1]] * normalizationFactor) + minY; outPutVertices[i].z = (float)(probs[index + linesVector[2]] * normalizationFactor) + minZ; } //We set the new vertices to the mesh, this way the mesh changes its form automatically //and we do not need to construct a new mesh. outputMesh.vertices = outPutVertices; //wait until next frame. yield return(null); } // Reverse animation going back to startRotation if (reverseAnimation) { while (progress > 0) { //Calculating progress for the animation going back progress -= Time.deltaTime / Duration; //Rotation is interpolated between endRotation and startRtoation depending on progress rotation = progress * EndRotation + (1 - progress) * StartRotation; //Resetting the circuit (deleting the gates) circuit.ResetGates(); //Reusing the circuit by filling in the original values before the calculation again for (int i = 0; i < circuit.AmplitudeLength; i++) { circuit.Amplitudes[i].Real = realAmplitudes[i]; } //Applying the operation to the circuit (the blur effect) ApplyPartialQ(circuit, rotation); //Calculating probabilities simulator.CalculateProbabilities(circuit, ref probs, ref amplitudes); //Filling the new calculated values into the vertices for (int i = 0; i < numberOfVertices; i++) { int index = linesVertices[i] * maxHeight; //Since we have probabilities already we do not need to square them. //We undo the normalization from above and the translation (offset) from the beginning outPutVertices[i].x = (float)(probs[index + linesVector[0]] * normalizationFactor) + minX; outPutVertices[i].y = (float)(probs[index + linesVector[1]] * normalizationFactor) + minY; outPutVertices[i].z = (float)(probs[index + linesVector[2]] * normalizationFactor) + minZ; } outputMesh.vertices = outPutVertices; //We set the new vertices to the mesh, this way the mesh changes its form automatically //and we do not need to construct a new mesh.outputMesh.vertices = outPutVertices; //wait until next frame. yield return(null); } } }
/// <summary> /// Creates a blurred version of the input mesh, according to the rotation. The bigger the rotation the stronger the blur effect. /// The model gets unrecognizeable as soon as the rotation gets to big /// </summary> /// <param name="inputMesh">The mesh to produce a blurred version of.</param> /// <param name="rotation">Can be between 0 and 3.1415 (pi). For starting 0.1 would be a good value.</param> /// <returns>A blurred (distorted) mesh of the original input mesh. </returns> public Mesh CreateBluredMesh(Mesh inputMesh, float rotation) { //It is important to create a copy of the vertices and only use "inputMesh.vertices" only once // since this is a get function. Meaning in every call of the function the mesh will be copied. Vector3[] vertices = inputMesh.vertices; int numberOfVertices = vertices.Length; //We look at our input being 2 dimensional. One dimension is the number of vertices, //the other dimension is the vector x,y,z //We create lines for the first dimension the number of vertices int numberOfVertexCubits = Mathf.CeilToInt(Mathf.Log(numberOfVertices) / Mathf.Log(2)); //The lines are needed to encode the data in a way that encoding of neighbouring vertices only differ in 1 bit int[] linesVertices = QuantumImageHelper.MakeLinesInt(numberOfVertexCubits); //We create lines for the second dimension the vector x,y,z so there are only 3 values (thats where the 3 comes from). //The 2 is to transform the thing to base 2 since we need the logarithm in base 2. int numberOfVectorQubits = Mathf.CeilToInt(Mathf.Log(3) / Mathf.Log(2)); //The lines are needed to encode the data in a way that the encoding of x and y as well as y and z only differ in 1 bit. int[] linesVector = QuantumImageHelper.MakeLinesInt(numberOfVectorQubits); //Creating a circuit big enough to fit in the mesh data int numberOfQubits = numberOfVertexCubits + numberOfVectorQubits; QuantumCircuit circuit = new QuantumCircuit(numberOfQubits, numberOfQubits, true); //Since we work with probabilities, we need the values to be positive (or 0). //Therefore we want to translate the values adding an offset to our values, such that they become positive. //Getting the smallest (most negative) values to use for the displacement //initiate values as 0 float minX = 0; float minY = 0; float minZ = 0; for (int i = 0; i < vertices.Length; i++) { if (vertices[i].x < minX) { minX = vertices[i].x; } if (vertices[i].y < minY) { minY = vertices[i].y; } if (vertices[i].z < minZ) { minZ = vertices[i].z; } } //Needed to transform the position of our 2 dimensions mentioned above into a single array. //The indexes look like this: 0_X, 0_Y, 0_Z, 0_?, 1_X, 1_Y, 1_Z.... Where 0,1 etc stand for the vertex number //X,Y,Z stands for the respective coordinates and ? is just a placeholder which is not really needed (but we need to have a power of 2 so 4 values for our 3) int maxHeight = linesVector.Length; for (int i = 0; i < numberOfVertices; i++) { //We use the lines produced above to calculate the new position int index = linesVertices[i] * maxHeight; //We interpret the values as probabilities. And the amplitudes are the square root of the probabilities. circuit.Amplitudes[index + linesVector[0]].Real = Math.Sqrt(vertices[i].x - minX); circuit.Amplitudes[index + linesVector[1]].Real = Math.Sqrt(vertices[i].y - minY); circuit.Amplitudes[index + linesVector[2]].Real = Math.Sqrt(vertices[i].z - minZ); } //We need to normalize the circuit, since probabilities should add up to 1. //We store the factor used for normalization in order to reverse this scaling later. circuit.Normalize(); double normalizationFactor = circuit.OriginalSum; //We apply the effect to the circuit. Here this is the normal blur effect also used in the images. ApplyPartialQ(circuit, rotation); //Calculating the probabilities after having applied the operation above SimulatorBase simulator = new MicroQiskitSimulator(); //MicroQiskitSimulator simulator = new MicroQiskitSimulator(); //QiskitSimulator simulator = new QiskitSimulator(); double[] probs = simulator.GetProbabilities(circuit); //Fill in the new calculated values back into the vertices for (int i = 0; i < numberOfVertices; i++) { int index = linesVertices[i] * maxHeight; //Since we have probabilities already we do not need to square them. //We undo the normalization from above and the translation (offset) from the beginning vertices[i].x = (float)(probs[index + linesVector[0]] * normalizationFactor) + minX; vertices[i].y = (float)(probs[index + linesVector[1]] * normalizationFactor) + minY; vertices[i].z = (float)(probs[index + linesVector[2]] * normalizationFactor) + minZ; } //creating the new mesh Mesh outputMesh = new Mesh(); //setting the newly calculated vertices outputMesh.vertices = vertices; //Copying most stuff from original mesh outputMesh.name = inputMesh.name + " blurred"; outputMesh.triangles = inputMesh.triangles; outputMesh.uv = inputMesh.uv; //Recalculating normals for correct lighning outputMesh.RecalculateNormals(); //returning the mesh return(outputMesh); }