I'm working on keyboard function that moves up, down, left, right and forward&backward. They seems to work okay, but the problem is that the previous object images still appears. It's like after images are spread all over the screen.
Below are my codes.
This in an initial setting for variables:
double x1 = 0.0f;
double yi = 1.0f;
double z1 = 3.0f;
double lx1 = 0.0f;
double ly1 = 0.0f;
double lz1 = -1.0f;
double angle = 0.0f;
Keyboard function:
switch (key) {
case 033:
glutLeaveMainLoop();
break;
case 'd':
angle -= 0.01f;
lx1 = sin(angle);
lz1 = -cos(angle);
//setCamera();
break;
case 'a':
angle += 0.01f;
lx1 = sin(angle);
lz1 = -cos(angle);
//setCamera();
break;
case 's':
angle += 0.01f;
ly1 = angle;
//setCamera();
break;
case 'w':
angle -= 0.01f;
ly1 = angle;
//setCamera();
break;
case '2' :
x1= (-1) * lx1 * 0.1 + x1;
z1 = (-1) * lz1 * 0.1 + z1;
//setCamera();
break;
case '1':
x1 = (1) * lx1 * 0.1 + x1;
z1 = (1) * lz1 * 0.1 + z1;
//setCamera();
break;
}
glutPostRedisplay(); }
and
void setCamera() {
glLoadIdentity();
gluLookAt(x1, yi, z1, x1 + lx1, yi + ly1, z1 + lz1, 0, 1, 0);
}
There is setCamera() function in display() function as well. What I thought about this was every time I type inputs, variables that are inserted in gluLookAt() function gets updated and will draw a new image by glutPostRedisplay(), whereas former image remains. Are there anything I'd overlook?
Related
Just another question! I'm trying to make the circle bounce around, but it's not working I even tried the most basic way, of just adding a value (from a 'step' int) to the circle x, but it's not working. What's the approach I should follow?
I know it's a basic question, but I'm knew to this :)
float time;
PFont font1;
/*float posX, posY, velX, velY, raio;
int dirX = 1;
int dirY = -1;*/
int passo = 2;
color c1 = color (253, 196, 80, 40);
color c2 = color(254, 127, 168, 40);
color c3 = color (53, 63, 114, 80);
color c4 = color (206, 186, 221, 80);
void setup() {
size(600, 800);
smooth();
background (#F6C4C7);
ellipseMode(RADIUS);
noStroke();
time = 17;
}
//make gradient
void desenhar_grad(float posX, float posY, int raio, color color1, color color2) {
pushStyle();
noStroke();
for (int r = raio; r > 0; r--) {
int tom = lerpColor(color1, color2, map(r, 0, raio, 0.0, 1.0)); // os últimos dois valores são as cores. o primeiro é o centro, o segundo é o exterior
fill(tom);
circle(posX, posY, r * 2);
}
popStyle();
}
/*void move() {
posY+=velY*dirY;
if (posY>height-raio || posY<raio)
dirY*=-1;
posX+=velX*dirX;
if (posX>width-raio || posX<raio)
dirX*=-1;
}*/
void draw () {
smooth();
for (int linha = 0; linha < 3; linha++) {
for (int coluna = 0; coluna < 3; coluna++) {
if (time <= 19) {
desenhar_grad(150 + coluna * 150, 200 + linha * 150, 30, c1, c2);
} else
desenhar_grad(150 + coluna * 150, 200 + linha * 150, 30, c4, c3);
}
}
}
} ```
Also, should I create a class for the circles in order to optimize the code?
Thank you!
I see your attempt with using the move() function (and related variables).
Again, close, but there are a few gotchas:
the values used in move() should be initialised: otherwise they'll default to 0 and any number multiplied by 0 is 0 which will result in no movement at all
once you have computed the correct posX, posY you could use those to translate() everything (i.e. the gradients): once everything is translated the 150, 200 offsets could be removed (and used as posX, posY initial values)
it's unclear with the "pivot" of the 3x3 gradient grid should be at the centre or the top left corner of the grid. Let's start with the simpler top left option. This can easily be changed later to centre simply by adding had the grid size to posX and posY
Here's a modified version of your sketch using the notes above:
float time;
// initialise movement variables
float posX = 150, posY = 200, velX = 1, velY = 1;
int raio = 30;
int dirX = 1;
int dirY = -1;
color c1 = color (253, 196, 80, 40);
color c2 = color(254, 127, 168, 40);
color c3 = color (53, 63, 114, 80);
color c4 = color (206, 186, 221, 80);
void setup() {
size(600, 800);
smooth();
ellipseMode(RADIUS);
smooth();
noStroke();
time = 17;
}
//make gradient
void desenhar_grad(float posX, float posY, int raio, color color1, color color2) {
pushStyle();
noStroke();
for (int r = raio; r > 0; r--) {
int tom = lerpColor(color1, color2, map(r, 0, raio, 0.0, 1.0)); // os últimos dois valores são as cores. o primeiro é o centro, o segundo é o exterior
fill(tom);
circle(posX, posY, r * 2);
}
popStyle();
}
void move() {
posY += velY * dirY;
if (posY > height - raio || posY < raio)
dirY *= -1;
posX += velX * dirX;
if (posX > width - raio || posX < raio)
dirX *= -1;
// for testing only:
println("posX",posX, "width", width, "posY", posY, "height", height);
}
void draw () {
if(!mousePressed) background (#F6C4C7);
// update posX, posY taking sketch borders into account
move();
// translate everything to the updated position
translate(posX, posY);
for (int linha = 0; linha < 3; linha++) {
for (int coluna = 0; coluna < 3; coluna++) {
if (time <= 19) {
desenhar_grad(coluna * 150, linha * 150, raio, c1, c2);
} else
desenhar_grad(coluna * 150, linha * 150, raio, c4, c3);
}
}
}
I've removed unused variables for clarity and added a few comments.
There are still a few confusing, perhaps unrelated items:
should the screen be cleared or should the grid leave trails ? (for now you can leave trails by holding the mouse pressed, but you can easily choose when to call background() based on the look you're going for)
how should the time variable be updated ? Currently it's set to 17 in setup() and doesn't change making the if/else condition inside the nested for loops redundant. Perhaps you meant to update in draw() based on some conditions ?
should the grid move as a whole or should each gradient move on its own ? my assumption is you're trying move the grid altogether however if you want to move each gradient on its own bare in mind you will need to use an array for each variable used in move() so it can be updated independently for each gradient (e.g. float[] posX, posY, velX, velY).)
Side note: If the movement is this simple you could get away with pos and
vel variables and not use dir variables:
void move() {
posY += velY;
if (posY > height - raio || posY < raio)
velY *= -1;
posX += velX;
if (posX > width - raio || posX < raio)
velY *= -1;
}
Manually updating each x,y variable is a great way to learn.
At a later date you might find PVector useful for movement.
int main()
{
const auto console = ::GetConsoleWindow();
const auto context = ::GetDC(console);
constexpr auto red = RGB(255, 0, 0);
constexpr auto yellow = RGB(255, 255, 0);
RECT rectClient, rectWindow;
GetClientRect(console, &rectClient);
GetWindowRect(console, &rectWindow);
int posx, posy;
posx = GetSystemMetrics(SM_CXSCREEN) / 2 - (rectWindow.right - rectWindow.left) / 2;
posy = GetSystemMetrics(SM_CYSCREEN) / 2 - (rectWindow.bottom - rectWindow.top) / 2;
const int radius = 150;
for (int y = -radius; y <= radius; y++)
for (int x = -radius; x <= radius; x++)
if (x * x + y * y <= radius * radius)
SetPixel(context, posx + x, posy + y, red);
}
It gives me this result img
it looks good but i saw this weird pixels at sides (up, down, right, left)
img
and this is what I want (I added some pixels at the top so it looks better)
enter image description here
Your "what I want" looks anti-aliased. So draw anti-aliased.
If the original condition is not met, but x*x + y*y <= (radius+1)*(radius+1) is met then you need a partially-shaded pixel.
Another way to do anti-aliasing is to test not the center of each pixel but the four corners (x \plusminus 0.5, y \plusminus 0.5). If more than zero but fewer than four corners are inside the circle, you need a partially-shaded pixel.
Now, I know similar questions have been asked. But none of the answers has helped me to find the result I need.
Following situation:
We have a line with a point-of-origin (PO), given as lx, ly. We also have an angle for the line in that it exits PO, where 0° means horizontally to the right, positive degrees mean clockwise. The angle is in [0;360[. Additionally we have the length of the line, since it is not infinitely long, as len.
There is also a circle with the given center-point (CP), given as cx, cy. The radius is given as cr.
I now need a function that takes these numbers as parameters and returns the distance of the closest intersection between line and circle to the PO, or -1 if no intersection occures.
My current approach is a follows:
float getDistance(float lx, float ly, float angle, float len, float cx, float cy, float cr) {
float nlx = lx - cx;
float nly = ly - cy;
float m = tan(angle);
float b = (-lx) * m;
// a = m^2 + 1
// b = 2 * m * b
// c = b^2 - cr^2
float[] x_12 = quadraticFormula(sq(m) + 1, 2*m*b, sq(b) - sq(cr));
// if no intersections
if (Float.isNaN(x_12[0]) && Float.isNaN(x_12[1]))
return -1;
float distance;
if (Float.isNaN(x_12[0])) {
distance = (x_12[1] - nlx) / cos(angle);
} else {
distance = (x_12[0] - nlx) / cos(angle);
}
if (distance <= len) {
return distance;
}
return -1;
}
// solves for x
float[] quadraticFormula(float a, float b, float c) {
float[] results = new float[2];
results[0] = (-b + sqrt(sq(b) - 4 * a * c)) / (2*a);
results[1] = (-b - sqrt(sq(b) - 4 * a * c)) / (2*a);
return results;
}
But the result is not as wished. Sometimes I do get a distance returned, but that is rarely correct, there often isn't even an intersection occuring. Most of the time no intersection is returned though, although there should be one.
Any help would be much appreciated.
EDIT:
I managed to find the solution thanks to MBo's answer. Here is the content of my finished getDistance(...)-function - maybe somebody can be helped by it:
float nlx = lx - cx;
float nly = ly - cy;
float dx = cos(angle);
float dy = sin(angle);
float[] results = quadraticFormula(1, 2*(nlx*dx + nly*dy), sq(nlx)+sq(nly)-sq(cr));
float dist = -1;
if (results[0] >= 0 && results[0] <= len)
dist = results[0];
if (results[1] >= 0 && results[1] <= len && results[1] < results[0])
dist = results[1];
return dist;
Using your nlx, nly, we can build parametric equation of line segment
dx = Cos(angle)
dy = Sin(Angle)
x = nlx + t * dx
y = nly + t * dy
Condition of intersection with circumference:
(nlx + t * dx)^2 + (nly + t * dy)^2 = cr^2
t^2 * (dx^2 + dy^2) + t * (2*nlx*dx + 2*nly*dy) + nlx^2+nly^2-cr^2 = 0
so we have quadratic equation for unknown parameter t with
a = 1
b = 2*(nlx*dx + nly*dy)
c = nlx^2+nly^2-cr^2
solve quadratic equation, find whether t lies in range 0..len.
// https://openprocessing.org/sketch/8009#
// by https://openprocessing.org/user/54?view=sketches
float circleX = 200;
float circleY = 200;
float circleRadius = 100;
float lineX1 = 350;
float lineY1 = 350;
float lineX2, lineY2;
void setup() {
size(400, 400);
ellipseMode(RADIUS);
smooth();
}
void draw() {
background(204);
lineX2 = mouseX;
lineY2 = mouseY;
if (circleLineIntersect(lineX1, lineY1, lineX2, lineY2, circleX, circleY, circleRadius) == true) {
noFill();
}
else {
fill(255);
}
ellipse(circleX, circleY, circleRadius, circleRadius);
line(lineX1, lineY1, lineX2, lineY2);
}
// Code adapted from Paul Bourke:
// http://local.wasp.uwa.edu.au/~pbourke/geometry/sphereline/raysphere.c
boolean circleLineIntersect(float x1, float y1, float x2, float y2, float cx, float cy, float cr ) {
float dx = x2 - x1;
float dy = y2 - y1;
float a = dx * dx + dy * dy;
float b = 2 * (dx * (x1 - cx) + dy * (y1 - cy));
float c = cx * cx + cy * cy;
c += x1 * x1 + y1 * y1;
c -= 2 * (cx * x1 + cy * y1);
c -= cr * cr;
float bb4ac = b * b - 4 * a * c;
//println(bb4ac);
if (bb4ac < 0) { // Not intersecting
return false;
}
else {
float mu = (-b + sqrt( b*b - 4*a*c )) / (2*a);
float ix1 = x1 + mu*(dx);
float iy1 = y1 + mu*(dy);
mu = (-b - sqrt(b*b - 4*a*c )) / (2*a);
float ix2 = x1 + mu*(dx);
float iy2 = y1 + mu*(dy);
// The intersection points
ellipse(ix1, iy1, 10, 10);
ellipse(ix2, iy2, 10, 10);
float testX;
float testY;
// Figure out which point is closer to the circle
if (dist(x1, y1, cx, cy) < dist(x2, y2, cx, cy)) {
testX = x2;
testY = y2;
} else {
testX = x1;
testY = y1;
}
if (dist(testX, testY, ix1, iy1) < dist(x1, y1, x2, y2) || dist(testX, testY, ix2, iy2) < dist(x1, y1, x2, y2)) {
return true;
} else {
return false;
}
}
}
I am working on a game that rotates an object on the z axis. I need to limit the total rotation to 80 degrees. I tried the following code, but it doesn't work. minAngle = -40.0f and maxAngle = 40.0f
Vector3 pos = transform.position;
pos.z = Mathf.Clamp(pos.z, minAngle, maxAngle);
transform.position = pos;
The code you posted clamps the z position. What you want is to use transform.rotation
void ClampRotation(float minAngle, float maxAngle, float clampAroundAngle = 0)
{
//clampAroundAngle is the angle you want the clamp to originate from
//For example a value of 90, with a min=-45 and max=45, will let the angle go 45 degrees away from 90
//Adjust to make 0 be right side up
clampAroundAngle += 180;
//Get the angle of the z axis and rotate it up side down
float z = transform.rotation.eulerAngles.z - clampAroundAngle;
z = WrapAngle(z);
//Move range to [-180, 180]
z -= 180;
//Clamp to desired range
z = Mathf.Clamp(z, minAngle, maxAngle);
//Move range back to [0, 360]
z += 180;
//Set the angle back to the transform and rotate it back to right side up
transform.rotation = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y, z + clampAroundAngle);
}
//Make sure angle is within 0,360 range
float WrapAngle(float angle)
{
//If its negative rotate until its positive
while (angle < 0)
angle += 360;
//If its to positive rotate until within range
return Mathf.Repeat(angle, 360);
}
Here's a static version of the nice solution by Imapler that, instead of changing the angle itself, it returns the campled angle, so it can be used with any axis.
public static float ClampAngle(
float currentValue,
float minAngle,
float maxAngle,
float clampAroundAngle = 0
) {
return Mathf.Clamp(
WrapAngle(currentValue - (clampAroundAngle + 180)) - 180,
minAngle,
maxAngle
) + 360 + clampAroundAngle;
}
public static float WrapAngle(float angle)
{
while (angle < 0) {
angle += 360;
}
return Mathf.Repeat(angle, 360);
}
Or if you don't expect to use the WrapAngle method, here's an all-in-one version:
public static float ClampAngle(
float currentValue,
float minAngle,
float maxAngle,
float clampAroundAngle = 0
) {
float angle = currentValue - (clampAroundAngle + 180);
while (angle < 0) {
angle += 360;
}
angle = Mathf.Repeat(angle, 360);
return Mathf.Clamp(
angle - 180,
minAngle,
maxAngle
) + 360 + clampAroundAngle;
}
So now you can do:
transform.localEulerAngles.x = YourMathf.ClampAngle(
transform.localEulerAngles.x,
minX,
maxX
);
I am writing a simple ray shader and I am trying to prodcue a dice with a cube and a number of spheres representing the dots. The spheres are correct, but the sides of the cube are on the x, y and z axes. The cube is centred around 0, 0, 0.
I have checked that the coordinate of the vertices are correct. I am assuming that my ray calculation is correct as the spheres are in the correct positions.
Here is the code for the ray calculation
Ray Image::RayThruPixel(float i, float j)
{
float alpha = m_tanFOVx * ((j - m_halfWidth) / m_halfWidth);
float beta = m_tanFOVy * ((m_halfHeight - i) / m_halfHeight);
vec3 *coordFrame = m_camera.CoordFrame();
vec3 p1 = (coordFrame[U_VEC] * alpha) + (coordFrame[V_VEC] * beta) - coordFrame[W_VEC];
return Ray(m_camera.Eye(), p1);
}
where m_tanFOVx is tan(FOVx / 2) and m_tanFOVy is tan(FOVy / 2) FOVx and FOVy are in radians.
To find the intersection of the ray and triangle my code is as follows:
bool Triangle::Intersection(Ray ray, float &fDistance)
{
static float epsilon = 0.000001;
bool bHit = false;
float fMinDist(10000000);
float divisor = glm::dot(ray.p1, normal);
// if divisor == 0 then the ray is parallel with the triangle
if(divisor > -epsilon && divisor < epsilon)
{
bHit = false;
}
else
{
float t = (glm::dot(v0, normal) - glm::dot(ray.p0, normal)) / divisor;
if(t > 0)
{
vec3 P = ray.p0 + (ray.p1 * t);
vec3 v2 = P - m_vertexA;
v0 = m_vertexB - m_vertexA;
v1 = m_vertexC - m_vertexA;
normal = glm::normalize(glm::cross(v0, v1));
d00 = glm::dot(v0, v0);
d01 = glm::dot(v0, v1);
d11 = glm::dot(v1, v1);
denom = d00 * d11 - d01 * d01;
float d20 = glm::dot(v2, v0);
float d21 = glm::dot(v2, v1);
float alpha = (d11 * d20 - d01 * d21) / denom;
float beta = (d00 * d21 - d01 * d20) / denom;
float gamma = 1.0 - alpha - beta;
vec3 testP = alpha * m_vertexA + beta * m_vertexB + gamma * m_vertexC;
if((alpha >= 0 ) &&
(beta >= 0) &&
(alpha + beta <= 1))
{
bHit = true;
fDistance = t;
}
}
}
return bHit;
}