Hi everyone
I hope someone can help me work out this issue for an educational project.
I have a model of a volcano, which has been textured. I can add a particle system to represent the smoke coming from the top. What I would like to do is to add lava to the slopes, according to the texture map. So, I create a new map and make it black and white. Lava = black. I would like for my lava particles appear only where there are black areas on the texture. I have found some code on the forum that can convert texture to particles, but from what I can tell it only does it as a flat image. I need it to follow the texture map on the model, in 3d. How could I adapt this code? I also don’t need it to animate, but would like for the particles to glow, so they only appear to be moving.
using UnityEngine;
using System.Collections;
public class ParticleShape : MonoBehaviour
{
public Texture2D shapeTexture;
public Vector3 scale = new Vector3(10, 10, 10);
private Vector3[] posEnd;
// initialize
void Start()
{
// store the end positions (one position for each particle we'll be spawning)
posEnd = new Vector3[CountOpaquePixels(shapeTexture)];
// keep track of which particle we're on
int i = 0;
// texture aspect ratio
float aspect = shapeTexture.width / shapeTexture.height;
// loop through each pixel in our texture
for (int x = 0; x < shapeTexture.width; x++)
{
for (int y = 0; y < shapeTexture.height; y++)
{
Color testColor = shapeTexture.GetPixel(x, y);
// only emit if we're opaque
if (testColor.a > 0)
{
// emit a particle (random initial position and velocity, use our pixel color, the two f numbers are particle size and how long they live)
particleEmitter.Emit(Random.insideUnitSphere * 1, Random.insideUnitSphere * 1, 0.5f, 100f, testColor);
// record the end position (standardized to 0-1 position)
posEnd[i] = new Vector3(0, (float)y / shapeTexture.height - 0.5f, ((float)x / shapeTexture.width - 0.5f) * aspect);
// scale according to user setting
posEnd[i].Scale(scale);
// increment our particle counter
i++;
}
}
}
// start our actual loop
StartCoroutine("SnapToPosition");
}
// in this example it just loops--but it demonstrates the idea!
IEnumerator SnapToPosition()
{
while (true)
{
// wait a bit
yield return new WaitForSeconds(0.0f);
// keep track of time and position (in a real script should make public variables) first number is how long we wait to show particles (if this number is larger than the seccond, then particles just appear), second number is how long it takes for the particles to get to their end state.
float timeElapsed = 1;
float timeLength = 0.5f;
float pos;
// hold the start/end position in these arrays
int length = particleEmitter.particles.Length;
Vector3[] posStart = new Vector3[length];
// set up the start of our cycle (start position)
Particle[] particles = particleEmitter.particles;
for (int i = 0; i < particles.Length; i++)
{
// start position
posStart[i] = particles[i].position;
// stop our particles from moving
particles[i].velocity = Vector3.zero;
}
// loop for our collapse animation
bool go = true;
while (go)
{
// how far into our cycle
pos = timeElapsed / timeLength;
// we're using a boolean to do one last iteration with pos=1
if (pos >= 1.0f)
{
go = false;
pos = 1;
}
// loop all of our particles and update positions
particles = particleEmitter.particles;
for (int i = 0; i < particles.Length; i++)
{
particles[i].position = Vector3.Lerp(posStart[i], posEnd[i], pos);
particles[i].velocity = Vector3.zero;
}
particleEmitter.particles = particles;
// wait a frame
yield return 0;
}
particleEmitter.particles = particles;
}
}
// count the number of non-transparent pixels in a texture
int CountOpaquePixels(Texture2D texture)
{
int count = 0;
for (int x = 0; x < texture.width; x++)
for (int y = 0; y < texture.height; y++)
if (texture.GetPixel(x, y).a > 0)
count++;
return count;
}
}