I am currently working on a simple car simulation on a plane in DirectX. I am having problems on orienting the car on the plane .
what i am doing is this...
D3DXMATRIX planeMat //matrix of the plane on which car is currently situated.
...
//calculating car rotation matrix (on XZ plane )
D3DXMATRIX carRot;
D3DXMatrixRotationY( &carRot , yaw );
//car up will same as plane
D3DXVECTOR3 carUp = D3DXVECTOR3( planeMat._12 , planeMat._22 , planeMat._32 );
//car lookat vector
D3DXVECTOR3 carLookat = D3DXVECTOR3( carRot._13 , carRot._23 , carRot._33 );
// calculating right vector
D3DXVec3Cross( &carRight , &carLookAt , &carUp );
D3DXVec3Normalize( &carRight , &carRight );
//calculating new lookat
D3DXVec3Cross( &carLookAt , &carRight , &carUp );
D3DXVec3Normalize( &carLookAt , &carLookAt );
//car matrix
D3DXMATRIX carMat; D3DXMatrixIdentity( &carMat );
carMat._11 = carRight.x ;carMat._21 = carRight.y ;carMat._31 = carRight.z ;
carMat._12 = carUp.x ;carMat._22 = carUp.y ;carMat._32 = carUp.z ;
carMat._13 = carLookAt.x ;carMat._23 = carLookAt.y ;carMat._33 = carLookAt.z ;
carMat._41 = carPos.x ;carMat._42 = carPos.y ;carMat._43 = carPos.z ;
I can't get car's rotation correct.please help me.
The way you are setting & using components in your matrix doesn't look correct. For instance, in carMat the 3 basis vectors have the 2nd digit of the component constant but in the last one (carPos), the 1st digit of the component is constant. It's either one way or the other for all 4 rows/columns of the matrix.
I believe the way you are setting the car's position (last row/column) is the correct way and the way you are doing the up, right, & lookat are incorrect. So, for instance, it should probably be like this:
D3DXMATRIX carMat; D3DXMatrixIdentity( &carMat );
carMat._11 = carRight.x ;carMat._12 = carRight.y ;carMat._13 = carRight.z ;//11, 12, 13 instead of 11, 21, 31
carMat._21 = carUp.x ;carMat._22 = carUp.y ;carMat._23 = carUp.z ;
carMat._31 = carLookAt.x ;carMat._32 = carLookAt.y ;carMat._33 = carLookAt.z ;
carMat._41 = carPos.x ;carMat._42 = carPos.y ;carMat._43 = carPos.z ;
Also, the way you populate the vectors carUp and carLookAt fom the components of planeMat & carRot suffers from the same issue.
Related
I have an SCNode which is dynamically created using the SCNPlane geometry to draw a plane using SceneKit.
How do I determine the normal vector to this plane?
Here is a playground demonstrating what I have tried. I have attached a screenshot of the resulting scene that is drawn. I don't think any of the cylinders, which represent the vectors obtained at the normal vector to this red plane.
//: Playground - noun: a place where people can play
import UIKit
import SceneKit
import PlaygroundSupport
// Set up the scene view
let frame = CGRect(
x: 0,
y: 0,
width: 500,
height: 300)
let sceneView = SCNView(frame: frame)
sceneView.showsStatistics = true
sceneView.autoenablesDefaultLighting = true
sceneView.allowsCameraControl = true
sceneView.scene = SCNScene()
// Setup our view into the scene
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x: 0, y: 0, z: 3)
sceneView.scene!.rootNode.addChildNode(cameraNode)
// Add a plane to the scene
let plane = SCNNode(geometry: SCNPlane(width: 3,height: 3))
plane.geometry?.firstMaterial!.diffuse.contents = UIColor.red.withAlphaComponent(0.5)
plane.geometry?.firstMaterial?.isDoubleSided = true
sceneView.scene!.rootNode.addChildNode(plane)
/*
normalSource = [SCNGeometrySource geometrySourceWithData:data
semantic:SCNGeometrySourceSemanticNormal
vectorCount:VERTEX_COUNT
floatComponents:YES
componentsPerVector:3 // nx, ny, nz
bytesPerComponent:sizeof(float)
dataOffset:offsetof(MyVertex, nx)
dataStride:sizeof(MyVertex)];
*/
let dataBuffer = plane.geometry?.sources(for: SCNGeometrySource.Semantic.normal)[0].data
let colorArray = [UIColor.red, UIColor.orange, UIColor.yellow, UIColor.green, UIColor.blue, UIColor.systemIndigo, UIColor.purple, UIColor.brown, UIColor.black, UIColor.systemPink]
let sceneGeometrySource = dataBuffer!.withUnsafeBytes {
(vertexBuffer: UnsafePointer<SCNVector3>) -> SCNGeometrySource in
let sceneVectors = Array(UnsafeBufferPointer(start: vertexBuffer, count: dataBuffer!.count/MemoryLayout<SCNVector3>.stride))
var i=0
for vector in sceneVectors{
let cyl = SCNCylinder(radius: 0.05, height: 3)
cyl.firstMaterial!.diffuse.contents = colorArray[i].withAlphaComponent(0.8)
let lineNode = SCNNode(geometry: cyl)
lineNode.eulerAngles = vector
sceneView.scene!.rootNode.addChildNode(lineNode)
}
return SCNGeometrySource(vertices: sceneVectors)
}
PlaygroundSupport.PlaygroundPage.current.liveView = sceneView
in the apple documentation https://developer.apple.com/documentation/accelerate/working_with_vectors in "Calculate the Normal of a Triangle" you can find the solution. You just need 3 points which are not on one line and then use this:
The following code defines the three vertices of the triangle:
let vertex1 = simd_float3(-1.5, 0.5, 0)
let vertex2 = simd_float3(1, 0, 3)
let vertex3 = simd_float3(0.5, -0.5, -1.5)
Your first step in calculating the normal of the triangle is to create two vectors defined by the difference between the vertices—representing two sides of the triangle:
let vector1 = vertex2 - vertex3
let vector2 = vertex2 - vertex1
The simd_cross function returns the vector that's perpendicular to the two vectors you pass it. In this example, the returned vector is the normal of the triangle. Because the normal represents a direction, you can normalize the value to get a unit vector:
let normal = simd_normalize(simd_cross(vector1, vector2))
I tried to make a simple application which solves ode for given starting value y_0.
For example we can have:
dy/dt = -2ty
Using some tutorials (scilab site and a youtube tutorial) I arrive at current version:
function dy = f(t,y)
dy = -2*t*y;
endfunction
function updatePlot()
clf(right)
y0 = get(y0CONTROL,"value");
t0 = 0;
t = 0:0.1:10
solution = ode(y0,t0,t,f);
plot(solution, right)
endfunction
gui = figure();
gui.visible = "on";
gui.immediate_drawing = "on";
left = uicontrol(gui,...
'style','frame',...
'layout','gridbag',...
'constraints', createConstraints('border', 'left',))
right = uicontrol(gui,...
'style','frame',...
'layout','border',...
'constraints', createConstraints('border', 'center'))
y0CONTROL = uicontrol(left, ...
'style','slider', ...
'max', 10, ...
'min', -10, ...
'value',-1,...
'callback', 'updatePlot')
updatePlot()
As one can see I attempted to use clf(right) to clear previous graph and plot(solution,right) to plot in now presumably empty right frame.
And yet this attempt fails - old lines stay on the graph after movement of the slider.
Please tell me how to correct this.
a more smooth solution is just to change the curve data:
function updatePlot()
y0CONTROL;
y0 = y0CONTROL.value
curve=y0CONTROL.user_data
t0 = 0;
t = 0:0.1:10
solution = ode(y0,t0,t,f);
if curve==[] then //first call
plot(t,solution)
curve=gce().children(1); //the handle on the curve
y0CONTROL.user_data=curve;
else //other calls
ax=gca();
ax.data_bounds(:,2)=[min(solution);max(solution)];
curve.data(:,2)=solution.';
end
endfunction
gui = figure();
ax=gca();
gui.visible = "on";
gui.immediate_drawing = "on";
y0CONTROL = uicontrol(gui, ...
'style','slider', ...
'position',[20 20 100 20],...
'max', 10, ...
'min', -10, ...
'value',-1,...
'callback', 'updatePlot()',...
'user_data',[])
ax.background=-2;
updatePlot()
It turns out that refreshing effect can be achieved by substituting
clf(right)
with
current_axes = gca()
delete(current_axes)
This was useful.
I have a 3d game where I will create an rectangle which is working as screen and the game itself works with vectors to positions. so I will create an rectangle and have only these parameters aviable:
start position ->vector (x,y,z).
Angle(rotation) of object(x,y,z).
size of rectangle.
now also the object need to be roatet to the right side so they are using angels also (x,y,z).
example:
position:-381.968750 -28.653845 -12702.185547
angle: -0.000 90.000 90.000
What I will create is an little bit hard but as idea simple.
I choose 2 complete different positions and angles and will create from the first vector to the second an rectangle.
I can only create an rectangle with the start point and angle.
and I can set the size so (x,y)
So I will now insert 2 positions(vectors) with 2 different angles
The rectangle will have the middle value between the first and second angle so like (90 and 0) -> 45
And the rectangle will start at the start vector and will end with his own size so I don't have a chance to use the end vector directly.
Legendary on photo:
Green=>start and end positions(vectors).
red => the marked zone.
Blue => how I will have the rectangle.
aem_point = vgui.Create( "AEM.Main.Panel" )
if IsValid(aem_point) then
aem_point:SetSize( 2,2 ) -- <-the size that i can set
aem_point:SetPos( 0, 0 )
aem_ph = vgui.Create( "DHTML", aem_point )
aem_ph:SetSize( aem_point:GetSize() )
aem_ph:SetPos(aem_point:GetPos())
aem_ph:SetVisible( true )
aem_ph:SetHTML([[
<html>
<body style="margin:0px;padding:0px;font-size:20px;color:red;border-style: solid;border-color: #ff0000;background-color:rgba(255,0,0,0.1);">
</body>
</html>
]] )
end
hook.Add( "PostDrawOpaqueRenderables", "DrawSample3D2DFrame" .. math.random(), function()
if first and dat_finish then
vgui.Start3D2D( input_position, input_angle, 1 ) -- <-and position&vec
aem_point:Paint3D2D()
vgui.End3D2D()
end
end )
Oh so you want to create a 3d2d plane from 2 vector positions?
Vec1 = A
Vec2 = B
input_position = ( Vec1 + Vec2 ) / 2
A problem you will run into is you need 3 points to generate a plane, so while you can get the position of the screen to get the angle of it you will need another point.
If these screens of yours are staticly set, as in you put their position into the lua code manually and dont intend to have it move or anything, just manually putting in the angle is by far the most simple approch.
As you can see, both of these planes are on the same two points, but they have diffrent angles.
I wrote the demo in expression 2, this should make it clear as to how this works, if you have any other questions just ask.
A = entity(73):pos()
B = entity(83):pos()
if(first())
{
holoCreate(1)
holoCreate(2)
}
holoPos(1,(A+B)/2)
holoScaleUnits(1,vec( abs(B:y() - A:y()) , 1 , abs(sqrt( ( B:z() - A:z() ) ^ 2 + ( B:x() - A:x() ) ^ 2 ))))
holoAng(1,ang(0,90,45))
holoPos(2,(A+B)/2)
holoScaleUnits(2,vec( abs(sqrt( ( B:x() - A:x() ) ^ 2 + ( B:y() - A:y() ) ^ 2 )) , 1 , abs(B:z()-A:z())))
holoAng(2,ang(0,45,0))
How can I find a point ( C (x,y,z) ) between 2 points ( A(x,y,z) , B(x,y,z) ) in a thgree.js scene?
I know that with this: mid point I can find the middle point between them, but I don't want the middle point, I want to find the point which is between them and also has distance a from the A point?
in this picture you can see what I mean :
Thank you.
Basically you need to get the direction vector between the two points (D), normalize it, and you'll use it for getting the new point in the way: NewPoint = PointA + D*Length.
You could use length normalized (0..1) or as an absolute value from 0 to length of the direction vector.
Here you can see some examples using both methods:
Using absolute value:
function getPointInBetweenByLen(pointA, pointB, length) {
var dir = pointB.clone().sub(pointA).normalize().multiplyScalar(length);
return pointA.clone().add(dir);
}
And to use with percentage (0..1)
function getPointInBetweenByPerc(pointA, pointB, percentage) {
var dir = pointB.clone().sub(pointA);
var len = dir.length();
dir = dir.normalize().multiplyScalar(len*percentage);
return pointA.clone().add(dir);
}
See it in action: http://jsfiddle.net/8mnqjsge/
Hope it helps.
I know the question is for THREE.JS and I end up looking for something similar in Babylon JS.
Just in case if you are using Babylon JS Vector3 then the formula would translate to:
function getPointInBetweenByPerc(pointA, pointB, percentage) {
var dir = pointB.clone().subtract(pointA);
var length = dir.length();
dir = dir.normalize().scale(length *percentage);
return pointA.clone().add(dir);
}
Hope it help somebody.
This is known as lerp between two points
e.g. in Three:
C = new Three.Vector3()
C.lerpVectors(A, B, a)
also in generic this is just a single lerp (linear interpolation) math (basically (a * t) + b * (1 - t)) on each axis. Lerp can be described as follows:
function lerp (a, b, t) {
return a + t * (b - a)
}
in your case (see above) :
A = {
x: lerp(A.x, B.x, a),
y: lerp(A.y, B.y, a),
z: lerp(A.z, B.z, a)
}
Following Problem: I have a database table with pins coordinates (lat, lng). I send my maps current bounds to the backend to choose visible pins from the database. My code (cakePHP) is following:
private function getMapData($level = 1)
{
$x1 = $this->request->query('x1');
$x2 = $this->request->query('x2');
$y1 = $this->request->query('y1');
$y2 = $this->request->query('y2');
if ($x1 > $x2)
{
$tmp = $x1;
$x1 = $x2;
$x2 = $tmp;
}
if ($y1 > $y2)
{
$tmp = $y1;
$y1 = $y2;
$y2 = $tmp;
}
return $this->Map->find('all',
array(
'fields' => array(
'Map.lat',
'Map.lng',
'Map.level_number'
),
'conditions' => array('Map.level_number' => $level,
'Map.lat BETWEEN ? AND ?' => array($x1, $x2),
'Map.lng BETWEEN ? AND ?' => array($y1, $y2),
),
'group' => 'Map.lat, Map.lng, Map.level_number' //for distinct values
));
}
The query just picks the pins with coordinates in bounds' range. It works most of the time and it doesn't matter which bound's corner comes first - left/right/top/bottom.
But sometimes this simple calculation seems not to work.
I'm getting the bounds and the center point. If I apply the calculation on the center point it's sometimes not within tne bounds which is realy strange but it's really correct data. So I suspect there is something else in this bounds calculation I didn't think about.
here is an example of parameters I get: ?x1=68.62149425024305&y1=150.81473437500006&x2=-16.728397127562125&y2=173.31473437500006&x=36.520571863374705&y=-377.93526562499994&z=3
x1 and y1 is corner point 1
x2, y2 corner point 2
x,y is center
z is zoomlevel
this isn't a good example as center's lng = -377,9.. but I've got requests with coordinates within range lat between -90 and 90 and lng between -180 and 180 and still my calculation fails I get zero data from database and center point which I get from maps api is not within the bounds I get from the same api
When it's so far off you can add 180° and use absolute value:abs(-377.9+180).