naprawa algorytmu rysowania ognia, problem

naprawa algorytmu rysowania ognia, problem
wilkwielki
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 678
0

mam problem z funkcją rysowania ognia, a mianowicie do rozdzielczości 256x256 jest dobrze a jak np zwiększe na 512x256 to zamiast namalować szerszy to dubluje obraz w poziomie co jest źle z tym algorytmem, image to tło a pixels wynik wyjściowy:

Kopiuj
void generate_fire_frame(unsigned char* image,unsigned char* &pixels, int width, int height)
{
	// minimalne sprawdzenia
	if (!pixels || width < 2 || height < 2) return;

	// statyczne struktury by zachować stan między wywołaniami
	static std::vector<uint8_t> heat;
	static std::vector<uint8_t> palette; // 256 * 3
	static std::mt19937 rng((unsigned)std::random_device{}());
	static std::uniform_int_distribution<int> smallRand(0, 2);
	static std::uniform_int_distribution<int> baseRand(160, 255);

	// (re)alokacja przy zmianie rozmiaru
	if ((int)heat.size() != width * height) {
		heat.assign(width * height, 0);
	}
	
	if (palette.size() != 256 * 3) {
		palette.resize(256 * 3);
		// prosta paleta: black -> red -> yellow -> white
		for (int i = 0; i < 256; ++i) {
			float t = i / 255.0f;
			uint8_t r, g, b;
			if (t < 0.33f) {
				// black -> red
				float u = t / 0.33f;
				r = (uint8_t)(u * 255.0f);
				g = 0;
				b = 0;
			}
			else if (t < 0.66f) {
				// red -> yellow (increase green)
				float u = (t - 0.33f) / 0.33f;
				r = 255;
				g = (uint8_t)(u * 255.0f);
				b = 0;
			}
			else {
				// yellow -> white (increase blue)
				float u = (t - 0.66f) / (1.0f - 0.66f);
				r = 255;
				g = 255;
				b = (uint8_t)(u * 255.0f);
			}
			palette[i * 3 + 0] = r;
			palette[i * 3 + 1] = g;
			palette[i * 3 + 2] = b;
		}
	}

	// --- 1) Odśwież dolny wiersz (źródło ognia) ---
	// Można modyfikować intensywność bazową
	int bottom = (height - 1) * width;
	for (int x = 0; x < width; ++x) {
		// losujemy podstawową siłę płomienia w dolnym wierszu
		heat[bottom + x] = (uint8_t)baseRand(rng);
	}

	// --- 2) Propagacja: rozprzestrzenianie w górę z lekkim rozpylaniem ---
	// Dla każdego piksela od dna-1 do góry:
	for (int y = height - 2; y >= 0; --y) {
		int row = y * width;
		int rowBelow = (y + 1) * width;
		for (int x = 0; x < width; ++x) {
			// weź wartość spodem i zastosuj decay (0..2)
			int belowVal = heat[rowBelow + x];
			int decay = smallRand(rng);
			int v = belowVal - decay;
			if (v < 0) v = 0;

			// rozprosz (spread) - przesunięcie docelowe na boki
			int shift = smallRand(rng) - 1; // -1,0,1
			int dstX = x + shift;
			if (dstX < 0) dstX = 0;
			if (dstX >= width) dstX = width - 1;

			heat[row + dstX] = (uint8_t)v;
		}
	}

	// --- 3) Mapowanie heat -> RGB do bufora pixels ---
	// pixels jest w porządku RGB, równe width*height*3
	for (int i = 0; i < width * height; ++i) {
		uint8_t h = heat[i];
		float alpha = h / 255.0f;
		int idx = i * 3;

		unsigned char r = palette[h * 3 + 0];
		unsigned char g = palette[h * 3 + 1];
		unsigned char b = palette[h * 3 + 2];

		// mieszanie ognia z tłem
		pixels[idx + 2] = (unsigned char)(r * alpha + image[idx + 2] * (1 - alpha));
		pixels[idx + 1] = (unsigned char)(g * alpha + image[idx + 1] * (1 - alpha));
		pixels[idx + 0] = (unsigned char)(b * alpha + image[idx + 0] * (1 - alpha));
	}
}
wilkwielki
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 678
0

nomralnie 256x256
screenshot-20251104075727.png
a przy 512x256 jest tak:
screenshot-20251104075806.png

LukeJL
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 8487
0

a mianowicie do rozdzielczości 256x256 jest dobrze a jak np zwiększe na 512x256 to zamiast namalować szerszy to dubluje obraz w poziomie co jest źle z tym algorytmem, image to tło a pixels wynik wyjściowy:

Zobacz, czy nie pomyliłeś nigdzie w kodzie szerokości z wysokością. Bo możliwe, że przy kwadracie to nie będzie odczuwalne (skoro wysokość=szerokość), ale jak zmieniasz, że szerokość jest 512, a jeśli program liczyłby 256, to w rezultacie może się tak zdarzyć, że zamiast iść do góry, do kolejnego rzędu, będzie przerabiać kolejne kolumny. Stąd będzie się wydawać, że dubluje obraz.

No ale tak zgaduję, próbując sobie to wyobrazić na podstawie moich własnych doświadczeń z tego typu algorytmami i objawów, które podałeś. Natomiast patrząc w kod, nie potrafię zweryfikować tej hipotezy, więc nie wiem.

wilkwielki
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 678
0
Kopiuj
	int w = 256;
	int h = 256;
	unsigned char* timage = new unsigned char[w * h * 3];
	unsigned char* timageB = new unsigned char[w * h * 3];
	draw.GetDataFragmentDrawBuffor(300, 512, w, h, timageB);
	generate_fire_frame(timageB,timage, w, h);
	draw.CopyImageToDrawBuffor(300, 512, w, h, timage);
	delete[]timage;
	delete[]timageB;

to jest dobrze a na 512x256 jest źle

Kopiuj
    int w = 512;
	int h = 256;
	unsigned char* timage = new unsigned char[w * h * 3];
	unsigned char* timageB = new unsigned char[w * h * 3];
	draw.GetDataFragmentDrawBuffor(300, 512, w, h, timageB);
	generate_fire_frame(timageB,timage, w, h);
	draw.CopyImageToDrawBuffor(300, 512, w, h, timage);
	delete[]timage;
	delete[]timageB;
hzmzp
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 734
1

Ten kod zakłada, że bufor image ma dokładnie taką samą szerokość jak pixels, czyli że image odpowiada bieżącemu rozmiarowi ognia (width x height).
Jeśli jednak obraz tła (image) ma inną szerokość (np. 256) i Ty generujesz ogień o szerokości 512, to wtedy image[idx + ...] zaczyna wychodzić poza zakres oryginalnego tła, lub „zawija się” (jeśli bufor jest powielany), co skutkuje właśnie dublowaniem ognia w poziomie.

wilkwielki
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 678
0
Kopiuj
void GetDataFragmentDrawBuffor(int xs, int ys, int width, int height, unsigned char*& gdata)
{

	int xpos = 0;
	int ypos = 0;


	for (int py = ys; py < ys + height; py += 1)
	{

		for (int px = xs; px < xs + width; px += 1)
		{

			int pis = (xpos * 3 + ypos * height * 3);

			int index = (px * 4 + py * rx * 4);
			if (px < rx && py < ry && px >= 0 && py >= 0)
			{
				gdata[pis] = drawbuffor[index];
				gdata[pis + 1] = drawbuffor[index + 1];
				gdata[pis + 2] = drawbuffor[index + 2];
			}
			xpos += 1;
			if (xpos == width)
				xpos = 0;
		}
		ypos += 1;
	}
	

}

oraz

Kopiuj
void CopyImageToDrawBuffor(int xs, int ys, int width, int height, unsigned char*& gdata)
{

	int xpos = 0;
	int ypos = 0;

	for (int py = ys; py < ys + height; py += 1)
	{

		for (int px = xs; px < xs + width; px += 1)
		{

			int pis = (xpos * 3 + ypos * height * 3);

			int index = (px * 4 + py * rx * 4);
			if (px < rx && py < ry && px>=0 && py>=0)
			{
				drawbuffor[index] = gdata[pis];
				drawbuffor[index + 1] = gdata[pis + 1];
				drawbuffor[index + 2] = gdata[pis + 2];
			}

			xpos += 1;
			if (xpos == width)
				xpos = 0;
		}
		ypos += 1;
	}

}

gotowe 😀

wilkwielki
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 678
0
Kopiuj
  int w = 512;
	int h = 256;
	unsigned char* timage = new unsigned char[w * h * 3];
	unsigned char* timageB = new unsigned char[w * h * 3];
	draw.GetDataFragmentDrawBuffor(300, 512, w, h, timageB);
	generate_fire_frame(timageB,timage, w, h);
	draw.CopyImageToDrawBuffor(300, 512, w, h, timage);
	delete[]timage;
	delete[]timageB;
LukeJL
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 8487
4

int pis = (xpos * 3 + ypos * height * 3);

to wygląda podejrzanie. Czemu mnożysz współrzędną pionową przez wysokość, a nie szerokość? Zakładam, że piksele a buforze masz ułożone rzędami.

Spróbuj tak:

Kopiuj
int pis = (xpos * 3 + ypos * width * 3);
wilkwielki
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 678
1

screenshot-20251104150502.png

Spine
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 6959
1

Parafrazując mem.... ChatGPT would have prevented this post... https://chatgpt.com/share/690a0ec1-16e0-800a-b1cd-381c79a29808

screenshot-20251104153507.png

Nawet na tak słabo napisane pytanie potrafił odpowiedzieć.
Ale trzeba było dodać metody odpowiedzialne za problem.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.