I am using a raytracer to render a Sphereflake, but I am having trouble trying to have more than object appear in the scene. In the scene below I am just trying to test out having two spheres in a scene, but for some reason only ever one sphere appears in the scene, and usually its the sphere with the largest radius.
Another peculiar thing is, even though there is a camera set in the scene, it seems as though the output window always shows the predominant object at the centre ((0,0) with screen coordinates between [-1,-1]->[1,1]) rather than in relevance to the camera coordinate space.
I am unsure if it is a parent hierarchy problem or how I'm rendering the objects, but any insight into why the problem is persisting would be greatly appreciated.
main.cpp (creates scenes renders objects)
#include <stdio.h>
#include <iostream>
#include <vector>
#include <math.h>
#include <glm.hpp>
#include <gtc/matrix_transform.hpp>
#include <Raytracer/Raytracer.h>
using namespace glm;
using namespace Raytracer;
using namespace Raytracer::Scenes;
using namespace Raytracer::Objects;
/**
* Places a few spheres in the scene and adds some lights.
*
* #param scene The scene
*/
Scene *BuildScene(int depth, float aspect)
{
const int materialCount = 6;
vec3 colors[materialCount] =
{
vec3(1.0f, 0.0f, 0.0f),
vec3(1.0f, 1.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f),
vec3(0.0f, 1.0f, 1.0f),
vec3(0.0f, 0.0f, 1.0f),
vec3(1.0f, 0.0f, 1.0f)
};
Material *materials[materialCount];
for (int i = 0; i < materialCount; i++)
{
materials[i] = new Material();
if (materials[i] == NULL)
return NULL;
vec3 ambient = colors[i] * 0.01f;
materials[i]->SetAmbient(ambient);
materials[i]->SetDiffuse(colors[i]);
materials[i]->SetShininess(25.0f);
}
if (depth <= 0)
return NULL;
// Create the scene.
Scene *scene = new Scene();
if (scene == NULL)
return NULL;
Sphere * s1 = new Sphere(0.33f, materials[5]);
s1->SetPosition(vec3(5.0f, 0.0f, -2.0f));
Sphere * s2 = new Sphere(0.33f, materials[1]);
s2->SetPosition(vec3((5.0f, 0.33f, -2.0f));
s1->AddChild(s2);
// Create a light.
Light *light = new PointLight(vec3(10.0f));
if (light == NULL)
{
delete scene;
return NULL;
}
light->SetPosition(vec3(-5.0f, 3.0f, 2.0f));
scene->AddChild(light);
// Create a camera.
Camera *camera = new Camera(vec3(-2.0f, 2.0f, 4.0f), vec3(0.0f, 0.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f), Camera::DefaultFov, aspect);
scene->AddChild(s1);
if (camera == NULL)
{
delete scene;
return NULL;
}
scene->AddChild(camera);
scene->SetActiveCamera(camera);
return scene;
}
/**
* Renders the scene and saves the result to a BMP file.
*
* #param fileName The name of the file
* #param width The image width
* #param height The image height
*/
void Render(const char *fileName, int width, int height)
{
if (fileName == NULL || width <= 0 || height <= 0)
return;
SimpleRenderer renderer;
renderer.SetAccelerator(new SimpleAccelerator());
renderer.SetIntegrator(new PhongIntegrator());
puts("Generiere Szene...");
Scene *scene = BuildScene(3, (float)width / height);
if (scene == NULL)
return;
puts("Rendere Bild...");
Image *image = renderer.Render(*scene, width, height);
if (image != NULL)
{
puts("Speichere Ergebnis...");
image->SaveBMP(fileName, 2.2f);
delete image;
}
delete scene;
}
/**
* The main program
*/
int main()
{
Render("image.bmp", 512, 512);
return 0;
}
example of a scene with two spheres as stated above with s1.radius = 0.33f & s2.radius = 0.33f
scene 1
another example of a scene with two spheres with s1.radius = 0.33f & s2.radius = 1.0f
scene 2
As you can see, it seems the camera is invalid as a point of perspective, as no matter what the position of the sphere is, the only difference is its lighting, but it will always be at the centre of the display window
Since s2 is attached as a child of s1, it's being drawn 5 units further down the X axis than s1:
s2->SetPosition(vec3((5.0f, 0.33f, -2.0f));
...
s1->AddChild(s2);
And since your camera is looking down the positive x axis:
Camera *camera = new Camera(vec3(-2.0f, 2.0f, 4.0f),
vec3(0.0f, 0.0f, 0.0f), vec3(0.0f, 1.0f, 0.0f), Camera::DefaultFov, aspect);
s2 is simply being drawn behind s1.
It turns out it was not a problem with my scene builder, but how the child/parent inherritance works in another class SceneObject*. Anyway, I fixed the AddChild function and now the code now works with the camera perspective and with mulitple items in the scene
Related
I'm developing a first-person camera in my project of DirectX, the problem is that I don't know how to move my mesh with the camera, It only works like a normal camera that can move around the world and can rotate with the mouse, but can move it with the mesh, It only stays static.
I already try to multiply my view matrix with the Matrix of the Mesh, but it seems to make a really weird thing like deforming the mesh or getting a wrong perspective.
This is my code that moves the camera :
void CManager::cameraMove(ID3D11DeviceContext* &pImmediateContext, ID3D11Buffer*&pCBNeverChanges, WPARAM wParam, float xPos, float yPos)
{
if (wParam == 37) // Left
{
Camera.g_View *= XMMatrixTranslation(m_Cx, 0.0f, 0.0f);
//DwarfMatrix = Camera.g_View;
//DwarfMatrix *= translate;
}
else if (wParam == 'W') // Front
{
Camera.g_View *= XMMatrixTranslation(0.0f, 0.0f, -m_Cz);
}
else if (wParam == 39) // Right
{
Camera.g_View *= XMMatrixTranslation(-m_Cx, 0.0f, 0.0f);
//DwarfMatrix *= translateN;
}
else if (wParam == 'S') // Back
{
Camera.g_View *= XMMatrixTranslation(0.0f, 0.0f, m_Cz);
}
else if (wParam == 38) // Up
{
Camera.g_View *= XMMatrixTranslation(0.0f, -m_Cy, 0.0f);
}
else if (wParam == 40) // Down
{
Camera.g_View *= XMMatrixTranslation(0.0f, m_Cy, 0.0f);
}
else if (wParam == 'C') // Change Texture
{
camChange();
}
Camera.cbNeverChanges.mView = XMMatrixTranspose(Camera.g_View);
pImmediateContext->UpdateSubresource(NeverChangeBuffer.m_Buffer, 0, NULL, &Camera.cbNeverChanges, 0, 0);
}
And here is the code of my model with his matrix:
XMMATRIX ModelMatrix = XMMATRIX(
.03f, 0.0f, 0.0f, m_x,
0.0f, .03f, 0.0f, m_y,
0.0f, 0.0f, .03f, m_z,
0.0f, 0.0f, 0.0f, 1.0f
);
// Asign the Model to his matrix in render
g_manager.m_mesh[i].m_object.mWorld = g_manager.ModelMatrix;
I expect to move the mesh with the camera matrix or with some matrix attached to the camera. I already have the camera working but not as I expect with the model.
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 have to present a menu like this in the picture :
where this buttons can move arround the cercle in the center similar to 3D effect, means you can see there dimensions transformation while moving.
I remember that iCarroussel project can do such things, Could Any pne guide me to the right control that provide this animation?
Thanks.
EDIT1 :
Ok I am able to see that iCarousel is almost what I need, but how to change the carousel vertical angle to get like the first picture? see how iCarousel is by default.
What you need to do is the following (Step by step as indicated below)
Download iCarousel ...
Open the sample project under Tests/ARC iOS (open iCarouselExample.xcodeproj)
Set default to "Cylinder" instead of "Coverflow" (in the viewDidLoad function of iCarouselExampleViewController.m)
- (void)viewDidLoad
{
[super viewDidLoad];
carousel.type = iCarouselTypeCylinder;
navItem.title = #"Cylinder";
}
Since you need just six items in your custom carousel set a "number of panes" in iCarouselExampleViewContoller.h as ...
//NOTE!
#define NUMBER_OF_ITEMS 6
Use this NUMBER_OF_ITEMS to setup the carousel (i.e. in iCarouselExampleViewContoller.m change the setup function as follows (use 'wrap' as shown)
- (void)setUp
{
//set up data
wrap = YES;
self.items = [NSMutableArray array];
//NOTE! use preset number of vars in Carousel
//for (int i = 0; i < 10000; i++)
for (int i=0; i< NUMBER_OF_ITEMS; i++)
{
[items addObject:[NSNumber numberWithInt:i]];
}
}
Now provide the perspective in iCarousel by updating the _perspective parameter in the uCarousel class. Do this in the setup function of iCarousel.m:
- (void)setUp
{
_type = iCarouselTypeLinear;
//NOTE! Tweak perspective parameters
_perspective = -1.0f/750.0f;
... etc ...
}
Finally give the entire view a "tilt" about the X axis by rotating the carousel by 15 degrees about the x axis. The way to do this is to tweak the transform matrix (set transform = CATransform3DRotate(transform, -15.0f*M_PI/180.0f, 1.0f, 0.0f, 0.0f) In code, in the iCarousel.m's transformForItemView function update this as follows:
- (CATransform3D)transformForItemView:(UIView *)view withOffset:(CGFloat)offset
{
//set up base transform
CATransform3D transform = CATransform3DIdentity;
transform.m34 = _perspective;
transform = CATransform3DTranslate(transform, -_viewpointOffset.width, _viewpointOffset.height, 0.0f);
//perform transform
switch (_type)
{
.... SKIPPED THE INITIAL SECTIONS OF THIS CODE WE MAKE OUR CHANGE IN THE CYLINDER SECTION ...
case iCarouselTypeCylinder:
case iCarouselTypeInvertedCylinder:
{
CGFloat count = [self circularCarouselItemCount];
CGFloat spacing = [self valueForOption:iCarouselOptionSpacing withDefault:1.0f];
CGFloat arc = [self valueForOption:iCarouselOptionArc withDefault:M_PI * 2.0f];
CGFloat radius = [self valueForOption:iCarouselOptionRadius withDefault:fmaxf(0.01f, _itemWidth * spacing / 2.0f / tanf(arc/2.0f/count))];
CGFloat angle = [self valueForOption:iCarouselOptionAngle withDefault:offset / count * arc];
if (_type == iCarouselTypeInvertedCylinder)
{
radius = -radius;
angle = -angle;
}
if (_vertical)
{
transform = CATransform3DTranslate(transform, 0.0f, 0.0f, -radius);
transform = CATransform3DRotate(transform, angle, -1.0f, 0.0f, 0.0f);
return CATransform3DTranslate(transform, 0.0f, 0.0f, radius + 0.01f);
}
else
{
transform = CATransform3DTranslate(transform, 0.0f, 0.0f, -radius);
//NOTE! Give it a tilt about the "X" axis
transform = CATransform3DRotate(transform, -15.0f*M_PI/180.0f, 1.0f, 0.0f, 0.0f);
transform = CATransform3DRotate(transform, angle, 0.0f, 1.0f, 0.0f);
return CATransform3DTranslate(transform, 0.0f, 0.0f, radius + 0.01f);
}
I'm trying to rotate a simple triangle. The problem is that while it rotates correctly, it decrease its size until it disappears.
Some pieces of my code so far:
// Vertices
GLfloat vertexArray[] =
{
1.0f, -1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
// Render funcion (called every frame)
void render()
{
glClearColor(0.0f, 0.0f, 0.4f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObj);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexArray), vertexArray, GL_DYNAMIC_DRAW);
glUseProgram(programID); // simple vertex/frag shader
glDrawArrays(GL_TRIANGLES, 0, 3);
// Swap buffers
glfwSwapBuffers();
}
// Update funcion (called every frame before render function)
void update(float elapsedTime)
{
printf("elapsedTime: %f \r", elapsedTime);
float static theta = elapsedTime * 0.2f;
for(int i = 0; i < 9; i+=3)
{
vertexArray[i] = (vertexArray[i] * cosf(theta)) - (vertexArray[i+1] * sinf(theta));
vertexArray[i+1] = (vertexArray[i] * sinf(theta)) + (vertexArray[i+1] * cosf(theta));
vertexArray[i+2] = 0;
}
}
As you can see, I'm rotating every vertex on update function with a for loop. Maybe the best way to do this is using the shader (correct me if I'm wrong), but I wanted to keep things simple here just to illustrate the problem.
I believe the problem is, that when you compute vertexArray[i+1] = (vertexArray[i] * sinf(theta)) + (vertexArray[i+1] * cosf(theta)); you are not using the value of vertexArray[i] from the previous iteration, but rather the new vertexArray[i] computed in the first assignment of the for loop.
Try this:
for(int i = 0; i < 9; i+=3)
{
double tmp = vertexArray[i];
vertexArray[i] = (tmp * cosf(theta)) - (vertexArray[i+1] * sinf(theta));
vertexArray[i+1] = (tmp * sinf(theta)) + (vertexArray[i+1] * cosf(theta));
vertexArray[i+2] = 0;
}
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.