Finding points to build an Arrow.

Started by
4 comments, last by ChazH 9 years, 2 months ago

Hello,

I recently posted this over in the DirectX part of the forum but figured this would be a better place for this question. I am currently working on trying to visualize a raycast and am trying to draw an arrow to signify the direction they ray is facing. I have it working for when the ray is pointing in a specific direction however, when I have the ray pointing in a different everything blows up. This is how I find the various points to render the raycast.



float fStartX = 0.0f;
float fStartY = 0.0f;
float fStartZ = 0.0f;

float fEndX = fStartX + (v3Dir.X * m_fLength);
float fEndY = fStartY + (v3Dir.Y * m_fLength);
float fEndZ = fStartZ + (v3Dir.Z * m_fLength);

float fCos = cosf(ToRadians(45.0f));
float fSin = sinf(ToRadians(45.0f));
fAngle1X = fEndX + fCos;
fAngle1Y = fEndY + fSin;
fAngle1Z = fEndZ / 2.0f;

fAngle2X = fEndX - fCos;
fAngle2Y = fEndY + fSin;
fAngle2Z = fEndZ / 2.0f;

fAngle3X = fEndX - fCos;
fAngle3Y = fEndY - fSin;
fAngle3Z = fEndZ / 2.0f;

fAngle4X = fEndX + fCos;
fAngle4Y = fEndY - fSin;
fAngle4Z = fEndZ / 2.0f;

I have a feeling that my issue is that I am not taking into account the ray direction. Which is throwing off the position of my angles. My question is what would be the best way to find the correct positions of the arrow based on direction. The only thing that I can think of is throwing in a couple of if statements to figure it out but that seems like a bad idea. I know it can be done with math. I am just not sure what the steps are to find it.


Thank you,
Chaz H.

Thank you,
Chaz
Advertisement

I made such draw function in the past, but in 2D - should be fairly simple to implement this in 3D.

The trick is to use the perpendical direction to calculate the tip left/right position.


    function drawVector(origin, vec, color, title, titleColor, titleIsOppsite, invert) {
        var n = {x: (origin.x + vec.x) - origin.x, y: (origin.y + vec.y) - origin.y};
        var l = Math.sqrt(n.x * n.x + n.y * n.y);
        n.x /= l;
        n.y /= l;
        var t = {x: -n.y, y: n.x};
        var arrowWidth = 12;
        var arrowDepth = 12;
        var textSpace = 20;

        var target = new Vec2(origin.x + vec.x, origin.y + vec.y);

        ctx.lineWidth = 3;
        ctx.beginPath();
        ctx.moveTo(origin.x, origin.y);
        ctx.lineTo(target.x, target.y);

        if (!invert){
            ctx.moveTo(target.x, target.y);
            ctx.lineTo(target.x + t.x * arrowWidth + n.x * -arrowDepth, target.y + t.y * arrowWidth + n.y * -arrowDepth);
            ctx.moveTo(target.x, target.y);
            ctx.lineTo(target.x + t.x * -arrowWidth + n.x * -arrowDepth, target.y + t.y * -arrowWidth + n.y * -arrowDepth);
        } else {
            ctx.moveTo(origin.x, origin.y);
            ctx.lineTo(origin.x + t.x * arrowWidth + n.x * arrowDepth, origin.y + t.y * arrowWidth + n.y * arrowDepth);
            ctx.moveTo(origin.x, origin.y);
            ctx.lineTo(origin.x + t.x * -arrowWidth + n.x * arrowDepth, origin.y + t.y * -arrowWidth + n.y * arrowDepth);
        }

        ctx.strokeStyle = color || "white";
        ctx.stroke();
        ctx.lineWidth = 1;

        if (typeof title != "undefined" && title != null) {
            var rad = Math.atan2(n.y, n.x);
            ctx.fillStyle = titleColor || color || "white";
            ctx.textBaseline = "middle";
            ctx.textAlign = "center";
            ctx.save();
            ctx.translate(0 + n.x * l * 0.5 + (titleIsOppsite ? t.x : -t.x) * textSpace, 0 + n.y * l * 0.5 + (titleIsOppsite ? t.y : -t.y) * textSpace);
            ctx.rotate(rad > Math.PI / 2 || rad < -Math.PI / 2 ? rad - Math.PI : rad);
            ctx.fillText(title, 0, 0);
            ctx.restore();
        }
    }

Its pretty trivial in 2D but for God's sake, get yourself using a Vector class rather than manually doing each per-component operation like that.

Vec2 rayPos, rayDir; // assuming rayDir is normalized
float rayLength;

Vec2 end = rayPos + (rayDir * rayLength);

Vec2 left(rayDir.y, -rayDir.x);
Vec2 right(-rayDir.y, rayDir.x); // may have these wrong way round, might be right then left smile.png but basically the perpendiculars to the ray direction vector

Vec2 p = end - (rayDir * someDistance); // move a bit back from the end
Vec2 arrowA = p + (left * someDistance); // move a bit out from arrow shaft at right angles
Vec2 arrowB = p + (right * someDistance); // move a bit out the opposite way

arrowA and arrowB are now the ends of each arrow line, so the following three lines:

rayPos -> end
arrowA -> end
arrowB -> end

will draw the arrow.

Bear in mind in 3D there are an infinite possible number of answers for arrowA and arrowB as you rotate around the arrow so the answer becomes slightly trickier.

Thank you for the help. I have been trying to figure this out all day. My problem seems to be trying to figure out how to convert the left and right vectors that you used into 3D. Any suggestions on the proper way to format those vectors for 3D?

Thank you,
Chaz
That would depend upon where you want the tips of the arrow heads to be in relation to the arrow shaft - for example aligned to the view in some way? Or aligned to world axes in some way?

Honestly, I never thought about that. What would be the easiest to setup? Also, I was thinking. Would't it be easier to find to just find the cross product of the half way point and then use that to build both sides of the arrow head?

Thank you,
Chaz

This topic is closed to new replies.

Advertisement