// EVALUATE // // override public void Evaluate() { Vector4 customVector; Vector3 position; Vector3 pivotOffset; Vector3 rotation; Quaternion quaternionRotation; Vector3 scale; Color color; bool shouldRecreateMesh; bool shouldBeDoubleSided; Quaternion camFacingRotation; int vertexIndexSteps; int triangleIndexSteps; if (ownerBlueprint == null || ownerBlueprint.ownerEmitter == null || ownerBlueprint.ownerEmitter.particleMarkers == null) { return; // To fix null ref log spam after script rebuild. } if (finalMesh == null) { SoftReset(); } ownerBlueprint.ownerEmitter.activeParticleIndices = ownerBlueprint.ownerEmitter.particleMarkers.GetActiveIndices(); particleCount = ownerBlueprint.ownerEmitter.activeParticleIndices.Length; shouldRecreateMesh = (particleCount != lastParticleCount); shouldBeDoubleSided = isDoubleSided.GetValue(); if (shouldBeDoubleSided) { vertexIndexSteps = 8; triangleIndexSteps = 12; } else { vertexIndexSteps = 4; triangleIndexSteps = 6; } // TODO: Investigate why this line fails at runtime around 2 * 4: //shouldRecreateMesh = triangles.Length != particleCount * vertexIndexSteps; if (shouldRecreateMesh) { finalMesh.Clear(); vertices = new Vector3[particleCount * vertexIndexSteps]; normals = new Vector3[particleCount * vertexIndexSteps]; tangents = new Vector4[particleCount * vertexIndexSteps]; uvs = new Vector2[particleCount * vertexIndexSteps]; uv2s = new Vector2[particleCount * vertexIndexSteps]; colors = new Color[particleCount * vertexIndexSteps]; triangles = new int[particleCount * triangleIndexSteps]; lastParticleCount = particleCount; } int particleIndex; for (int i = 0; i < ownerBlueprint.ownerEmitter.activeParticleIndices.Length; i++) { particleIndex = ownerBlueprint.ownerEmitter.activeParticleIndices[i]; customVector = ownerBlueprint.customVectorStack.values[particleIndex]; position = AmpsHelpers.ConvertVector4Vector3(ownerBlueprint.ownerEmitter.blueprint.positionStack.values[particleIndex]); // Raw position stack result. position = AmpsHelpers.RotateAroundPoint(position, ownerBlueprint.ownerEmitter.transform.position, Quaternion.Inverse(ownerBlueprint.ownerEmitter.transform.rotation)); position -= ownerBlueprint.ownerEmitter.emitterPosition; // Compensating for emitter position, turning position world relative. pivotOffset = AmpsHelpers.ConvertVector4Vector3(ownerBlueprint.pivotOffsetStack.values[particleIndex]); rotation = AmpsHelpers.ConvertVector4Vector3(ownerBlueprint.rotationStack.values[particleIndex]); // Raw particle stack result. quaternionRotation = Quaternion.Inverse(ownerBlueprint.ownerEmitter.transform.rotation) * Quaternion.Euler(rotation); scale = AmpsHelpers.ConvertVector4Vector3(ownerBlueprint.scaleStack.values[particleIndex]); color = ownerBlueprint.colorStack.values[particleIndex]; // Setting up the quad, particle is at the center. vertices[i * vertexIndexSteps] = (position + pivotOffset) + (new Vector3(scale.x, scale.y, 0) / 2); vertices[i * vertexIndexSteps + 1] = (position + pivotOffset) + (new Vector3(-scale.x, scale.y, 0) / 2); vertices[i * vertexIndexSteps + 2] = (position + pivotOffset) + (new Vector3(-scale.x, -scale.y, 0) / 2); vertices[i * vertexIndexSteps + 3] = (position + pivotOffset) + (new Vector3(scale.x, -scale.y, 0) / 2); switch (orientation.GetValue()) { case (int)eOrientation.Rotated: // Rotating the (pivot offset) vertices around particle position. vertices[i * vertexIndexSteps] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps], position, quaternionRotation); vertices[i * vertexIndexSteps + 1] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps + 1], position, quaternionRotation); vertices[i * vertexIndexSteps + 2] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps + 2], position, quaternionRotation); vertices[i * vertexIndexSteps + 3] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps + 3], position, quaternionRotation); break; case (int)eOrientation.CameraFacing: camFacingRotation = Quaternion.LookRotation(ownerBlueprint.ownerEmitter.currentCameraTransform.forward, ownerBlueprint.ownerEmitter.currentCameraTransform.up); camFacingRotation = Quaternion.Inverse(ownerBlueprint.ownerEmitter.transform.rotation) * camFacingRotation; // TODO: Research if camera-particle position diff vector is better. // Rotating all vertices around the center so the quad faces the camera. vertices[i * vertexIndexSteps] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps], position, camFacingRotation); vertices[i * vertexIndexSteps + 1] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps + 1], position, camFacingRotation); vertices[i * vertexIndexSteps + 2] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps + 2], position, camFacingRotation); vertices[i * vertexIndexSteps + 3] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps + 3], position, camFacingRotation); break; case (int)eOrientation.RotatedCameraFacing: camFacingRotation = Quaternion.LookRotation(ownerBlueprint.ownerEmitter.currentCameraTransform.forward, ownerBlueprint.ownerEmitter.currentCameraTransform.up); camFacingRotation = Quaternion.Inverse(ownerBlueprint.ownerEmitter.transform.rotation) * camFacingRotation; camFacingRotation = camFacingRotation * Quaternion.Euler(rotation); // Rotating all vertices around the center so the quad faces the camera. vertices[i * vertexIndexSteps] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps], position, camFacingRotation); vertices[i * vertexIndexSteps + 1] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps + 1], position, camFacingRotation); vertices[i * vertexIndexSteps + 2] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps + 2], position, camFacingRotation); vertices[i * vertexIndexSteps + 3] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps + 3], position, camFacingRotation); break; case (int)eOrientation.VectorAlignedCameraFacing: //Vector3 upVector = Vector3.Normalize(alignmentVector.GetValue()); //Vector3 forwardVector = ownerBlueprint.ownerEmitter.currentCameraTransform.forward; ////ownerBlueprint.ownerEmitter.currentCameraTransform.up; //camFacingRotation = Quaternion.LookRotation(forwardVector, upVector); ////camFacingRotation = Quaternion.Inverse(ownerBlueprint.ownerEmitter.transform.rotation) * camFacingRotation; camFacingRotation = Quaternion.LookRotation(ownerBlueprint.ownerEmitter.currentCameraTransform.forward, Vector3.up); Vector3 eulerRotation = camFacingRotation.eulerAngles; eulerRotation.x = 0; // Discard rotation around x. eulerRotation.z = 0; // Discard rotation around z. camFacingRotation = Quaternion.Euler(eulerRotation); // Rotating all vertices around the center so the quad faces the camera. vertices[i * vertexIndexSteps] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps], position, camFacingRotation); vertices[i * vertexIndexSteps + 1] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps + 1], position, camFacingRotation); vertices[i * vertexIndexSteps + 2] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps + 2], position, camFacingRotation); vertices[i * vertexIndexSteps + 3] = AmpsHelpers.RotateAroundPoint(vertices[i * vertexIndexSteps + 3], position, camFacingRotation); break; } if (shouldBeDoubleSided) { vertices[i * vertexIndexSteps + 4] = vertices[i * vertexIndexSteps]; vertices[i * vertexIndexSteps + 5] = vertices[i * vertexIndexSteps + 1]; vertices[i * vertexIndexSteps + 6] = vertices[i * vertexIndexSteps + 2]; vertices[i * vertexIndexSteps + 7] = vertices[i * vertexIndexSteps + 3]; } colors[i * vertexIndexSteps] = color; colors[i * vertexIndexSteps + 1] = color; colors[i * vertexIndexSteps + 2] = color; colors[i * vertexIndexSteps + 3] = color; if (shouldBeDoubleSided) { if ((eDoubleSidedColorMode)doubleSidedColorMode.GetValue() == eDoubleSidedColorMode.ColorStack) { colors[i * vertexIndexSteps + 4] = colors[i * vertexIndexSteps]; colors[i * vertexIndexSteps + 5] = colors[i * vertexIndexSteps + 1]; colors[i * vertexIndexSteps + 6] = colors[i * vertexIndexSteps + 2]; colors[i * vertexIndexSteps + 7] = colors[i * vertexIndexSteps + 3]; } else { colors[i * vertexIndexSteps + 4] = customVector; colors[i * vertexIndexSteps + 5] = customVector; colors[i * vertexIndexSteps + 6] = customVector; colors[i * vertexIndexSteps + 7] = customVector; } } switch (normalMode.GetValue()) { case (int)eNormalMode.Skip: break; case (int)eNormalMode.Flat: Vector3 calculatedNormal = Vector3.Cross((vertices[i * vertexIndexSteps + 2] - vertices[i * vertexIndexSteps]), (vertices[i * vertexIndexSteps + 1] - vertices[i * vertexIndexSteps])); calculatedNormal = Vector3.Normalize(calculatedNormal); normals[i * vertexIndexSteps] = calculatedNormal; normals[i * vertexIndexSteps + 1] = calculatedNormal; normals[i * vertexIndexSteps + 2] = calculatedNormal; normals[i * vertexIndexSteps + 3] = calculatedNormal; break; } if (shouldBeDoubleSided) { normals[i * vertexIndexSteps + 4] = normals[i * vertexIndexSteps] * -1; normals[i * vertexIndexSteps + 5] = normals[i * vertexIndexSteps + 1] * -1; normals[i * vertexIndexSteps + 6] = normals[i * vertexIndexSteps + 2] * -1; normals[i * vertexIndexSteps + 7] = normals[i * vertexIndexSteps + 3] * -1; } switch (uv2Mode.GetValue()) { case (int)eUV2Mode.Skip: break; case (int)eUV2Mode.CustomVectorXY: uv2s[i * vertexIndexSteps] = new Vector2(customVector.x, customVector.y); uv2s[i * vertexIndexSteps + 1] = new Vector2(customVector.x, customVector.y); uv2s[i * vertexIndexSteps + 2] = new Vector2(customVector.x, customVector.y); uv2s[i * vertexIndexSteps + 3] = new Vector2(customVector.x, customVector.y); break; case (int)eUV2Mode.CustomVectorXYZW: // BUG: Doesn't really work... Vector2 calculatedUv2 = Vector2.zero; calculatedUv2.x = AmpsHelpers.PackVector2(new Vector2(customVector.x, customVector.y)); calculatedUv2.y = AmpsHelpers.PackVector2(new Vector2(customVector.z, customVector.w)); uv2s[i * vertexIndexSteps] = calculatedUv2; uv2s[i * vertexIndexSteps + 1] = calculatedUv2; uv2s[i * vertexIndexSteps + 2] = calculatedUv2; uv2s[i * vertexIndexSteps + 3] = calculatedUv2; break; } if (shouldBeDoubleSided) { uv2s[i * vertexIndexSteps + 4] = uv2s[i * vertexIndexSteps]; uv2s[i * vertexIndexSteps + 5] = uv2s[i * vertexIndexSteps + 1]; uv2s[i * vertexIndexSteps + 6] = uv2s[i * vertexIndexSteps + 2]; uv2s[i * vertexIndexSteps + 7] = uv2s[i * vertexIndexSteps + 3]; } switch (tangentMode.GetValue()) { case (int)eTangentMode.Skip: break; case (int)eTangentMode.Generate: //Vector3 rawTangent = Vector3.Normalize(vertices[i * 4 + 3] - vertices[i * 4 + 1]); Vector3 rawTangent = Vector3.Normalize(vertices[i * 4 + 0] - vertices[i * 4 + 1]); Vector4 calculatedTangent = new Vector4(rawTangent.x, rawTangent.y, rawTangent.z, -1); tangents[i * vertexIndexSteps] = calculatedTangent; tangents[i * vertexIndexSteps + 1] = calculatedTangent; tangents[i * vertexIndexSteps + 2] = calculatedTangent; tangents[i * vertexIndexSteps + 3] = calculatedTangent; break; case (int)eTangentMode.CustomVectorXYZW: tangents[i * vertexIndexSteps] = customVector; tangents[i * vertexIndexSteps + 1] = customVector; tangents[i * vertexIndexSteps + 2] = customVector; tangents[i * vertexIndexSteps + 3] = customVector; break; } if (shouldBeDoubleSided) { // TODO: Should it be multiplied by -1? tangents[i * vertexIndexSteps + 4] = tangents[i * vertexIndexSteps]; tangents[i * vertexIndexSteps + 5] = tangents[i * vertexIndexSteps + 1]; tangents[i * vertexIndexSteps + 6] = tangents[i * vertexIndexSteps + 2]; tangents[i * vertexIndexSteps + 7] = tangents[i * vertexIndexSteps + 3]; } if (shouldRecreateMesh) // Things go in here which don't change unless particle count changes. { uvs[i * vertexIndexSteps] = new Vector2(1, 1); uvs[i * vertexIndexSteps + 1] = new Vector2(0, 1); uvs[i * vertexIndexSteps + 2] = new Vector2(0, 0); uvs[i * vertexIndexSteps + 3] = new Vector2(1, 0); if (shouldBeDoubleSided) { uvs[i * vertexIndexSteps + 4] = new Vector2(1, 1); uvs[i * vertexIndexSteps + 5] = new Vector2(0, 1); uvs[i * vertexIndexSteps + 6] = new Vector2(0, 0); uvs[i * vertexIndexSteps + 7] = new Vector2(1, 0); } //First triangle. triangles[i * triangleIndexSteps] = i * vertexIndexSteps; triangles[i * triangleIndexSteps + 1] = i * vertexIndexSteps + 2; triangles[i * triangleIndexSteps + 2] = i * vertexIndexSteps + 1; //Second triangle. triangles[i * triangleIndexSteps + 3] = i * vertexIndexSteps + 2; triangles[i * triangleIndexSteps + 4] = i * vertexIndexSteps; triangles[i * triangleIndexSteps + 5] = i * vertexIndexSteps + 3; if (shouldBeDoubleSided) { //Third triangle. triangles[i * triangleIndexSteps + 6] = i * vertexIndexSteps + 5; triangles[i * triangleIndexSteps + 7] = i * vertexIndexSteps + 6; triangles[i * triangleIndexSteps + 8] = i * vertexIndexSteps + 4; //Forth triangle. triangles[i * triangleIndexSteps + 9] = i * vertexIndexSteps + 7; triangles[i * triangleIndexSteps + 10] = i * vertexIndexSteps + 4; triangles[i * triangleIndexSteps + 11] = i * vertexIndexSteps + 6; } } } // TODO: Bubble sort with limited run time. finalMesh.vertices = vertices; finalMesh.uv = uvs; finalMesh.uv2 = uv2s; finalMesh.normals = normals; finalMesh.tangents = tangents; finalMesh.colors = colors; finalMesh.triangles = triangles; }