Page 1 of 3

3D fundamentals snake

Posted: June 28th, 2017, 5:06 pm
by paulboon
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

Re: 3D fundamentals snake

Posted: June 28th, 2017, 10:05 pm
by albinopapa
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.

Re: 3D fundamentals snake

Posted: June 28th, 2017, 10:07 pm
by albinopapa
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.

Re: 3D fundamentals snake

Posted: June 28th, 2017, 10:12 pm
by albinopapa
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."

Re: missing pixels

Posted: June 29th, 2017, 8:33 am
by paulboon
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

Re: 3D fundamentals snake

Posted: June 29th, 2017, 3:02 pm
by albinopapa
What method are you using? Could you share some code? Perhaps we could help you find the issue.

Re: 3D fundamentals snake

Posted: June 29th, 2017, 3:32 pm
by paulboon
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];
	}
};

Re: 3D fundamentals snake

Posted: June 29th, 2017, 3:40 pm
by paulboon
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

	}

Re: 3D fundamentals snake

Posted: June 29th, 2017, 4:49 pm
by albinopapa
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.

Re: 3D fundamentals snake

Posted: June 29th, 2017, 4:52 pm
by albinopapa
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.