# Rendering .MAP Using Triangles

## Help needed with generating triangles.

So recently I’ve wrote a script to parse a .MAP file. For those unfamiliar with this file, it is a readable file that contains vertex’s and entities, these were commonly used in games like Quake. As far as parsing the data goes, it seems to work perfectly. I parse the .MAP and get all of the data needed, such as positions of entities, and geometry vertexes.

Quake’s maps, to my understanding, were rendered using 3 points(A triangle), based off of the Vectors they provided. I took the time to conver the vector’s they had into a working Roblox format seeing as their coordinates are different, and the scaling was too. I managed to load entities into the correct positions and it all looks good there.

Each yellow box is a light source, and each red block is a enemy.

This map I am loading is E1M1 from Quake 1. The positions of everything is accurate, so there is nothing wrong with my positions or scaling.

The issue is when I use the same scaling, and positions to generate triangles, I get some seriously funky results.

Expected result (minus textures):

For generating the Triangles I am using @EgoMoose’s triangle module.

I have tried looking at Quake’s source, but I am unable to find the specific point where rendering occurs of maps, if anyone knows where that is, feel free to lemme know.

The triangle function looks like this (again not mine, egomoose )

``````function Triangle(a, b, c, parent, wb, wc)
local ab, ac, bc = b - a, c - a, c - b
local abl, acl, bcl = ab.magnitude, ac.magnitude, bc.magnitude
if abl > bcl and abl > acl then
c, a = a, c
elseif acl > bcl and acl > abl then
a, b = b, a
end
ab, ac, bc = b - a, c - a, c - b
local out = cross(ac, ab).unit
wb = wb or clone(ref)
wc = wc or clone(ref)
local biDir = cross(bc, out).unit
local biLen = abs(dot(ab, biDir))
local norm = bc.magnitude
wb.Size = v3(2, abs(dot(ab, bc))/norm, biLen)
wc.Size = v3(2, biLen, abs(dot(ac, bc))/norm)
bc = -bc.unit
wb.CFrame = fromAxes((a + b)/2, -out, bc, -biDir)
wc.CFrame = fromAxes((a + c)/2, -out, biDir, bc)
wb.Parent = parent
wc.Parent = parent
return wb, wc
end
``````

An example of the positions I am slapping in look like this:

``````( 640 320 -16 ) ( 640 320 0 ) ( 640 192 0 )
-- Quakes Vectors, These are in Quakes units, not studs, also the Z is the vertical positioning.
``````

I convert these positions into studs, and then get much more reasonable numbers

``````( 46.96 -1.17 23.48 ) ( 46.96 0 23.48 ) ( 46.96 0 14.08 )
-- These are full Roblox Vectors that I use for generating triangles, I made Z the Y in the previous
``````

The triangle I generate uses the 3 points above as a Vector3, for each set of Vectors in the .MAP and I get completely wrong positions. My math with this kinda stuff is not super great, and I think that is probably where things are going wrong.

There is not a whole lot of articles on Google about this, but I did find one which gave some guidelines for the points.

``````-- 1st Point \   Those three points define a plane, so they must not be colinear.
-- 2nd Point  >  Each plane should only be defined once.
-- 3rd Point /   Plane normal is oriented toward the cross product of (P1 - P2) and (P3 -P2)
``````

As I said above, my math is not great with this, so I have no idea if this even works with the function above. Honestly, any help to get a somewhat recognizable map would be appreciated. If you need code snippets of anything let me know.

I have a feeling @Maximum_ADHD might have an idea about this, seeing as he dealt with some of the same thing with his VMF Importer.

Sorry if my explaination was a bit confusing.

TLDR: I need to generate wedges that form a triangle to create geometry from Quake maps, and I am getting funky results that look awful.

Any help would be amazing, thanks.

2 Likes

It’s actually a little more elaborate than that. The 3 points don’t form triangles, they are used to define geometric planes.

Where the planes intersect form the edges and faces of a convex hull. It’s effectively CSG. My VMF Importer has code for solving this, and you can check it’s source out here:

5 Likes

I appreciate your response, I am sure the answer is there but I cant seem to achieve it, I am getting the same results using your source.

I tried it on a much smaller, testing map, which is simply a rectangle, and it seems like all the rotations are incorrect. I can’t tell though.

``````-- Test Map Source
return [[{
"sounds" "1"
"classname" "worldspawn"
"worldtype" "0"
{
( 128 0 0 ) ( 128 1 0 ) ( 128 0 1 ) GROUND1_6 0 0 0 1.0 1.0
( 256 0 0 ) ( 256 0 1 ) ( 256 1 0 ) GROUND1_6 0 0 0 1.0 1.0
( 0 128 0 ) ( 0 128 1 ) ( 1 128 0 ) GROUND1_6 0 0 0 1.0 1.0
( 0 384 0 ) ( 1 384 0 ) ( 0 384 1 ) GROUND1_6 0 0 0 1.0 1.0
( 0 0 64 )  ( 1 0 64 )  ( 0 1 64 )  GROUND1_6 0 0 0 1.0 1.0
( 0 0 128 ) ( 0 1 128 ) ( 1 0 128 ) GROUND1_6 0 0 0 1.0 1.0
}
}
{
"classname" "info_player_start"
"origin" "256 384 160"
}
{
"classname" "light"
"origin" "256 384 200"
}
]]
``````

Also, thanks for clarifying the planes, makes more sense than triangles lol,

I was looking at `Plane.lua` and `Polygon.lua`, not sure if I am missing a larger chunk of things there.

1 Like

To expand on this, think back to highschool math.

• 1 point forms a coordinate
• 2 points form a line/segment
• 3 or more points form a plane

Try to think about all three of those when generating triangles.

The main module of interest is the `Winding` module.
It provides the actual math for carving convex shapes.

https://github.com/CloneTrooper1019/Roblox-Plugins/blob/master/VMFImporter/Modules/Winding.lua

From there, the faces are solved using these functions in the plugin’s main code:
https://github.com/CloneTrooper1019/Roblox-Plugins/blob/master/VMFImporter/init.server.lua#L478-L785

I ported most of this from Hammer’s source code.

1 Like