How to ripple on a sphere - c++

I'm trying to implement a program that turns a cube into a sphere based on key presses, and ripples whenever it's clicked. I managed to implement the cube-to-sphere-and-back part, but I have completely no idea where to start on the rippling. I've looked at tons of sources online, I get the math, but I have no idea how to implement it on my vertex shader. Can anyone help me with my dilemma? Thank you!
Here's my cpp, vsh, and fsh: https://drive.google.com/file/d/0B4hkcF9foOTgbUozMjZmSHJhQWM/view?usp=sharing
I'm using GLSL, OpenGL 4.4.0
Here's my code for the vertex shader:
#version 120
attribute vec3 pos;
varying vec4 out_color;
uniform float t;
float PI = 3.14159265357;
int factor = 2; //for determining colors
int num_colors; // = factor * 3 (because RGB)
float currang = 0;
float angfac;
vec4 calculate( float a )
{
//this is just to calculate for the color
}
void main() {
num_colors = factor*3;
angfac = 2*PI/num_colors;
float ang = atan( pos.z, pos.x )+PI;
out_color = calculate(ang);
//rotation
mat3 rotateX = mat3(
vec3( 1, 0, 0),
vec3( 0, cos(t), sin(t)),
vec3( 0, -sin(t), cos(t))
);
mat3 rotateY = mat3(
vec3( cos(t), 0, -sin(t)),
vec3( 0, 1, 0),
vec3( sin(t), 0, cos(t))
);
mat3 rotateZ = mat3(
vec3( cos(t), sin(t), 0),
vec3(-sin(t), cos(t), 0),
vec3( 0, 0, cos(t))
);
gl_Position = gl_ModelViewProjectionMatrix * vec4((pos.xyz*rotateY*rotateX) , 1.0 );
}
and here's parts of my cpp file:
//usual include statements
using namespace std;
enum { ATTRIB_POS };
GLuint mainProgram = 0;
// I use this to indicate the position of the vertices
struct Vtx {
GLfloat x, y, z;
};
const GLfloat PI = 3.14159265357;
const int sideLength = 10;
const size_t nVertices = (sideLength*sideLength*sideLength)-((sideLength-2)*(sideLength-2)*(sideLength-2));
Vtx cube[nVertices];
Vtx sphere[nVertices];
Vtx diff[nVertices];
const double TIME_SPEED = 0.01;
int mI = 4*(sideLength-1);
const int sLCubed = sideLength*sideLength*sideLength;
int indices[nVertices*nVertices];
GLfloat originX = 0.0f; //offset
GLfloat originY = 0.0f; //offset
bool loadShaderSource(GLuint shader, const char *path) {...}
void checkShaderStatus(GLuint shader) {...}
bool initShader() {...}
//in this part of the code, I instantiate an array of indices to be used by glDrawElements()
void transform(int fac)
{
//move from cube to sphere and back by adding/subtracting values and updating cube[].xyz
//moveSpeed = diff[]/speedFac
//fac is to determine direction (going to sphere or going to cube; going to sphere is plus, going back to cube is minus)
for( int i = 0; i<nVertices; i++ )
{
cube[i].x += fac*diff[i].x;
cube[i].y += fac*diff[i].y;
cube[i].z += fac*diff[i].z;
}
}
void initCube() {...} //computation for the vertices of the cube depending on sideLength
void initSphere() {...} //computation for the vertices of the sphere based on the vertices of the cube
void toSphere() {...} //changes the values of the array of vertices of the cube to those of the sphere
void initDiff() {...} //computes for the difference of the values of the vertices of the sphere and the vertices of the cube for the slow transformation
int main() {
//error checking (GLEW, OpenGL versions, etc)
glfwSetWindowTitle("CS177 Final Project");
glfwEnable( GLFW_STICKY_KEYS );
glfwSwapInterval( 1 );
glClearColor(0,0,0,0);
if ( !initShader() ) {
return -1;
}
glEnableVertexAttribArray(ATTRIB_POS);
glVertexAttribPointer(ATTRIB_POS, 3, GL_FLOAT, GL_FALSE, sizeof(Vtx), cube);
initCube();
initIndices();
initSphere();
initDiff();
glUseProgram(mainProgram);
GLuint UNIF_T = glGetUniformLocation(mainProgram, "t");
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
float t = 0;
glUniform1f(UNIF_T, t);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glPointSize(2.0);
glEnable(GL_POINT_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glfwOpenWindowHint(GLFW_FSAA_SAMPLES,16);
glEnable(GL_MULTISAMPLE);
do {
int width, height;
glfwGetWindowSize( &width, &height );
glViewport( 0, 0, width, height );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
t += TIME_SPEED;
glUniform1f(UNIF_T, t);
if (glfwGetKey(GLFW_KEY_DEL)) transform(-1);
if (glfwGetKey(GLFW_KEY_INSERT)) transform( 1 );
if (glfwGetKey(GLFW_KEY_HOME)) initCube();
if (glfwGetKey(GLFW_KEY_END)) toSphere();
glDrawElements( GL_TRIANGLES, nVertices*nVertices, GL_UNSIGNED_INT, indices);
glfwSwapBuffers();
} while ( glfwGetKey(GLFW_KEY_ESC) != GLFW_PRESS &&
glfwGetWindowParam(GLFW_OPENED) );
glDeleteProgram(mainProgram);
glfwTerminate();
return 0;
}

Related

How to draw a rotated texture including text on top of output texture buffer using OpenGL

I have developed an opengl application where we draw strings of text using freetype and opengl.
I want to achieve rotation capability for the text that I put on OpenGL window.
For instance, "This is a text" string should be calculated and put into a buffer on a plain background and then refactored with a rotation value, so that the text will be visible as such below
I also have a text background that is just a regular texture with a buffer. I manually fill this background with a uint8_t buffer which can contain anything ranging from a single colour to an image buffer.
struct Background{
Color color;
Texture* bg_texture;
int x, y;
int w, h;
uint8_t* buffer;
explicit Background(int x, int y):x(x), y(y)
{
};
void create_bg_buffer();
~Background()
{
free(buffer);
}
};
void Background::create_bg_buffer()
{
int w = this->w;
int h = this->h;
if (posix_memalign((void**)&this->buffer, 128, w * h * 4) != 0)
{
VI_ERROR("ERROR::FREETYTPE: Couldn't allocate frame buffer ");
}
int c = 0;
for ( int i = 0; i < w; i++ )
{
for ( int j = 0; j < h; j++ )
{
this->buffer[ c + 0 ] = this->color.get_color_char(Utils::RED);
this->buffer[ c + 1 ] = this->color.get_color_char(Utils::GREEN);
this->buffer[ c + 2 ] = this->color.get_color_char(Utils::BLUE);
this->buffer[ c + 3 ] = 0xFF;
c += 4;
}
}
}
I want users to be able to rotate this text with it's background with a given angle. In on itself, rotating this is a tedious task. So I want to draw the text inside the backgrounds buffer itself, and then rotate it.
Please note that the way I rotate a background, for different reasons is not using an opengl function but rather taking the rectangle's middle point and rotating each point manually and passing those points to opengl with this code:
cpp
...
GLfloat vertices[32] = {
// positions // colors // texture coords
pos.TR_x, pos.TR_y, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top right
pos.BR_x, pos.BR_y, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, // bottom right
pos.BL_x, pos.BL_y, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom left
pos.TL_x, pos.TL_y, 1.0f, 0.1f, 0.1f, 0.1f, 0.0f, 0.0f // top left
};
unsigned int indices[] = {
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
...
Every pos stands for a rotated position, with labels indicating positions such as TR stands for top-right.
We want to use a Framebuffer for the output buffer. Then we want to use this framebuffer to be used for actual OpenGL output.
How should we alter the render_text function so that it will use the framebuffer to prepare the string from each individual character.
void Text::render_text(float angle_rad, bool has_bg)
{
if(has_bg) background->bg_texture->render(background->w, background->h, background->buffer, 1);
int start_y = ty + background->h;
start_y = ( std::abs(start_y - SCR_HEIGHT) / 2);
int total_h_index = 0;
for(auto& line: lines)
{
line.y = start_y;
line.x = tx;
total_h_index += line.total_height + LINE_GAP;
calc_pos(line.x, line.y, line.total_width, line.total_height, total_h_index);
for (c = line.text.begin(); c != line.text.end(); c++)
{
Character ch = Characters[*c];
line.char_h.push_back(ch.Size.y);
line.chars_y.push_back( line.y - (ch.Size.y - ch.Bearing.y) );
}
}
// glEnable(GL_CULL_FACE);
// glDisable(GL_BLEND);
// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
shader.use();
glUniform3f(glGetUniformLocation(shader.ID, "textColor"), color.r, color.g, color.b);
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(VAO);
GLfloat vertices[6][4] = {
{ 0.0, 1.0, 0.0, 0.0 },
{ 0.0, 0.0, 0.0, 1.0 },
{ 1.0, 0.0, 1.0, 1.0 },
{ 0.0, 1.0, 0.0, 0.0 },
{ 1.0, 0.0, 1.0, 1.0 },
{ 1.0, 1.0, 1.0, 0.0 }
};
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); // Be sure to use glBufferSubData and not glBufferData
glBindBuffer(GL_ARRAY_BUFFER, 0);
GLint transition_loc = glGetUniformLocation(shader.ID, "transparency");
glUniform1f(transition_loc, 1.0f);
for(auto& line: lines)
{
GLfloat char_x = 0.0f;
std::string str = line.text;
glm::mat4 transOriginM = glm::translate(glm::mat4(1.0f), glm::vec3(line.x, line.y, 0));
glm::mat4 rotateM = glm::rotate(glm::mat4(1.0f), glm::radians(-angle_rad), glm::vec3(0.0f, 0.0f, 1.0f));
int e = 0;
std::vector<glm::vec2> rotated_pos = calc_rotation(line.chars_x, line.chars_y, -angle_rad, line.total_width);
for (c = str.begin(); c != str.end(); c++)
{
Character ch = Characters[*c];
GLfloat w = ch.Size.x;
GLfloat h = ch.Size.y;
GLfloat xrel = rotated_pos[e].x ; // char_x
GLfloat yrel = rotated_pos[e].y;
// Now advance cursors for next glyph (note that advance is number of 1/64 pixels)
e++; // Bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels))
glm::mat4 transRelM = glm::translate(glm::mat4(1.0f), glm::vec3(xrel, yrel, 0));
glm::mat4 scaleM = glm::scale(glm::mat4(1.0f), glm::vec3(w, h, 1.0f));
// Keep the translation matrix that sets the position of the text before the rotation matrix
glm::mat4 modelM = transOriginM * transRelM * rotateM * scaleM;
GLint model_loc = glGetUniformLocation(shader.ID, "model");
glUniformMatrix4fv(model_loc, 1, GL_FALSE, glm::value_ptr(modelM));
// Render glyph texture over quad
glBindTexture(GL_TEXTURE_2D, ch.TextureID);
// Render quad
glDrawArrays(GL_TRIANGLES, 0, 6);
}
}
As of now, "Adding a character or text" is completely independent from the background operation.
They are just positioned in a way, so it looks like it has a background.
Our aim is to use a single output buffer that will hold both background color and freetype text data.
Following is how we handle the texture and texture rotation mechanism :
#define _VERTICIZE_X(number, global) _VERTICIZE(number, global) - 1
#define _VERTICIZE_Y(number, global) _VERTICIZE(number, global) + 1
namespace OpenGL
{
Texture::Texture(int x, int y, int w, int h, int gw, int gh, float angle)
{
Utils::Point rotatedPoints[4] = {
{x, y},
{x + w, y},
{x, y + h},
{x + w, y + h},
};
Utils::RotateRectangle(rotatedPoints, angle);
pos.TL_x = _VERTICIZE_X(rotatedPoints[0].x, gw); pos.TL_y = -_VERTICIZE_Y(rotatedPoints[0].y, gh);
pos.TR_x = _VERTICIZE_X(rotatedPoints[1].x, gw); pos.TR_y = -_VERTICIZE_Y(rotatedPoints[1].y, gh);
pos.BL_x = _VERTICIZE_X(rotatedPoints[2].x, gw); pos.BL_y = -_VERTICIZE_Y(rotatedPoints[2].y, gh);
pos.BR_x = _VERTICIZE_X(rotatedPoints[3].x, gw); pos.BR_y = -_VERTICIZE_Y(rotatedPoints[3].y, gh);
}
int Texture::init(float alpha, std::string* filter, Utils::Color proj_filt)
{
shader = Shader("./src/opengl/shaders/texture_shaders/texture.vs", "./src/opengl/shaders/texture_shaders/texture.fs");
void RotateRectangle(Point (&points)[4], float angle) {
// Calculate the center point
Point center = { 0 };
for (int i = 0; i < 4; i++) {
center.x += points[i].x;
center.y += points[i].y;
}
center.x /= 4;
center.y /= 4;
// Rotate each point
float angleRadians = angle * M_PI / 180.0f;
float s = sin(angleRadians);
float c = cos(angleRadians);
for (int i = 0; i < 4; i++) {
// Subtract the center point to get a vector from the center to the point
Point vector = { points[i].x - center.x, points[i].y - center.y };
// Rotate the vector
float x = vector.x;
float y = vector.y;
vector.x = x * c - y * s;
vector.y = x * s + y * c;
// Add the center point back to the rotated vector to get the new point
points[i].x = vector.x + center.x;
points[i].y = vector.y + center.y;
}
}
How can we use a framebuffer so that all OpenGL and FreeType operation are going to be executed in a single output space, and following that depending our way we can rotate the whole text using this single output framebuffer ?

How to implement interactive rotation operations in a decent way

Recently, I want to achieve interactive rotation operations as can be done in meshlab:
Basically, it achieves rotation of three degrees of freedom. I visualize these operations as following codes with the help of GLFW:
static void mouse_move_callback(GLFWwindow* window, double xpos, double ypos){
...
do{
//perform rotation operations only if keeping the right mouse key pressed
if(glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_RELEASE) {
g_clr_right_mouse = true;
break;
}
/*clear mouse state once transferred from release state
to pressed state to prevent from a instant flicker*/
if(g_clr_right_mouse){
g_lastX = xpos;
g_lastY = ypos;
g_clr_right_mouse = false;
}
float xoffset = xpos - g_lastX; //let movement from down to top positive
float yoffset = g_lastY - ypos;
g_lastX = xpos;
g_lastY = ypos;
//do counterclockwise rotation around x-asis with movement in y direction
glm::mat4 r1 = glm::rotate(glm::mat4(), glm::radians(-yoffset * 0.5f), glm::vec3(1.0f,0.0f,0.0f));
//do counterclockwise rotation around y-asis with movement in x direction
glm::mat4 r2 = glm::rotate(glm::mat4(), glm::radians( xoffset * 0.5f), glm::vec3(0.0f,1.0f,0.0f));
glm::mat4 tmp = r2 * r1 * g_model;
for(int i=0; i<3; i++)
g_model[i] = tmp[i];
return ;
}while(false);
}
These codes are located here, and the whole project can be found here which can be downloaded and built. Finally, it performs as follows:
However, my implementation can only achieve rotation operations of 2 DOF, I add a keyboard callback to achieve rotation around the z axis:
void keyboard_callback(GLFWwindow* window, int key, int scancode, int action, int mod){
if(glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS){
glm::mat4 r3 = glm::rotate(glm::mat4(), glm::radians(3.0f), glm::vec3(0,0,1.0f));
glm::mat4 tmp = r3 * g_model;
for(int i=0; i<3; i++)
g_model[i] = tmp[i];
}else if(glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS){
glm::mat4 r3 = glm::rotate(glm::mat4(), glm::radians(-3.0f), glm::vec3(0,0,1.0f));
glm::mat4 tmp = r3 * g_model;
for(int i=0; i<3; i++)
g_model[i] = tmp[i];
}
}
So my question is how to decently achieve interactive rotation operations of 3 DOF only with mouse movement?
When dragging the mouse, the object must be rotated around an axis that is perpendicular to the direction of movement of the mouse. The pivot is the origin of the model.
Rotate the mouse movement vector by 90 ° in the XY plane of the view. Since this is a vector in view space, the vector must be transformed from view space into world space. The matrix that transforms a vector from view space to world space is the inverse matrix of the upper left 3x3 of the view matrix:
vec2 drag_start;
vec2 drag_end;
glm::mat3 to_world = glm::inverse(glm::mat3(view_matrix));
glm::vec2 drag_vec = glm::vec2(drag_end.x - drag_start.x, drag_start.y - drag_end.y);
glm::vec3 axis_vec = glm::normalize(to_world * glm::vec3(-drag_vec.y, drag_vec.x, 0));
Create a rotation matrix around the axis. The angle depends on the length of the vector (height is the height of the viewport in pixels):
GLfloat angle = glm::length(drag_vec) / height / 2 * M_PI;
drag_rotation = glm::rotate(glm::mat4(1.0f), angle, axis_vec);
Compute a rotation matrix while dragging the mouse. Concatenate the rotation matrix and the model matrix after the drag ends:
glm::mat4 view_matrix(1.0f);
glm::mat4 model_rotation(1.0f);
glm::mat4 drag_rotation(1.0f);
glm::vec2 drag_start(0.0f);
bool drag = false;
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
{
if (button != GLFW_MOUSE_BUTTON_LEFT)
return;
if (action == GLFW_PRESS)
{
drag = true;
double xpos, ypos;
glfwGetCursorPos(window, &xpos, &ypos);
drag_start = glm::vec2(xpos, ypos);
}
else if (action == GLFW_RELEASE)
{
drag = false;
model_rotation = drag_rotation * model_rotation;
drag_rotation = glm::mat4(1.0f);
}
}
void cursor_position_callback(GLFWwindow* window, double xpos, double ypos)
{
if (!drag)
return;
glm::mat3 to_world = glm::inverse(glm::mat3(view_matrix));
glm::vec2 drag_vec = glm::vec2(xpos - drag_start.x, drag_start.y - ypos);
glm::vec3 axis_vec = glm::normalize(to_world * glm::vec3(-drag_vec.y, drag_vec.x, 0));
GLfloat angle = glm::length(drag_vec) / height / 2 * M_PI;
drag_rotation = glm::rotate(glm::mat4(1.0f), angle, axis_vec);
}
The model matrix is the concatenation of drag_rotation and model_rotation:
glm::mat4 model = drag_rotation * model_rotation;
See also Orbit
Complete example:
#include <GL/glew.h>
#include <GL/gl.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <GLFW/glfw3.h>
#include <vector>
#include <string>
#include <stdexcept>
#include <iostream>
#define _USE_MATH_DEFINES
#include <cmath>
#include <math.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
std::string sh_vert = R"(
#version 460 core
layout (location = 0) in vec4 a_position;
layout (location = 1) in vec3 a_uvw;
out vec3 v_uvw;
layout (location = 0) uniform mat4 u_projection;
layout (location = 1) uniform mat4 u_view;
layout (location = 2) uniform mat4 u_model;
void main()
{
v_uvw = a_uvw;
gl_Position = u_projection * u_view * u_model * a_position;
}
)";
std::string sh_frag = R"(
#version 460 core
out vec4 frag_color;
in vec3 v_uvw;
vec3 HUEtoRGB(in float H)
{
float R = abs(H * 6.0 - 3.0) - 1.0;
float G = 2.0 - abs(H * 6.0 - 2.0);
float B = 2.0 - abs(H * 6.0 - 4.0);
return clamp(vec3(R, G, B), 0.0, 1.0);
}
void main()
{
frag_color = vec4(HUEtoRGB(v_uvw.z), 1.0);
}
)";
class ShaderProgram
{
public:
GLuint programObject;
static ShaderProgram newProgram(const std::string& vsh, const std::string& fsh);
private:
GLuint compileShader(const std::string& sourceCode, GLenum shaderType);
void linkProgram(std::vector<GLuint> shObjs);
void compileStatus(GLuint shader);
void linkStatus();
};
class VertexArrayObject
{
public:
GLuint vaoObject = 0;
GLsizei noOfVertices = 0;
GLsizei noOfIndices = 0;
static VertexArrayObject newCube();
static VertexArrayObject newCircles();
static VertexArrayObject newVAO(const std::vector<GLfloat>& varray, const std::vector<GLuint>& iarray);
};
int width = 800, height = 600;
glm::mat4 view_matrix(1.0f);
glm::mat4 model_rotation(1.0f);
glm::mat4 drag_rotation(1.0f);
glm::vec2 drag_start(0.0f);
bool drag = false;
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
{
if (button != GLFW_MOUSE_BUTTON_LEFT)
return;
if (action == GLFW_PRESS)
{
drag = true;
double xpos, ypos;
glfwGetCursorPos(window, &xpos, &ypos);
drag_start = glm::vec2(xpos, ypos);
}
else if (action == GLFW_RELEASE)
{
drag = false;
model_rotation = drag_rotation * model_rotation;
drag_rotation = glm::mat4(1.0f);
}
}
void cursor_position_callback(GLFWwindow* window, double xpos, double ypos)
{
if (!drag)
return;
glm::mat3 to_world = glm::inverse(glm::mat3(view_matrix));
glm::vec2 drag_vec = glm::vec2(xpos - drag_start.x, drag_start.y - ypos);
glm::vec3 axis_vec = glm::normalize(to_world * glm::vec3(-drag_vec.y, drag_vec.x, 0));
GLfloat angle = glm::length(drag_vec) / height / 2 * M_PI;
drag_rotation = glm::rotate(glm::mat4(1.0f), angle, axis_vec);
}
int main(void)
{
if (glfwInit() == GLFW_FALSE)
throw std::runtime_error( "error initializing glfw" );
glfwWindowHint(GLFW_SAMPLES, 8);
GLFWwindow * window = glfwCreateWindow(width, height, "OGL window", nullptr, nullptr);
if (window == nullptr)
{
glfwTerminate();
throw std::runtime_error( "error initializing window" );
}
glfwSetMouseButtonCallback(window, mouse_button_callback);
glfwSetCursorPosCallback(window, cursor_position_callback);
glfwMakeContextCurrent(window);
if ( glewInit() != GLEW_OK )
throw std::runtime_error( "error initializing glew" );
auto progam = ShaderProgram::newProgram(sh_vert, sh_frag);
auto cube = VertexArrayObject::newCube();
auto circles = VertexArrayObject::newCircles();
glUseProgram(progam.programObject);
glEnable( GL_DEPTH_TEST );
glClearColor(0.1f, 0.3f, 0.2f, 0.0f);
view_matrix = glm::lookAt(glm::vec3(0.0f, 0.0f, 7.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
glUniformMatrix4fv(1, 1, GL_FALSE, glm::value_ptr(view_matrix));
while (!glfwWindowShouldClose(window))
{
glfwGetFramebufferSize(window, &width, &height);
float ascpect = (float)width / (float)height;
glm::mat4 project = glm::perspective(glm::radians(60.0f), ascpect, 0.1f, 20.0f);
glUniformMatrix4fv(0, 1, GL_FALSE, glm::value_ptr(project));
glm::mat4 model = drag_rotation * model_rotation;
glViewport(0, 0, width, height);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glUniformMatrix4fv(2, 1, GL_FALSE, glm::value_ptr(model));
glBindVertexArray(cube.vaoObject);
glDrawElements(GL_TRIANGLES, cube.noOfIndices, GL_UNSIGNED_INT, nullptr);
glUniformMatrix4fv(2, 1, GL_FALSE, glm::value_ptr(glm::scale(model, glm::vec3(2.5f))));
glBindVertexArray(circles.vaoObject);
glDrawElements(GL_LINES, circles.noOfIndices, GL_UNSIGNED_INT, nullptr);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
ShaderProgram ShaderProgram::newProgram(const std::string& vsh, const std::string& fsh)
{
ShaderProgram program;
auto shObjs = std::vector<GLuint>
{
program.compileShader(vsh, GL_VERTEX_SHADER),
program.compileShader(fsh, GL_FRAGMENT_SHADER),
};
for (auto shObj : shObjs)
program.compileStatus(shObj);
program.linkProgram(shObjs);
for (auto shObj : shObjs)
glDeleteShader(shObj);
return program;
}
GLuint ShaderProgram::compileShader(const std::string& sourceCode, GLenum shaderType)
{
auto shaderObj = glCreateShader(shaderType);
const char* srcCodePtr = sourceCode.c_str();
glShaderSource(shaderObj, 1, &srcCodePtr, nullptr);
glCompileShader(shaderObj);
return shaderObj;
}
void ShaderProgram::linkProgram(std::vector<GLuint> shObjs)
{
programObject = glCreateProgram();
for (auto shObj : shObjs)
glAttachShader(programObject, shObj);
glLinkProgram(programObject);
linkStatus();
}
void ShaderProgram::compileStatus(GLuint shader)
{
GLint status = GL_TRUE;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
GLint logLen;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLen);
std::vector< char >log(logLen);
GLsizei written;
glGetShaderInfoLog(shader, logLen, &written, log.data());
std::cout << "compile error:" << std::endl << log.data() << std::endl;
}
}
void ShaderProgram::linkStatus()
{
GLint status = GL_TRUE;
glGetProgramiv(programObject, GL_LINK_STATUS, &status);
if (status == GL_FALSE)
{
GLint logLen;
glGetProgramiv(programObject, GL_INFO_LOG_LENGTH, &logLen);
std::vector< char >log(logLen);
GLsizei written;
glGetProgramInfoLog(programObject, logLen, &written, log.data());
std::cout << "link error:" << std::endl << log.data() << std::endl;
}
}
VertexArrayObject VertexArrayObject::newCube()
{
static const std::vector<GLfloat> vertices{ -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1 };
static const std::vector<GLfloat> uv{ 0, 0, 1, 0, 1, 1, 0, 1 };
static const std::vector<size_t> faces{ 0, 1, 2, 3, 1, 5, 6, 2, 5, 4, 7, 6, 4, 0, 3, 7, 3, 2, 6, 7, 1, 0, 4, 5 };
std::vector<GLfloat> varray;
std::vector<GLuint> iarray;
for (auto si = 0; si < faces.size() / 4; si++)
{
for (auto qi = 0; qi < 4; qi++)
{
varray.insert(varray.end(), vertices.begin() + faces[si * 4 + qi] * 3, vertices.begin() + faces[si * 4 + qi] * 3 + 3);
std::vector<GLfloat> uvw{ 0, 0, (GLfloat)si * 4.0f / (GLfloat)faces.size() };
varray.insert(varray.end(), uvw.begin(), uvw.end());
}
std::vector<GLuint> indices{ 4u * si, 4u * si + 1, 4u * si + 2, 4u * si, 4u * si + 2, 4u * si + 3 };
iarray.insert(iarray.end(), indices.begin(), indices.end());
}
return newVAO(varray, iarray);
}
VertexArrayObject VertexArrayObject::newCircles()
{
const GLuint noC = 360;
std::vector<GLfloat> varray;
std::vector<GLuint> iarray;
for (int i = 0; i <= noC; i++)
{
GLfloat angle = static_cast<GLfloat>(i * 2 * M_PI / noC);
GLfloat c = cos(angle), s = sin(angle);
std::vector<GLfloat> va{ 0, c, s, 0, 0, 0, s, 0, c, 0, 0, 1.0f / 3.0f, c, s, 0, 0, 0, 2.0f / 3.0f };
varray.insert(varray.end(), va.begin(), va.end());
}
for (GLuint ci = 0; ci < 3; ci++)
{
for (GLuint i = 0; i <= noC; i++)
{
std::vector<GLuint> ia{ i * 3 + ci, ((i + 1) % noC) * 3 + ci };
iarray.insert(iarray.end(), ia.begin(), ia.end());
}
}
return newVAO(varray, iarray);
}
VertexArrayObject VertexArrayObject::newVAO(const std::vector<GLfloat>& varray, const std::vector<GLuint>& iarray)
{
VertexArrayObject vao;
vao.noOfIndices = static_cast<GLsizei>(iarray.size());
vao.noOfVertices = static_cast<GLsizei>(varray.size() / 6);
GLuint bufferObjects[2];
glGenBuffers(2, bufferObjects);;
glGenVertexArrays(1, &vao.vaoObject);
glBindVertexArray(vao.vaoObject);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, bufferObjects[0]);
glBufferData(GL_ARRAY_BUFFER, varray.size() * sizeof(*varray.data()), varray.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(*varray.data()), 0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(*varray.data()), (void*)(3 * sizeof(*varray.data())));
if (vao.noOfIndices > 0)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferObjects[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, iarray.size() * sizeof(*iarray.data()), iarray.data(), GL_STATIC_DRAW);
}
glBindVertexArray(0);
glDeleteBuffers(2, bufferObjects);
return vao;
}
You kinda need to draw the ball to make it intuitive.
On mouse down, you put an anchor on the ball directly under the mouse pointer. If the click is outside the ball, then you use the closest point on the ball.
As the mouse moves, you rotate the ball so that the anchor point follows the shortest path so that it remains directly under the mouse pointer. If the mouse pointer is off the ball, then the closest point on the ball is used.
Maybe this will help.

Arc with radius between 2 points [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 months ago.
Improve this question
I need to find out how to draw an arc with OpenGL between 2 points with a given radius.Is there any way to do this in OpenGL or to find the center point where I need to draw the arc so the both points get connected with the given radius ? :)
Attached screenshot: https://i.imgur.com/LLP78Ak.png
Here is a simple, but complete and tested opengl program that demonstrates what it sounds like you are looking for. Note that there is not a single answer to the question of what is the arc between two points at radius x, since the arc can bend in either of two directions.
Pay careful attention to the second createArc function overload as this represents the core of the answer, though it calls the first createArc function overload to finish the job.
EDIT: I've realized that I did not account for the ambiguity of "arc between two angles" in my earlier answer (arc from 0 to 90 could be direct or all the way around). I've updated the code to define whether you are interested in the smaller arc or the larger arc.
#define GLEW_STATIC
#define _USE_MATH_DEFINES
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <gl/gl.h>
#include <math.h>
#include <iostream>
const int ARC_VERTEX_COUNT = 100;
// Don't use global variables at home, kids!
GLFWwindow* window;
GLuint shader;
GLint shaderLoc_pos;
GLuint vbo_circle;
GLuint vbo_arc;
float normalizeAngleToSmallestPositive(float angle) {
while (angle < 0.0) { angle += M_PI*2; }
while (angle >= M_PI*2) { angle -= M_PI*2; }
return angle;
}
bool startApp() {
if (!glfwInit()) {
return false;
}
window = glfwCreateWindow(500, 500, "Hello World", NULL, NULL);
if (!window) {
glfwTerminate();
return false;
}
glfwMakeContextCurrent(window);
glewInit();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glLineWidth(10.0);
return true;
}
void stopApp() {
glfwTerminate();
}
void createShader() {
const char* vsSrc =
"#version 330 core\n"
"in vec2 pos; void main() { gl_Position = vec4(pos, 0.0, 1.0); }";
const char* fsSrc =
"#version 330 core\n"
"out vec4 color; void main() { color = vec4(1.0,1.0,1.0,0.5); }";
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, &vsSrc, nullptr);
glCompileShader(vs);
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, &fsSrc, nullptr);
glCompileShader(fs);
shader = glCreateProgram();
glAttachShader(shader, vs);
glAttachShader(shader, fs);
glLinkProgram(shader);
shaderLoc_pos = glGetAttribLocation(shader, "pos");
}
// Create an arc between two given angles, based on the circle described by the given radius and
// center point
GLuint createArc(float angle1, float angle2, float radius, float x, float y, float useBiggerArc) {
// Prepare angles
angle1 = normalizeAngleToSmallestPositive(angle1);
angle2 = normalizeAngleToSmallestPositive(angle2);
if (angle1 > angle2) {
float buffer = angle1;
angle1 = angle2;
angle2 = buffer;
}
if (useBiggerArc != angle2-angle1 > M_PI) {
angle1 += M_PI*2;
}
// Create opengl geometry
GLfloat pos[ARC_VERTEX_COUNT * 2];
for (int i = 0; i < ARC_VERTEX_COUNT; i++) {
pos[i*2] = sin((float)i / (ARC_VERTEX_COUNT-1) * (angle2 - angle1) + angle1) * radius + x;
pos[i*2+1] = cos((float)i / (ARC_VERTEX_COUNT-1) * (angle2 - angle1) + angle1) * radius + y;
}
GLuint result;
glGenBuffers(1, &result);
glBindBuffer(GL_ARRAY_BUFFER, result);
glBufferData(GL_ARRAY_BUFFER, sizeof(pos), pos, GL_STATIC_DRAW);
return result;
}
GLuint createCircle(float radius, float x, float y) {
return createArc(M_PI*0, M_PI*2, radius, x, y, true);
}
// Create an arc between two given points that is based on a circle with the given radius.
GLuint createArc(
float x1, float y1, float x2, float y2, float radius, bool arcDirection, bool useBiggerArc)
{
// distance between points
float distance = sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
// halfway point
float xAverage = (x1+x2)/2.0;
float yAverage = (y1+y2)/2.0;
// circle center
float xCenter = sqrt(radius*radius - distance*distance/4.0) * (y1-y2) / distance;
float yCenter = sqrt(radius*radius - distance*distance/4.0) * (x2-x1) / distance;
xCenter = xAverage + (arcDirection ? xCenter : -xCenter);
yCenter = yAverage + (arcDirection ? yCenter : -yCenter);
// angles
float angle1 = atan2(x1-xCenter, y1-yCenter);
float angle2 = atan2(x2-xCenter, y2-yCenter);
// create the arc
return createArc(angle1, angle2, radius, xCenter, yCenter, useBiggerArc);
}
void runMainLoop() {
while (!glfwWindowShouldClose(window)) {
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shader);
glEnableVertexAttribArray(shaderLoc_pos);
glBindBuffer(GL_ARRAY_BUFFER, vbo_circle);
glVertexAttribPointer(shaderLoc_pos, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
glDrawArrays(GL_LINE_STRIP, 0, ARC_VERTEX_COUNT);
glBindBuffer(GL_ARRAY_BUFFER, vbo_arc);
glVertexAttribPointer(shaderLoc_pos, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
glDrawArrays(GL_LINE_STRIP, 0, ARC_VERTEX_COUNT);
glfwSwapBuffers(window);
glfwPollEvents();
}
}
int main(void) {
if (startApp())
{
createShader();
vbo_circle = createCircle(0.75, 0.0, 0.0);
vbo_arc = createArc(0.0, 0.75, 0.75, 0.0, 0.75, false, false);
runMainLoop();
stopApp();
return 0;
}
else
{
return -1;
}
}
This is more of a maths question, I feel.
If you have the coordinates of the two points suppose:
and the given radius is 'R'
then the coordinates of the centre, say can be calculated using
where
,
there shall be two centres, one for an upward arc and another for a downward arc.
the other centre can be found through
now, you can find the inverse cosine using the acos() function included in the <cmath> library.

(OpenGL ShadowMap)Shadow cast on incorrect faces

Here is the demo image:
(Left top 256x256 rect is the depth texture)
I render the shadow map in the first pass(with parallel projection),
then render the scene in the second pass,
then render the scene with shadow map in the final pass.
the shadow is sometimes rendered twice or on the wrong surfaces
Is there any solution?
Full code here:
typedef struct
{
vec3_t org;//origin
vec3_t off;//position offset
vec3_t ang;//angle
float dist;//radius
int w;//default 512
int h;//default 512
int depth;//depth texture
int color;//color texture
int dimension;//default = 8
float mvmatrix[16];
float projmatrix[16];
cl_entity_t *followent;
int inuse;
}sdlight_t;
void R_RenderDepthMap()
{
qglPolygonOffset( 5.0, 0.0 );
qglEnable(GL_POLYGON_OFFSET_FILL);
if(cursdlight->followent)
{
VectorCopy(cursdlight->followent->origin, cursdlight->org);
}
qglMatrixMode(GL_PROJECTION);
qglLoadIdentity();
qglOrtho(-cursdlight->w / cursdlight->dimension, cursdlight->w / cursdlight->dimension, -cursdlight->h / cursdlight->dimension, cursdlight->h / cursdlight->dimension, -9999, 9999);//cursdlight->dist
qglMatrixMode(GL_MODELVIEW);
qglLoadIdentity();
qglRotatef(-90, 1, 0, 0);
qglRotatef(90, 0, 0, 1);
qglRotatef(-cursdlight->ang[2], 1, 0, 0);
qglRotatef(-cursdlight->ang[0], 0, 1, 0);
qglRotatef(-cursdlight->ang[1], 0, 0, 1);
qglTranslatef(-cursdlight->org[0], -cursdlight->org[1], -cursdlight->org[2]);
qglViewport(0, 0, cursdlight->w, cursdlight->h);
glGetFloatv(GL_PROJECTION_MATRIX, cursdlight->projmatrix);
glGetFloatv(GL_MODELVIEW_MATRIX, cursdlight->mvmatrix);
qglDepthRange(1.0, 0.0);
qglDepthFunc(GL_LEQUAL);
qglEnable(GL_CULL_FACE);
//qglCullFace(GL_FRONT);
qglClearColor(1, 1, 1, 1);
qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//Render Models..
R_DrawEntitiesOnList();
qglDisable(GL_POLYGON_OFFSET_FILL);
qglBindFramebufferEXT(GL_READ_FRAMEBUFFER, s_BackBufferFBO.s_hBackBufferFBO);
qglActiveTextureARB(GL_TEXTURE0);
qglBindTexture(GL_TEXTURE_2D, cursdlight->depth);
qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 0, 0, cursdlight->w, cursdlight->h, 0);
}
void R_SetupShadowLight(void)
{
// enable automatic texture coordinates generation
GLfloat planeS[] = {1.0, 0.0, 0.0, 0.0};
GLfloat planeT[] = {0.0, 1.0, 0.0, 0.0};
GLfloat planeR[] = {0.0, 0.0, 1.0, 0.0};
GLfloat planeQ[] = {0.0, 0.0, 0.0, 1.0};
// setup texture stages
qglActiveTextureARB(GL_TEXTURE0_ARB);
qglBindTexture(GL_TEXTURE_2D, cursdlight->depth);
qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_REF_TO_TEXTURE);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
qglTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY);
qglEnable(GL_TEXTURE_GEN_S);
qglEnable(GL_TEXTURE_GEN_T);
qglEnable(GL_TEXTURE_GEN_R);
qglEnable(GL_TEXTURE_GEN_Q);
qglTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
qglTexGenfv(GL_S, GL_EYE_PLANE, planeS);
qglTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
qglTexGenfv(GL_T, GL_EYE_PLANE, planeT);
qglTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
qglTexGenfv(GL_R, GL_EYE_PLANE, planeR);
qglTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
qglTexGenfv(GL_Q, GL_EYE_PLANE, planeQ);
// load texture projection matrix
qglMatrixMode(GL_TEXTURE);
qglLoadIdentity();
qglTranslatef(0.5, 0.5, 0.5);
qglScalef(0.5, 0.5, 0.5);
qglMultMatrixf(cursdlight->projmatrix);
qglMultMatrixf(cursdlight->mvmatrix);
qglMatrixMode(GL_MODELVIEW);
if (gl_polyoffset->value)
{
qglEnable(GL_POLYGON_OFFSET_FILL);
qglPolygonOffset(-1, -gl_polyoffset->value);
}
qglDepthMask(GL_FALSE);
qglEnable(GL_BLEND);
qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
qglColor4f(1,1,1,1);
qglUseProgramObjectARB(shadow_program);
qglUniform1iARB(shadow_uniform.shadowmap, 0);
}
void R_FinishShadowLight(void)
{
qglUseProgramObjectARB(0);
if (gl_polyoffset->value)
{
qglDisable(GL_POLYGON_OFFSET_FILL);
}
qglDepthMask(GL_TRUE);
qglDisable(GL_BLEND);
qglActiveTextureARB(GL_TEXTURE0_ARB);
qglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
qglMatrixMode(GL_TEXTURE);
qglLoadIdentity();
qglDisable(GL_TEXTURE_GEN_S);
qglDisable(GL_TEXTURE_GEN_T);
qglDisable(GL_TEXTURE_GEN_R);
qglDisable(GL_TEXTURE_GEN_Q);
qglMatrixMode(GL_MODELVIEW);
}
void R_DrawShadows(void)
{
for (int i = 0; i < numsdlights; i++)
{
cursdlight = &sdlights[i];
if(!R_ShouldCastShadow())
continue;
R_SetupShadowLight();
R_DrawSceneShadow();
R_FinishShadowLight();
}
}
GLSL part:
//vertex shader
varying vec4 shadowcoord;
void main()
{
shadowcoord = gl_TextureMatrix[0] * gl_Vertex;
gl_Position = ftransform();
}
//fragment shader
#version 120
uniform sampler2DShadow shadowmap;
varying vec4 shadowcoord;
uniform float xoffset = 1.0/512.0;
uniform float yoffset = 1.0/512.0;
float lookup(vec4 coord, vec2 offSet)
{
return shadow2DProj(shadowmap, coord + vec4(offSet.x * xoffset, offSet.y * yoffset, 0.0, 0.0) ).w;
}
void main()
{
float shadow;
shadow = lookup(shadowcoord, vec2(0.0,0.0)) + lookup(shadowcoord, vec2(0.035,0.0)) + lookup(shadowcoord, vec2(-0.035,0.0)) + lookup(shadowcoord, vec2(0.0,0.035)) + lookup(shadowcoord, vec2(0.0,-0.035));
shadow /= 5.0;
if(shadow == 1.0)
discard;
else
gl_FragColor = vec4(0.0, 0.0, 0.0, (1.0-shadow) * 0.5);
}

Rotation of my cube based on arcball quaternion rotation matrix slightly off

Im trying to rotate my cube using quaternion to matrix rotation based on arcball mouse movement. My cube is rendering, and it has movement/rotation, but it isnt simply just rotating around an axis, it is also moving in the direction of my mouse, so i think that either the data that im getting from my trackball is a bit off, or the way im transforming my quaternion into a rotation matrix is slightly off. trackball_ptov is where i translate mouse location to an arcball. mouseMotion() is where im creating the rotation matrix from the quaternion.
The entirety of my main:
#include "Angel.h"
#include <gl/glew.h>
#include <glut.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>
using namespace std;
#define bool int /* if system does not support bool type */
#define false 0
#define true 1
#define M_PI 3.14159265358 /* if not in math.h */
int winWidth, winHeight;
float angle = 0.0, axis[3], trans[3];
bool trackingMouse = false;
float lastPos[3] = {0.0, 0.0, 0.0};
float aspect = 1.0;
int curx, cury;
int startX, startY;
int modelInit=1;
//the program object
GLuint program = 0;
glm::mat4 model;
typedef Angel::vec4 color4;
typedef Angel::vec4 point4;
const int NumVertices = 36; //(6 faces)(2 triangles/face)(3 vertices/triangle)
point4 points[NumVertices];
color4 colors[NumVertices];
enum { Xaxis = 0, Yaxis = 1, Zaxis = 2, NumAxes = 3 };
int Axis = Xaxis;
GLuint mvpUniform;
GLuint shaderaxis;
int Index = 0;
// Vertices of a unit cube centered at origin, sides aligned with axes
point4 vertices[8]={
point4(-0.5, -0.5, 0.5, 1.0),
point4(-0.5, 0.5, 0.5, 1.0),
point4(0.5, 0.5, 0.5, 1.0),
point4(0.5, -0.5, 0.5, 1.0),
point4(-0.5, -0.5, -0.5, 1.0),
point4(-0.5, 0.5, -0.5, 1.0),
point4(0.5, 0.5, -0.5, 1.0),
point4(0.5, -0.5, -0.5, 1.0)
};
// RGBA colors
color4 vertex_colors[8] = {
color4(0.0, 0.0, 0.0, 1.0), // black
color4(1.0, 0.0, 0.0, 1.0), // red
color4(1.0, 1.0, 0.0, 1.0), // yellow
color4(0.0, 1.0, 0.0, 1.0), // green
color4(0.0, 0.0, 1.0, 1.0), // blue
color4(1.0, 0.0, 1.0, 1.0), // magenta
color4(1.0, 1.0, 1.0, 1.0), // white
color4(0.0, 1.0, 1.0, 1.0) // cyan
};
// quad generates two triangles for each face and assigns colors to the vertices
void quad(int a, int b, int c, int d) {
colors[Index] = vertex_colors[a]; points[Index] = vertices[a]; Index++;
colors[Index] = vertex_colors[b]; points[Index] = vertices[b]; Index++;
colors[Index] = vertex_colors[c]; points[Index] = vertices[c]; Index++;
colors[Index] = vertex_colors[a]; points[Index] = vertices[a]; Index++;
colors[Index] = vertex_colors[c]; points[Index] = vertices[c]; Index++;
colors[Index] = vertex_colors[d]; points[Index] = vertices[d]; Index++;
}
// generate 12 triangles: 36 vertices and 36 colors
void colorcube(void) {
quad(1, 0, 3, 2);
quad(2, 3, 7, 6);
quad(3, 0, 4, 7);
quad(6, 5, 1, 2);
quad(4, 5, 6, 7);
quad(5, 4, 0, 1);
}
// OpenGL initialization
void init(void) {
colorcube();
// Load shaders and use the resulting shader program
GLuint program = InitShader("vshader36.glsl", "fshader36.glsl");
glUseProgram(program);
// Create a vertex array object
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// Create and initialize a buffer object
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(points) + sizeof(colors), NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(points), points);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(points), sizeof(colors), colors);
// set up vertex arrays
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
model = glm::translate(glm::mat4(1.0), glm::vec3(0.0, 0.0, -5.0));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(sizeof(points)));
mvpUniform = glGetUniformLocation(program, "mvp");
glEnable(GL_DEPTH_TEST);
glClearColor(1.0, 1.0, 1.0, 1.0);
}
void trackball_ptov(int x, int y, int width, int height, float v[3]) {
float d, a;
/* project x, y onto a hemisphere centered within width, height , note z is up here*/
v[0] = (2.0*x - width) / width;
v[1] = (height - 2.0F*y) / height;
d = sqrt(v[0]*v[0] + v[1]*v[1]);
v[2] = cos((M_PI/2.0) * ((d < 1.0) ? d : 1.0));
a = 1.0 / sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
v[0] *= a;
v[1] *= a;
v[2] *= a;
}
void display() {
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glm::mat4 proj = glm::perspective(90.F, 1.F, 0.1F, 100.F);
glm::mat4 view = glm::translate(glm::mat4(1.0), glm::vec3(0.0, 0.0, 0.0)); //apply mouse translation
//view = glm::rotate(view, 0.2*mousediff.x, glm::vec3(0.0, 1.0, 0.0)); //apply mouse rotation
//view = glm::rotate(view, 0.2*mousediff.y, glm::vec3(1.0, 0.0, 0.0));
//model = glm::translate(glm::mat4(1.0), glm::vec3(0.0, 0.0, -5.0));
//glUniformMatrix4fv(mvpUniform, 1, false, glm::value_ptr(proj));
glUniformMatrix4fv(mvpUniform, 1, false, glm::value_ptr(proj*view*model));
//glUniformMatrix4fv(mvpUniform, 1, false, glm::value_ptr(model*view*proj));
glDrawArrays(GL_TRIANGLES, 0, NumVertices);
glutSwapBuffers();
}
void keyboard(unsigned char key, int x, int y) {
switch(key) {
case 033: // Escape Key
case 'q': case 'Q':
exit(EXIT_SUCCESS);
break;
}
}
void mouseButton(int button, int state, int x, int y) {
if(button==GLUT_RIGHT_BUTTON) exit(0);
/* holding down left button allows user to rotate cube */
if(button==GLUT_LEFT_BUTTON)
switch(state) {
case GLUT_DOWN:
trackingMouse = true;
startX = x;
startY = y;
curx = x;
cury = y;
trackball_ptov(x, y, 512, 512, lastPos);
break;
case GLUT_UP:
trackingMouse = false;
angle = 0.0;
break;
}
}
void mouseMotion(int x, int y) {
float curPos[3], dx, dy, dz;
/* compute position on hemisphere */
if(trackingMouse) {
/* compute the change in position on the hemisphere */
trackball_ptov(x, y, 512, 512, curPos);
dx = curPos[0] - lastPos[0];
dy = curPos[1] - lastPos[1];
dz = curPos[2] - lastPos[2];
if (dx || dy || dz) {
/* compute theta and cross product */
angle = 90.0 * sqrt(dx*dx + dy*dy + dz*dz);
axis[0] = lastPos[1]*curPos[2] - lastPos[2]*curPos[1];
axis[1] = lastPos[2]*curPos[0] - lastPos[0]*curPos[2];
axis[2] = lastPos[0]*curPos[1] - lastPos[1]*curPos[0];
/* update position */
lastPos[0] = curPos[0];
lastPos[1] = curPos[1];
lastPos[2] = curPos[2];
}
float w = angle;
float x = axis[0];
float y = axis[1];
float z = axis[2];
glm::mat4 xform = glm::mat4((1.F - (2.F * ( y*y + z*z ))),(2.F * ( x*y - z*w )),( x*z + y*w ),0.F,
(2.F * ( x*y + z*w )),(1.F - (2.F * ( x*x + z*z ))),(2.F * ( y*z - x*w )),0.F,
(2.F * ( x*z - y*w )),(2.F * ( y*z + x*w )),(1.F - (2.F * ( x*x + y*y ))),0.F,
0.F,0.F,0.F,1.F);
model = xform*model;
}
glutPostRedisplay();
}
int main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(512, 512);
glutCreateWindow("Color Cube");
glewInit();
init();
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutIdleFunc(display);
glutMouseFunc(mouseButton);
glutMotionFunc(mouseMotion);
glutMainLoop();
return 0;
}
Here is the fshader36
#version 150
in vec4 color;
out vec4 fColor;
void main()
{
fColor = color;
}
here is VSHADER
#version 330
uniform mat4 mvp;
layout(location=0) in vec4 vPosition;
layout(location=1) in vec4 vColor;
out vec4 color;
void main() {
color = vColor;
gl_Position = mvp * vPosition;
}