Having a little trouble creating a fractal in opengl. Here is my current code
void generateTree(){
Point3f startPoint({0.0f,0.0f,0.0f});
Point3f endPoint({1.0f,0.0f,0.0f});
float rotation = 90.0f;
glutWireSphere(0.05, 4, 4);
_generateTreeBranches(startPoint,1.0f,rotation,0);
}
void _generateTreeBranches(const Point3f& newPosition,
float length,
float rotation,
const int depth)
{
if(depth > MAX_DEPTH) return;
cout << "at depth = " << depth << endl;
if(depth == 0){
glColor3f(1.0f,1.0f,1.0f);
}else if(depth == 1){
glColor3f(1.0f,0.0f,0.0f);
}else{
glColor3f(0.0f,1.0f,0.0f);
}
glTranslatef(newPosition.x,newPosition.y,newPosition.z);
glRotatef(rotation, 0.0f, 0.0f, 1.0f);
drawLine(length);
glRotatef(-rotation, 0.0f, 0.0f, 1.0f);
glTranslatef(-newPosition.x,-newPosition.y,-newPosition.z);
const float newLength = length * BRANCH_LENGTH_DECREASE_FACTOR;
int nextDepth = depth + 1;
Point3f nextPosition = {newPosition.x+length, newPosition.y, newPosition.z};
float leftRotation = rotation + CHILD_BRANCH_ANGLE * nextDepth;
_generateTreeBranches(nextPosition,newLength,leftRotation,nextDepth);
float rightRotation = rotation - CHILD_BRANCH_ANGLE * nextDepth;
_generateTreeBranches(nextPosition,newLength,rightRotation,nextDepth);
}
The positioning isn't correct, although the rotation seems to be right. The new branches arent' being draw starting at the end point of the parent's branch. Can someone help me on fixing this problem. Check out the full code here
The formula for nextPosition is incorrect as it didn't factor in the direction which the current branch is facing
Point3f nextPosition = {newPosition.x+length, newPosition.y, newPosition.z};
It should be something like this (please check exactly):
Point3f nextPosition = {newPosition.x+length*cos(rotation), newPosition.y+length*sin(rotation), newPosition.z};
Also, please use glLoadIdentity() to reset the matrix immediately like this:
glTranslatef(newPosition.x,newPosition.y,newPosition.z);
glRotatef(rotation, 0.0f, 0.0f, 1.0f);
drawLine(length);
glLoadIdentity();
It will be much clearer than what you are trying to do.
Related
I want to control my camera so that it can rotate around the model.
The theoretical code should be:
// `camera_rotation_angle_x_` and `camera_rotation_angle_y_` are initialized to 0, and can be modified by the user.
glm::mat4 CreateViewMatrix(glm::vec3 eye_pos, glm::vec3 scene_center, glm::vec3 up_vec) {
auto eye_transform = glm::translate(glm::mat4(1.0f), -scene_center); // recenter
eye_transform = glm::rotate(eye_transform, camera_rotation_angle_x_, glm::vec3(1.0f, 0.0f, 0.0f));
eye_transform = glm::rotate(eye_transform, camera_rotation_angle_y_, glm::vec3(0.0f, 1.0f, 0.0f));
eye_transform = glm::translate(eye_transform, scene_center); // move back
eye_pos = eye_transform * glm::vec4(eye_pos, 1.0f);
up_vec = eye_transform * glm::vec4(up_vec, 0.0f);
return glm::lookAt(eye_pos, scene_center, up_vec);
}
But the two lines "recenter" and "move back" must be written as follows to rotate correctly, otherwise the distance from the camera to the center will vary when the rotation parameters change:
auto eye_transform = glm::translate(glm::mat4(1.0f), scene_center); // recenter *The sign has changed*
...
eye_transform = glm::translate(eye_transform, -scene_center); // move back *The sign has changed*
...
// Correctness test, only when the distance remains constant, the rotation logic is correct.
cout << "eye_pos: " << eye_pos[0] << ", " << eye_pos[1] << ", " << eye_pos[2] << endl;
cout << "distance: " << (sqrt(
pow(eye_pos[0] - scene_center[0], 2)
+ pow(eye_pos[1] - scene_center[1], 2)
+ pow(eye_pos[2] - scene_center[2], 2)
)) << endl;
It is the correct logic to subtract the central value first and then add it back. It does not make any sense to add and then subtract.
So what's going wrong that I have to write code with logic errors in order for it to work properly?
The caller's code is below, maybe the bug is here?
// `kEyePos`, `kSceneCenter`, `kUpVec`, `kFovY`, `kAspect`, `kDistanceEyeToBack` and `kLightPos` are constants throughout the lifetime of the program
UniformBufferObject ubo{};
ubo.model = glm::mat4(1.0f);
ubo.view = CreateViewMatrix(kEyePos, kSceneCenter, kUpVec);
ubo.proj = glm::perspective(kFovY, kAspect, 0.1f, kDistanceEyeToBack);
// GLM was originally designed for OpenGL, where the Y coordinate of the clip coordinates is inverted.
// The easiest way to compensate for that is to flip the sign on the scaling factor of the Y axis in the projection matrix.
// Because of the Y-flip we did in the projection matrix, the vertices are now being drawn in counter-clockwise order instead of clockwise order.
// This causes backface culling to kick in and prevents any geometry from being drawn.
// You should modify the frontFace in `VkPipelineRasterizationStateCreateInfo` to `VK_FRONT_FACE_COUNTER_CLOCKWISE` to correct this.
ubo.proj[1][1] *= -1;
ubo.light_pos = glm::vec4(kLightPos, 1.0f); // The w component of point is 1
memcpy(vk_buffer_->GetUniformBufferMapped(frame_index), &ubo, sizeof(ubo));
I found that the problem was with the order of matrix construction, not with the glm::lookAt method.
m = glm::rotate(m, angle, up_vec)
is equivalent to
m = m * glm::rotate(glm::mat4(1), angle, up_vec)
, not
m = glm::rotate(glm::mat4(1), angle, up_vec) * m
as I thought.
This easily explains why swapping "recenter" and "move back" works properly.
The correct code is as follows:
glm::mat4 VulkanRendering::CreateViewMatrix(glm::vec3 eye_pos, glm::vec3 scene_center, glm::vec3 up_vec) const {
// Create transform matrix in reverse order.
// First rotate around the X axis, and then around the Y axis, otherwise it does not match the practice of most games.
auto view_transform = glm::translate(glm::mat4(1.0f), scene_center); // last: move back
view_transform = glm::rotate(view_transform, camera_rotation_angle_y_, glm::vec3(0.0f, 1.0f, 0.0f));
view_transform = glm::rotate(view_transform, camera_rotation_angle_x_, glm::vec3(1.0f, 0.0f, 0.0f));
view_transform = glm::translate(view_transform, -scene_center); // first: recenter
eye_pos = view_transform * glm::vec4(eye_pos, 1.0f); // The w component of point is 1
up_vec = view_transform * glm::vec4(up_vec, 0.0f); // The w component of vector is 0
return glm::lookAt(eye_pos, scene_center, up_vec);
}
Ive found some things for drawing any image using DX11, so i need rotate this image around center of this image, but my math is bad :).
void UpdateBuffers(int positionX, int positionY)
{
if((positionX == m_previousPosX) && (positionY == m_previousPosY))
return;
m_previousPosX = positionX;
m_previousPosY = positionY;
float left = (float)((m_screenWidth / 2) * -1) + (float)positionX;
float right = left + (float)m_bitmapWidth;
float top = (float)(m_screenHeight / 2) - (float)positionY;
float bottom = top - (float)m_bitmapHeight;
D3D11_MAPPED_SUBRESOURCE mappedResource;
HRESULT result = m_render->m_pImmediateContext->Map(m_vertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
if(FAILED(result))
return;
Vertex *verticesPtr = (Vertex*)mappedResource.pData;
verticesPtr[0].pos = XMFLOAT3(left, top, 0.0f);
verticesPtr[0].tex = XMFLOAT2(0.0f, 0.0f);
verticesPtr[1].pos = XMFLOAT3(right, bottom, 0.0f);
verticesPtr[1].tex = XMFLOAT2(1.0f, 1.0f);
verticesPtr[2].pos = XMFLOAT3(left, bottom, 0.0f);
verticesPtr[2].tex = XMFLOAT2(0.0f, 1.0f);
verticesPtr[3].pos = XMFLOAT3(left, top, 0.0f);
verticesPtr[3].tex = XMFLOAT2(0.0f, 0.0f);
verticesPtr[4].pos = XMFLOAT3(right, top, 0.0f);
verticesPtr[4].tex = XMFLOAT2(1.0f, 0.0f);
verticesPtr[5].pos = XMFLOAT3(right, bottom, 0.0f);
verticesPtr[5].tex = XMFLOAT2(1.0f, 1.0f);
m_render->m_pImmediateContext->Unmap(m_vertexBuffer, 0);
}
As i understand im need 4 points for do this, but point struct should contains x and y axises, and this function have basiaclly x,y,w,h only and im bit confused with this. Mb somebody can help me.
In order to calculate the projection view matrix for a directional light I take the vertices of the frustum of my active camera, multiply them by the rotation of my directional light and use these rotated vertices to calculate the extends of an orthographic projection matrix for my directional light.
Then I create the view matrix using the center of my light's frustum bounding box as the position of the eye, the light's direction for the forward vector and then the Y axis as the up vector.
I calculate the camera frustum vertices by multiplying the 8 corners of a box with 2 as size and centered in the origin.
Everything works fine and the direction light projection view matrix is correct but I've encountered a big issue with this method.
Let's say that my camera is facing forward (0, 0, -1), positioned on the origin and with a zNear value of 1 and zFar of 100. Only objects visible from my camera frustum are rendered into the shadow map, so every object that has a Z position between -1 and -100.
The problem is, if my light has a direction which makes the light come from behind the camera and the is an object, for example, with a Z position of 10 (so behind the camera but still in front of the light) and tall enough to possibly cast a shadow on the scene visible from my camera, this object is not rendered into the shadow map because it's not included into my light frustum, resulting in an error not casting the shadow.
In order to solve this problem I was thinking of using the scene bounding box to calculate the light projection view Matrix, but doing this would be useless because the image rendered into the shadow map cuold be so large that numerous artifacts would be visible (shadow acne, etc...), so I skipped this solution.
How could I overcome this problem?
I've read this post under the section of 'Calculating a tight projection' to create my projection view matrix and, for clarity, this is my code:
Frustum* cameraFrustum = activeCamera->GetFrustum();
Vertex3f direction = GetDirection(); // z axis
Vertex3f perpVec1 = (direction ^ Vertex3f(0.0f, 0.0f, 1.0f)).Normalized(); // y axis
Vertex3f perpVec2 = (direction ^ perpVec1).Normalized(); // x axis
Matrix rotationMatrix;
rotationMatrix.m[0] = perpVec2.x; rotationMatrix.m[1] = perpVec1.x; rotationMatrix.m[2] = direction.x;
rotationMatrix.m[4] = perpVec2.y; rotationMatrix.m[5] = perpVec1.y; rotationMatrix.m[6] = direction.y;
rotationMatrix.m[8] = perpVec2.z; rotationMatrix.m[9] = perpVec1.z; rotationMatrix.m[10] = direction.z;
Vertex3f frustumVertices[8];
cameraFrustum->GetFrustumVertices(frustumVertices);
for (AInt i = 0; i < 8; i++)
frustumVertices[i] = rotationMatrix * frustumVertices[i];
Vertex3f minV = frustumVertices[0], maxV = frustumVertices[0];
for (AInt i = 1; i < 8; i++)
{
minV.x = min(minV.x, frustumVertices[i].x);
minV.y = min(minV.y, frustumVertices[i].y);
minV.z = min(minV.z, frustumVertices[i].z);
maxV.x = max(maxV.x, frustumVertices[i].x);
maxV.y = max(maxV.y, frustumVertices[i].y);
maxV.z = max(maxV.z, frustumVertices[i].z);
}
Vertex3f extends = maxV - minV;
extends *= 0.5f;
Matrix viewMatrix = Matrix::MakeLookAt(cameraFrustum->GetBoundingBoxCenter(), direction, perpVec1);
Matrix projectionMatrix = Matrix::MakeOrtho(-extends.x, extends.x, -extends.y, extends.y, -extends.z, extends.z);
Matrix projectionViewMatrix = projectionMatrix * viewMatrix;
SceneObject::SetMatrix("ViewMatrix", viewMatrix);
SceneObject::SetMatrix("ProjectionMatrix", projectionMatrix);
SceneObject::SetMatrix("ProjectionViewMatrix", projectionViewMatrix);
And this is how I calculate the frustum and it's bounding box:
Matrix inverseProjectionViewMatrix = projectionViewMatrix.Inversed();
Vertex3f points[8];
_frustumVertices[0] = inverseProjectionViewMatrix * Vertex3f(-1.0f, 1.0f, -1.0f); // near top-left
_frustumVertices[1] = inverseProjectionViewMatrix * Vertex3f( 1.0f, 1.0f, -1.0f); // near top-right
_frustumVertices[2] = inverseProjectionViewMatrix * Vertex3f(-1.0f, -1.0f, -1.0f); // near bottom-left
_frustumVertices[3] = inverseProjectionViewMatrix * Vertex3f( 1.0f, -1.0f, -1.0f); // near bottom-right
_frustumVertices[4] = inverseProjectionViewMatrix * Vertex3f(-1.0f, 1.0f, 1.0f); // far top-left
_frustumVertices[5] = inverseProjectionViewMatrix * Vertex3f( 1.0f, 1.0f, 1.0f); // far top-right
_frustumVertices[6] = inverseProjectionViewMatrix * Vertex3f(-1.0f, -1.0f, 1.0f); // far bottom-left
_frustumVertices[7] = inverseProjectionViewMatrix * Vertex3f( 1.0f, -1.0f, 1.0f); // far bottom-right
_boundingBoxMin = _frustumVertices[0];
_boundingBoxMax = _frustumVertices[0];
for (AInt i = 1; i < 8; i++)
{
_boundingBoxMin.x = min(_boundingBoxMin.x, _frustumVertices[i].x);
_boundingBoxMin.y = min(_boundingBoxMin.y, _frustumVertices[i].y);
_boundingBoxMin.z = min(_boundingBoxMin.z, _frustumVertices[i].z);
_boundingBoxMax.x = max(_boundingBoxMax.x, _frustumVertices[i].x);
_boundingBoxMax.y = max(_boundingBoxMax.y, _frustumVertices[i].y);
_boundingBoxMax.z = max(_boundingBoxMax.z, _frustumVertices[i].z);
}
_boundingBoxCenter = Vertex3f((_boundingBoxMin.x + _boundingBoxMax.x) / 2.0f, (_boundingBoxMin.y + _boundingBoxMax.y) / 2.0f, (_boundingBoxMin.z + _boundingBoxMax.z) / 2.0f);
I am trying to create my own quaternion class and I get weird results. Either the cube I am trying to rotate is flickering like crazy, or it is getting warped.
This is my code:
void Quaternion::AddRotation(vec4 v)
{
Quaternion temp(v.x, v.y, v.z, v.w);
*this = temp * (*this);
}
mat4 Quaternion::GenerateMatrix(Quaternion &q)
{
q.Normalize();
//Row order
mat4 m( 1 - 2*q.y*q.y - 2*q.z*q.z, 2*q.x*q.y - 2*q.w*q.z, 2*q.x*q.z + 2*q.w*q.y, 0,
2*q.x*q.y + 2*q.w*q.z, 1 - 2*q.x*q.x - 2*q.z*q.z, 2*q.y*q.z + 2*q.w*q.x, 0,
2*q.x*q.z - 2*q.w*q.y, 2*q.y*q.z - 2*q.w*q.x, 1 - 2*q.x*q.x - 2*q.y*q.y, 0,
0, 0, 0, 1);
//Col order
// mat4 m( 1 - 2*q.y*q.y - 2*q.z*q.z,2*q.x*q.y + 2*q.w*q.z,2*q.x*q.z - 2*q.w*q.y,0,
// 2*q.x*q.y - 2*q.w*q.z,1 - 2*q.x*q.x - 2*q.z*q.z,2*q.y*q.z - 2*q.w*q.x,0,
// 2*q.x*q.z + 2*q.w*q.y,2*q.y*q.z + 2*q.w*q.x,1 - 2*q.x*q.x - 2*q.y*q.y,0,
// 0,0,0,1);
return m;
}
When I create the entity I give it a quaternion:
entity->Quat.AddRotation(vec4(1.0f, 1.0f, 0.0f, 45.f));
And each frame I try to rotate it additionally by a small amount:
for (int i = 0; i < Entities.size(); i++)
{
if (Entities[i] != NULL)
{
Entities[i]->Quat.AddRotation(vec4(0.5f, 0.2f, 1.0f, 0.000005f));
Entities[i]->DrawModel();
}
else
break;
}
And finally this is how I draw each cube:
void Entity::DrawModel()
{
glPushMatrix();
//Rotation
mat4 RotationMatrix;
RotationMatrix = this->Quat.GenerateMatrix(this->Quat);
//Position
mat4 TranslationMatrix = glm::translate(mat4(1.0f), this->Pos);
this->Trans = TranslationMatrix * RotationMatrix;
glMultMatrixf(value_ptr(this->Trans));
if (this->shape != NULL)
this->shape->DrawShape();
glPopMatrix();
}
EDIT: This is the tutorial I used to learn quaternions:
http://www.cprogramming.com/tutorial/3d/quaternions.html
Without studying your rotation matrix to the end, there are two possible bugs I can think of. The first one is that your rotation matrix R is not orthogonal, i.e. the inverse of R is not equal to the transposed. This could cause warping of the object. The second place to hide a bug is inside the multiplication of your quaternions.
There's a mistake in the rotation matrix. Try exchanging the element (2,3) with element (3,2).
I'm trying to make a light source rotate around my character model in my OpenGL project, but as I try it, all I got so far is my model rotating like crazy (or the floor).
My rendering code looks like this:
void mainRender() {
updateState();
renderScene();
glFlush();
glutPostRedisplay();
//spin = (spin + 30) % 360;
Sleep(30);
}
void renderScene() {
glClearColor(backgrundColor[0],backgrundColor[1],backgrundColor[2],backgrundColor[3]);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // limpar o depth buffer
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
updateCam();
renderFloor();
modelAL.Translate(0.0f,1.0f,0.0f);
modelAL.Draw();
}
void renderFloor() {
// set things up to render the floor with the texture
glShadeModel(GL_SMOOTH);
glEnable(type);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glPushMatrix();
glTranslatef(-(float)planeSize/2.0f, 0.0f, -(float)planeSize/2.0f);
float textureScaleX = 10.0;
float textureScaleY = 10.0;
glColor4f(1.0f,1.0f,1.0f,1.0f);
int xQuads = 40;
int zQuads = 40;
for (int i = 0; i < xQuads; i++) {
for (int j = 0; j < zQuads; j++) {
glBegin(GL_QUADS);
glTexCoord2f(1.0f, 0.0f); // coords for the texture
glNormal3f(0.0f,1.0f,0.0f);
glVertex3f(i * (float)planeSize/xQuads, 0.0f, (j+1) * (float)planeSize/zQuads);
glTexCoord2f(0.0f, 0.0f); // coords for the texture
glNormal3f(0.0f,1.0f,0.0f);
glVertex3f((i+1) * (float)planeSize/xQuads, 0.0f, (j+1) * (float)planeSize/zQuads);
glTexCoord2f(0.0f, 1.0f); // coords for the texture
glNormal3f(0.0f,1.0f,0.0f);
glVertex3f((i+1) * (float)planeSize/xQuads, 0.0f, j * (float)planeSize/zQuads);
glTexCoord2f(1.0f, 1.0f); // coords for the texture
glNormal3f(0.0f,1.0f,0.0f);
glVertex3f(i * (float)planeSize/xQuads, 0.0f, j * (float)planeSize/zQuads);
glEnd();
}
}
glDisable(type);
glPopMatrix();
}
How could I make this new lightsource rotate around my "modelAL" object?
For the fixed pipeline, light source position assigned with glLight() are transformed with the model-view matrix, just as normal objects are. So you can use the transformation functions to position and rotate your light source as you would normal objects.
To rotate a light source (or other object) around a point, you need to follow these steps. Let L be where the light source will be when the rotation is 0 degrees, and O be the subject - the object around which you want to rotate the light source.
Position the light source at L-O (the position of the light source relative to the subject)
Rotate it about the required axis (probably the Y axis)
Translate it by O to move it into position.
Because of the way OpenGL works, you essentially do these in backwards order. Basically it would go like this:
glPushMatrix();
glTranslatef(O.x,O.y,O.z);
glRotate(angle,0,1,0);
GLfloat lightpos[4] = {L.x-O.x,L.y-O.y,L.z-O.z,1};
glLightfv(GL_LIGHT0,GL_POSITION,lightpos);
glPopMatrix();
Note, this only applies to positioned light sources, not directional ones i.e. with w=0.