3D fundamentals snake

The Partridge Family were neither partridges nor a family. Discuss.
paulboon
Posts: 14
Joined: February 11th, 2017, 3:02 pm

3D fundamentals snake

Post by paulboon » June 28th, 2017, 5:06 pm

I'm following along with the 3D fundamentals series.
I'm Really enjoying it and i tried to make a snake game using it.
graphics are still a bit(read very) buggy but i got something working and i'm planning to keep adding to it and improving it whilst the series continues.

btw how do you load in textures and read and write pixel values to them?

controls: wasd/arrow keys
Attachments
Release.zip
(2.1 MiB) Downloaded 156 times

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: 3D fundamentals snake

Post by albinopapa » June 28th, 2017, 10:05 pm

paulboon wrote: btw how do you load in textures and read and write pixel values to them?
Look at his Surface class, there should be a function to create a surface from file. This allows you to load a texture from a file. As for writing pixels to the surface, there is the PutPixel function in there as well.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: 3D fundamentals snake

Post by albinopapa » June 28th, 2017, 10:07 pm

Btw, all you needed was the exe file in your ZIP upload. The pdb has debug symbols in it, so that's optional. The Engine.obj file turns into the exe, so that's not necessary and I don't know what the ipdb file is.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: 3D fundamentals snake

Post by albinopapa » June 28th, 2017, 10:12 pm

Good start.

Oddly enough, the line where the triangles meet on the pulsating cubes has missing pixels, did you follow along or is this downloaded from the repo? If followed along, then there maybe a chance you missed a few variables.

I like the wrapping around to the other side, freaked me out at first was like "whoa I just teleported."
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

paulboon
Posts: 14
Joined: February 11th, 2017, 3:02 pm

Re: missing pixels

Post by paulboon » June 29th, 2017, 8:33 am

yeah i'm having touble with the missing pixels.
i'm using a slightly different method for drawing triangles but i'm having trouble applying the top-left rule from the tutorial

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: 3D fundamentals snake

Post by albinopapa » June 29th, 2017, 3:02 pm

What method are you using? Could you share some code? Perhaps we could help you find the issue.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

paulboon
Posts: 14
Joined: February 11th, 2017, 3:02 pm

Re: 3D fundamentals snake

Post by paulboon » June 29th, 2017, 3:32 pm

this is it. it's quite the bulk though.
the main idea is to have two dots trace the lines of the triangle.

Code: Select all

void triangle(Mesh mesh, int a, int b, int c, Graphics& gfx, std::function<void (Vec3i, EdgeWalker)> locationGiver) {
		Package vs [] = { mesh.getPackage(a),mesh.getPackage(b),mesh.getPackage(c) };
		std::sort(vs, vs + 3, [](Package a, Package b) -> bool {return a.vertex.y < b.vertex.y; });
		Package top = vs[0];
		Package middle = vs[1];
		Package bot = vs[2];

		float ratio = (middle.vertex.y - top.vertex.y) / (float)(bot.vertex.y - top.vertex.y);
		Package middleRight = top.lerp(bot, ratio);
		if (middle.vertex.x > middleRight.vertex.x)std::swap(middle, middleRight);

		auto fromTo = [&](Package topLeft, Package topRight, Package bottomLeft, Package bottomRight) {
			std::vector<FromTo> fromtosLeft;
			EdgeWalker leftWalker = EdgeWalker::copyOver(topLeft, bottomLeft, EdgeWalkerCode::y, std::vector<EdgeWalkerCode>{EdgeWalkerCode::x, EdgeWalkerCode::z, EdgeWalkerCode::uvx, EdgeWalkerCode::uvy});
			EdgeWalker rightWalker = EdgeWalker::copyOver(topRight, bottomRight, EdgeWalkerCode::y, std::vector<EdgeWalkerCode>{EdgeWalkerCode::x, EdgeWalkerCode::z, EdgeWalkerCode::uvx, EdgeWalkerCode::uvy});

			while (leftWalker.counter < (int)ceil(bottomLeft.vertex.y - 0.5f)) {
				EdgeWalker horizontalWalker = EdgeWalker::copyOver(leftWalker, rightWalker, EdgeWalkerCode::x, std::vector<EdgeWalkerCode>{EdgeWalkerCode::z, EdgeWalkerCode::uvx, EdgeWalkerCode::uvy});

				while (horizontalWalker.counter < (int)ceil(rightWalker.get(EdgeWalkerCode::x) - 0.5f)) {
					locationGiver(Vec3i(horizontalWalker.counter,leftWalker.counter,0), horizontalWalker);
					horizontalWalker.step();
				}

				leftWalker.step();
				rightWalker.step();
			}

			
		};

		fromTo(top,top,middle,middleRight);//upper triangle/flatbot
		fromTo(middle, middleRight,bot,bot);//lower triangle/flattop

	}
and these structs in another file

Code: Select all

enum EdgeWalkerCode {
	x, y, z, uvx, uvy
};

struct IEdgeCodeGetter {
	virtual float get(EdgeWalkerCode) = 0;
};

struct Package : public IEdgeCodeGetter{
	Vec3f vertex;
	Vec2f uv;

	Package() = default;

	Package(Vec3f vertex, Vec2f uv) :vertex(vertex), uv(uv) {

	}

	Package lerp(Package& v, float weight) {
		Package package;
		package.vertex = vertex.lerp(v.vertex, weight);
		package.uv = uv.lerp(v.uv, weight);
		return package;
	}

	float get(EdgeWalkerCode code) {
		switch (code) {
		case x:
			return vertex.x;
		case y:
			return vertex.y;
		case z:
			return vertex.z;
		case uvx:
			return uv.x;
		case uvy:
			return uv.y;
		default:
			return 0;
		}
	}


};

struct FromTo {
	EdgeWalkerCode edgeWalkerCode;
	float from, to;

	FromTo(EdgeWalkerCode edgeWalkerCode, float from, float to):edgeWalkerCode(edgeWalkerCode), from(from), to(to) {
		
	}
};

struct EdgeWalker : public IEdgeCodeGetter {
	int counter;
	std::map<EdgeWalkerCode, float> posMap;
	std::map<EdgeWalkerCode, float> incsMap;

	EdgeWalker(float from, float to, std::vector<FromTo> fromtos) {
		
		counter = (int)ceil(from - 0.5f);
		float diff = to - from;

		for each (FromTo package in fromtos){
			posMap[package.edgeWalkerCode] = package.from;
			incsMap[package.edgeWalkerCode] = (package.to - package.from) / diff;
		}

	}

	

	static EdgeWalker copyOver(IEdgeCodeGetter& a, IEdgeCodeGetter& b, EdgeWalkerCode walker, std::vector<EdgeWalkerCode> codes) {
		std::vector<FromTo> fromtos;
		for each (EdgeWalkerCode code in codes){
			fromtos.push_back(FromTo(code, a.get(code), b.get(code)));
		}

		return EdgeWalker(a.get(walker), b.get(walker), fromtos);
	}

	void step() {
		counter++;
		std::map<EdgeWalkerCode, float>::iterator it = posMap.begin();

		while (it != posMap.end()) {
			posMap[it->first] += incsMap[it->first];
			it++;
		}
	}


	float get(EdgeWalkerCode code) {
		return posMap[code];
	}
};

paulboon
Posts: 14
Joined: February 11th, 2017, 3:02 pm

Re: 3D fundamentals snake

Post by paulboon » June 29th, 2017, 3:40 pm

quickly added some comments

Code: Select all

	void triangle(Mesh mesh, int a, int b, int c, Graphics& gfx, std::function<void (Vec3i, EdgeWalker)> locationGiver) {
		//sort and name vertices
		Package vs [] = { mesh.getPackage(a),mesh.getPackage(b),mesh.getPackage(c) };
		std::sort(vs, vs + 3, [](Package a, Package b) -> bool {return a.vertex.y < b.vertex.y; });
		Package top = vs[0];
		Package middle = vs[1];
		Package bot = vs[2];

		//get splitting vertex
		float ratio = (middle.vertex.y - top.vertex.y) / (float)(bot.vertex.y - top.vertex.y);
		Package middleRight = top.lerp(bot, ratio);
		if (middle.vertex.x > middleRight.vertex.x)std::swap(middle, middleRight);

		//use edgewalkers to track and interpolate the edges of the triangle
		auto fromTo = [&](Package topLeft, Package topRight, Package bottomLeft, Package bottomRight) {
			std::vector<FromTo> fromtosLeft;
			EdgeWalker leftWalker = EdgeWalker::copyOver(topLeft, bottomLeft, EdgeWalkerCode::y, std::vector<EdgeWalkerCode>{EdgeWalkerCode::x, EdgeWalkerCode::z, EdgeWalkerCode::uvx, EdgeWalkerCode::uvy});
			EdgeWalker rightWalker = EdgeWalker::copyOver(topRight, bottomRight, EdgeWalkerCode::y, std::vector<EdgeWalkerCode>{EdgeWalkerCode::x, EdgeWalkerCode::z, EdgeWalkerCode::uvx, EdgeWalkerCode::uvy});

			while (leftWalker.counter < (int)ceil(bottomLeft.vertex.y - 0.5f)) {
				EdgeWalker horizontalWalker = EdgeWalker::copyOver(leftWalker, rightWalker, EdgeWalkerCode::x, std::vector<EdgeWalkerCode>{EdgeWalkerCode::z, EdgeWalkerCode::uvx, EdgeWalkerCode::uvy});

				while (horizontalWalker.counter < (int)ceil(rightWalker.get(EdgeWalkerCode::x) - 0.5f)) {
					locationGiver(Vec3i(horizontalWalker.counter,leftWalker.counter,0), horizontalWalker);
					horizontalWalker.step();
				}

				leftWalker.step();
				rightWalker.step();
			}

			
		};

		//draw top and bottom triangle
		fromTo(top,top,middle,middleRight);//upper triangle/flatbot
		fromTo(middle, middleRight,bot,bot);//lower triangle/flattop

	}

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: 3D fundamentals snake

Post by albinopapa » June 29th, 2017, 4:49 pm

Nope, sorry. That's a bit too complicated for me lol.

Perhaps, if you put it in a repo and drop a link or zip a cleaned solution and post here on forum I'd be able to walk through it in the debugger, but just looking at this code I can't tell. For the most part, I think I follow the code, and it seems that the logic is sound, but I can't tell just by looking at it.

Spoiler is just me externalizing my thoughts, don't take it seriously or in the wrong manner.
Spoiler:
I know it has nothing to do with the missing pixels, but it's eating me alive so I'm going to say it. For the love of GOD why make it so complicated lol. I like what you're going for, and you seem to have a good grasp of the language...although the for each thing seems like a C# or other language carry-over. I think your idea is to calculate the positions of each pixel before actually writing those pixels to the screen, but I'm not sure why. The part I like is making tools to handle the calculations like lerp and edge walker, but let's imagine an object that takes up the entire screen, now you have hundreds of vectors of pixels to create. Kind of a waste of memory and cpu cycles. Perhaps I'm just not seeing everything correctly. If I had a chance to study and debug the code live, I might be able to get a clearer picture.
As for the missing pixels, same thing, I'd need to be able to run it through the debugger.
No disrespect just had to say something.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: 3D fundamentals snake

Post by albinopapa » June 29th, 2017, 4:52 pm

Yeah, I wrote that before you put the comments in, I could tell what the sections did ( sort, split, etc ). It's just hard to visualize how a scenario would play out, so being able to debug line by line is how I work best, sorry.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

Post Reply