How do I calculate the points of a brush from a vmf?

Grab your favourite IDE and tinker with the innards of game engines

How do I calculate the points of a brush from a vmf?

Postby Chris528 on Mon Jul 29, 2013 5:38 pm

I'm trying to render the brushes from a Source engine .vmf file in C++, using OpenGL. My immediate goal is to make a simple vmf editor.

The .vmf stores solid brushes as a series of planes which I would like to use to calculate the points for each brush. I'm pretty sure this would be done exactly the same as for all Quake engine based .map files as well.

Basically each point of the brush is the point where 3 planes intersect. I found a similar question to mine on stackoverflow and the explanation is to get the unit normals for the 3 planes, then use equation 8 on this page http://mathworld.wolfram.com/Plane-Plan ... ction.html. My problem is that I have no idea how to implement that, or even if that's the best way.

Here's some code for a single 6 sided cube shaped brush:

"plane" "(0 0 256) (0 256 256) (256 256 256)"
"plane" "(0 256 0) (0 0 0) (256 0 0)"
"plane" "(0 0 0) (0 256 0) (0 256 256)"
"plane" "(256 256 0) (256 0 0) (256 0 256)"
"plane" "(0 256 0) (256 256 0) (256 256 256)"
"plane" "(256 0 0) (0 0 0) (0 0 256)"

I really have no idea where to start, any help would be appreciated, thanks.
User avatar
Chris528
Member
Member
 
Joined: Sat Mar 01, 2008 10:21 pm

Re: How do I calculate the points of a brush from a vmf?

Postby ScarT on Tue Jul 30, 2013 10:12 am

Pseudo code for calculating the normal from points.

Code: Select all
Vector GetNormalFromPoints( point0, point1, point2 )
{
   Vector vNormal;
   v1 = p0 - p1;
   v2 = p2 - p1;


   GetCrossProduct(v1, v2, vNormal);
   NormalizeVector(vNormal);

   return vNormal;
}
User avatar
ScarT
Senior Member
Senior Member
 
Joined: Sat Apr 02, 2005 7:33 pm
Location: Denmarkian Land

Re: How do I calculate the points of a brush from a vmf?

Postby Chris528 on Tue Jul 30, 2013 6:01 pm

I now have the normals calculated, what do I do after that?
User avatar
Chris528
Member
Member
 
Joined: Sat Mar 01, 2008 10:21 pm

Re: How do I calculate the points of a brush from a vmf?

Postby zombie@computer on Wed Jul 31, 2013 6:27 pm

Code: Select all
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace Sledgehammer
{
    public class VMFUTIL
    {
        class Winding : List<Vector3>
        {
            public int numpoints { get; set; }

            public const float MAX_TRACE_LENGTH = 1.732050807569f * 32768;
            public const int MAX_PLANES_ON_BRUSH = 256;
            public const int MAX_PLANE_POINTS = 128;

            private enum Sides { Front, Back, On };

            public void RemoveDuplicatePoints(float minDist)
            {
                int cnt = Count;
                for (int i = 0; i < cnt; i++)
                {
                    for (int j = i + 1; j < cnt; j++)
                    {
                        Vector3 edge = this[i] - this[j];
                        if (edge.Length() < minDist)
                        {
                            RemoveAt(j);
                            cnt--;
                        }
                    }
                }
                for (int i = cnt - 1; i >= 0; i--)
                    if (float.IsNaN(this[i].X))
                        RemoveAt(i);
            }
            public Vector3 VectorMA(Vector3 source, float scale, Vector3 dir)
            {
                Vector3 r = dir;
                r.Normalize();
                return source += (r * scale);
            }
            public Winding(int num)
            {
                numpoints = 0;
                for (int x = 0; x < num; x++) Add(new Vector3(float.NaN, float.NaN, float.NaN));
            }
            public Winding(Plane pPlane)
            {
                int x = -1;
                float max = -16384 * 4, v;

                // find the major axis
                v = Math.Abs(pPlane.Normal.X); if (v > max) { x = 0; max = v; }
                v = Math.Abs(pPlane.Normal.Y); if (v > max) { x = 1; max = v; }
                v = Math.Abs(pPlane.Normal.Z); if (v > max) { x = 2; }

                if (x == -1)
                    throw new Exception("BasePolyForPlane: no axis found");

                Vector3 vup = Vector3.Zero;
                switch (x)
                {
                    case 0:
                    case 1:
                        vup.Z = 1;
                        break;
                    case 2:
                        vup.X = 1;
                        break;
                }

                v = Vector3.Dot(vup, pPlane.Normal);
                vup = VectorMA(vup, -v, pPlane.Normal);
                vup.Normalize();

                Vector3 org = pPlane.Normal * pPlane.D;

                Vector3 vright = Vector3.Cross(vup, pPlane.Normal);

                vup = vup * MAX_TRACE_LENGTH;
                vright = vright * MAX_TRACE_LENGTH;

                // project a really big   axis aligned box onto the plane
                numpoints = 4;
                Add(org - vright);
                this[0] += vup;
                Add(org + vright);
                this[1] += vup;
                Add(org + vright);
                this[2] -= vup;
                Add(org - vright);
                this[3] -= vup;

            }
            public Winding Clip(Plane split)
            {
                float[] dists = new float[MAX_PLANE_POINTS];
                Sides[] sides = new Sides[MAX_PLANE_POINTS];
                int[] counts = new int[] { 0, 0, 0 };
                int p1, p2, mid;

                // determine sides for each point
                for (int i = 0; i < numpoints; i++)
                {
                    float dot = Vector3.Dot(this[i], split.Normal);
                    dot -= split.D;
                    dists[i] = dot;
                    if (dot > 0.01)
                        sides[i] = Sides.Front;
                    else if (dot < -0.01)
                        sides[i] = Sides.Back;
                    else
                        sides[i] = Sides.On;
                    counts[(int)sides[i]]++;
                }
                sides[numpoints] = sides[0];
                dists[numpoints] = dists[0];

                if (counts[0] == 0 && counts[1] == 0)
                    return this;
                if (counts[0] == 0)
                    return null;
                if (counts[1] == 0)
                    return this;
                int maxpts = numpoints + 4; // can't use counts[0]+2 because of fp grouping errors
                Winding neww = new Winding(maxpts);

                for (int i = 0; i < numpoints; i++)
                {
                    p1 = i;//i von this

                    mid = neww.numpoints;//von neww

                    if (sides[i] == Sides.Front || sides[i] == Sides.On)
                    {
                        neww[mid] = this[i];
                        neww.numpoints++;
                        if (sides[i] == Sides.On)
                            continue;
                        mid = neww.numpoints;
                    }

                    if (sides[i + 1] == Sides.On || sides[i + 1] == sides[i])
                        continue;

                    // generate a split point
                    if (i == numpoints - 1)
                        p2 = 0;//von this
                    else
                        p2 = p1 + 1;//von this

                    neww.numpoints++;

                    float dot = dists[i] / (dists[i] - dists[i + 1]);

                    Vector3 newvec = neww[mid];
                    if (split.Normal.X == 1)
                        newvec.X = split.D;
                    else if (split.Normal.X == -1)
                        newvec.X = -split.D;
                    newvec.X = this[p1].X + dot * (this[p2].X - this[p1].X);

                    if (split.Normal.Y == 1)
                        newvec.Y = split.D;
                    else if (split.Normal.Y == -1)
                        newvec.Y = -split.D;
                    newvec.Y = this[p1].Y + dot * (this[p2].Y - this[p1].Y);

                    if (split.Normal.Z == 1)
                        newvec.Z = split.D;
                    else if (split.Normal.Z == -1)
                        newvec.Z = -split.D;
                    newvec.Z = this[p1].Z + dot * (this[p2].Z - this[p1].Z);
                    neww[mid] = newvec;
                }
                if (neww.numpoints > maxpts)
                    throw new Exception("ClipWinding: points exceeded estimate");

                return neww;
            }
        }
        public static void CreateBSP(List<EditorPlane> p)
        {
            bool[] useplane = new bool[Winding.MAX_PLANES_ON_BRUSH];
            int nFaces = p.Count;
            for (int i = 0; i < nFaces; i++)
            {
                Plane f = p[i].P;
                if (f.Normal == Vector3.Zero)
                {
                    useplane[i] = false;
                    continue;
                }
                useplane[i] = true;
                for (int j = 0; j < i; j++)
                {
                    Plane pFaceCheck = p[j].P;
                    if (pFaceCheck.DotNormal(f.Normal) > 0.999 && (Math.Abs(f.D - pFaceCheck.D) < 0.01))
                    {
                        useplane[j] = false;
                        break;
                    }
                }
            }
            for (int i = 0; i < nFaces; i++)
            {
                Plane f = p[i].P;
                if (!useplane[i])
                    continue;
                Winding w = new Winding(f);
                for (int j = 0; j < nFaces && w != null; j++)
                {
                    if (j == i)
                        continue;
                    Plane pFaceClip = p[j].P;
                    w = w.Clip(new Plane(Vector3.Zero - pFaceClip.Normal, -pFaceClip.D));
                }
                if (w != null)
                {
                    for (int j = 0; j < w.numpoints; j++)
                    {
                        Vector3 sub = w[j];
                        float x = (float)Math.Round(sub.X);
                        if (x != sub.X && Math.Abs(sub.X - x) < 0.01f) sub.X = x;

                        float y = (float)Math.Round(sub.Y);
                        if (y != sub.Y && Math.Abs(sub.Y - y) < 0.01f) sub.Y = y;

                        float z = (float)Math.Round(sub.Z);
                        if (z != sub.Z && Math.Abs(sub.Z - z) < 0.01f) sub.Z = z;
                        w[j] = sub;
                    }
                    w.RemoveDuplicatePoints(0.5f);
                    p[i].Vectors.AddRange(w);
                    //ret.Add(w.ToEditorPlane(p[i]));
                }
            }
            foreach (EditorPlane pl in p)
                pl.Vectors.RemoveRange(0, 3);
            return;
        }
    }
}
C# class, you should be able to translate it to c++ easy peasy
When you are up to your neck in shit, keep your head up high
zombie@computer
Forum Goer Elite™
Forum Goer Elite™
 
Joined: Fri Dec 31, 2004 5:58 pm
Location: Lent, Netherlands

Return to Programming

Who is online

Users browsing this forum: No registered users