I'm reading this shader for YUV planar conversion to RGB.
It deals with lots of YUV formats. As you can see, it first does something with the yuv values, and then do the rgb conversion in the end:
vec3 yuv;
vec4 rgba;
if(tex_format == 0 || tex_format == 1){
if(tex_format == 0){
yuv.r = texture2D(tex_y, textureOut).r - 0.0625;
}else{
yuv.r = texture2D(tex_y, textureOut).r;
}
yuv.g = texture2D(tex_u, textureOut).r - 0.5;
yuv.b = texture2D(tex_v, textureOut).r - 0.5;
}else if(tex_format == 2){ // rgb
yuv = texture2D(tex_y, textureOut).rgb;
}else if(tex_format == 3){ // gray8
yuv.r = texture2D(tex_y, textureOut).r;
}else if(tex_format == 6){ //BGR
yuv = texture2D(tex_y, textureOut).bgr;
}else if(tex_format == 10){//yuv420p10le yuv444p10le
vec3 yuv_l;
vec3 yuv_h;
yuv_l.x = texture2D(tex_y, textureOut).r;
yuv_h.x = texture2D(tex_y, textureOut).a;
yuv_l.y = texture2D(tex_u, textureOut).r;
yuv_h.y = texture2D(tex_u, textureOut).a;
yuv_l.z = texture2D(tex_v, textureOut).r;
yuv_h.z = texture2D(tex_v, textureOut).a;
yuv = (yuv_l * 255.0 + yuv_h * 255.0 * 256.0) / (1023.0) - vec3(16.0 / 255.0, 0.5, 0.5);
}else if(tex_format == 8 || tex_format == 9){ //NV12 | NV21
yuv.r = texture2D(tex_y, textureOut).r - 0.0625;
vec4 uv = texture2D( tex_u, textureOut);
if(tex_format == 9){ //NV21
yuv.g = uv.a - 0.5;
yuv.b = uv.r - 0.5;
}else{ //NV12
yuv.g = uv.r - 0.5;
yuv.b = uv.a - 0.5;
}
}else if(tex_format == 16 || tex_format == 17){ //YUV16 YUVJ16
if(tex_format == 16){
yuv.r = texture2D(tex_y, textureOut).r - 0.0625;
}else{
yuv.r = texture2D(tex_y, textureOut).r;
}
yuv.g = texture2D(tex_u, textureOut).r - 0.5;
yuv.b = texture2D(tex_v, textureOut).r - 0.5;
}
if(tex_format == 0 || tex_format == 10 || tex_format == 16){//yuv | p10le | //YUV16
rgba.r = yuv.r + 1.596 * yuv.b;
rgba.g = yuv.r - 0.813 * yuv.b - 0.391 * yuv.g;
rgba.b = yuv.r + 2.018 * yuv.g;
}else if(tex_format == 1 || tex_format == 17){ //yuy-jpeg || YUVJ16
rgba.r = yuv.r + 1.402 * yuv.b;
rgba.g = yuv.r - 0.34413 * yuv.g - 0.71414 * yuv.b;
rgba.b = yuv.r + 1.772 * yuv.g;
}
else if(tex_format == 2){ //rgb
rgba.rgb = yuv.rgb;
}else if(tex_format == 3){ //gray8
rgba.r = yuv.r;
rgba.g = yuv.r;
rgba.b = yuv.r;
}else if(tex_format == 6){ //BGR
rgba.r = yuv.b;
rgba.g = yuv.g;
rgba.b = yuv.r;
}else if(tex_format == 19){ // BGGR
vec2 firstRed = vec2(1,1);
rgba.r = texture2D(tex_y, textureOut).r;
rgba.g = texture2D(tex_u, textureOut).r;
rgba.b = texture2D(tex_v, textureOut).r;
// // BGGR = 19,
// // RGGB = 20 ,
// // GRBG = 21 ,
// // GBRG = 22 ,
}else if(tex_format == 20){ //RGGB
vec2 firstRed = vec2(0,0);
}else if(tex_format == 21){ //GRBG
vec2 firstRed = vec2(0,1);
}else if(tex_format == 22){ //GBRG
vec2 firstRed = vec2(1,0);
}else if(tex_format == 23){//BGR565
rgba.rgb = texture2D(tex_y, textureOut).bgr;
}else{ //其它
rgba.r = yuv.r + 1.596 * yuv.b;
rgba.g = yuv.r - 0.813 * yuv.b - 0.391 * yuv.g;
rgba.b = yuv.r + 2.018 * yuv.g;
}
rgba.a = alpha;
if(enableHDR){
rgba.rgb = toHDR(rgba.rgb,1.0);
}
rgba.a = alpha;
gl_FragColor = rgba;
For example, in the yuv420p10le format, it first does:
vec3 yuv_l;
vec3 yuv_h;
yuv_l.x = texture2D(tex_y, textureOut).r;
yuv_h.x = texture2D(tex_y, textureOut).a;
yuv_l.y = texture2D(tex_u, textureOut).r;
yuv_h.y = texture2D(tex_u, textureOut).a;
yuv_l.z = texture2D(tex_v, textureOut).r;
yuv_h.z = texture2D(tex_v, textureOut).a;
yuv = (yuv_l * 255.0 + yuv_h * 255.0 * 256.0) / (1023.0) - vec3(16.0 / 255.0, 0.5, 0.5);
and then, to those yuv values, it does this:
rgba.r = yuv.r + 1.596 * yuv.b;
rgba.g = yuv.r - 0.813 * yuv.b - 0.391 * yuv.g;
rgba.b = yuv.r + 2.018 * yuv.g;
I've found the second conversion above here, but I can't understand which conversion is the first one. What is it doing? What about the other ones?
The first conversion is a transformation that normalize the limited YUV data. In limited YUV formation, Y in limited in 16 to 240. If we use 16 to divide 256, the answer is 0.0625. So, it is a normalization step.
Related
I try to find the ray intersection distance , t with the wedge shape, I checked the intersection for each finite plane of the wedge, I have this solution but is not working as I expect, I get the wrong result, I need help.
double getIntersectionDistance(Vec3 origin, Vec3 direction) {
//Vec3-3d vector of double
//origin and direction are ray origin and direction respectively.
/*
* BackfaceNormal(1, 0, 0)
* BottomfaceNormal(0, 1, 0)
* DiagonalNormal(1, 1, 0)
* RightTriangle(0, 0, 1)
* LeftTriangle(0, 0, -1)
*/
if(origin.x < 0) {
origin.x = -origin.x;
direction.x = -direction.x;
}
if(origin.y < 0) {
origin.y = -origin.y;
direction.y = -direction.y;
}
if(origin.z < 0) {
origin.z = -origin.z;
direction.z = -direction.z;
}
//for bottom plane
{
Vec3 normal(0, 1, 0);
double ty = (-1 - origin.y) / direction.y;
double y = origin.y + ty * direction.y;
if(std::abs(y) <= 1.0 && ty > 0) {
return ty;
}
}
//for back plane
{
Vec3 normal(1, 0, 0);
double tx = (-1 - origin.x) / direction.x;
double x = origin.x + tx * direction.x;
if(std::abs(x) <= 1.0 && tx > 0) {
return tx;
}
}
//left triangle
{
Vec3 normal(0, 0, 1);
double tz = (-1 - origin.z) / direction.z ;
double z = origin.z + tz * direction.z;
if(std::abs(z) <= 1.0 && tz > 0) {
return tz;
}
}
//right triangle
{
Vec3 normal(0, 0, -1);
double tz = (1 - origin.z) / direction.z;
double z = origin.z + tz * direction.z;
if(std::abs(z) <= 1.0 && tz > 0) {
return tz;
}
}
//diagonal
Vec3 normal(1, 1, 0);
const double dn = direction.x + direction.y;
double txy = (-origin.x - origin.y) / dn;
double x = origin.x + txy * direction.x;
double y = origin.y + txy * direction.y;
if(x + y <= 0.0 && txy > 0) {
return txy;
}
return std::numeric_limits<double>::infinity();//no intersection.
}
The logic I am using is that I am reading he yuv file in a buffer and using 3 pointers to point to the Y,U,V components. The image dimension is 1920*1080.
I am
taking 4 y pixels for corresponding 1U,1V pixels.
Extracting the pixel value in integers.
Converting the Y,U,V to R,G,B and storing the components in RGB buffer.
But the video output is incorrect. The output is somewhat like black and white
#include "stdafx.h"
#include <string>
#include <stdio.h>
unsigned char* g_pcRGBbuffer;
unsigned char* g_pcYUVBuffer;
int _tmain(int argc, _TCHAR* argv[])
{
int l_nSize = 1920 * 1080 * 1.5;
g_pcYUVBuffer = new unsigned char[l_nSize];
g_pcRGBbuffer = new unsigned char[1920 * 1080 * 3];
FILE* fp_source;
FILE* fp_rgb = NULL;
int l_nY, l_nU, l_nV;
double l_dR, l_dG, l_dB, l_ni;
fp_source = fopen("D:\\Sample_1920x1080.yuv", "rb");
// converting yuv file to rgb file
if (fp_source)
{
fp_rgb = fopen("D:\\Sample_1920x1080.rgb", "wb+");
while (!feof(fp_source))
{
fread(g_pcYUVBuffer, 1, l_nSize, fp_source);
unsigned char* l_pcY = g_pcYUVBuffer;
unsigned char* l_pcU = l_pcY + 1920 * 1080;
unsigned char* l_pcV = l_pcU + ((1920 * 1080) / 4);
unsigned char* l_pcRGBbuffer = g_pcRGBbuffer;
for (l_ni = 0; l_ni < (1920 * 1080) / 4; l_ni++)
{
l_nY = l_pcY[0];
l_nU = l_pcU[0];
l_nV = l_pcV[0];
l_dR = l_nY + 1.402 * (l_nV - 128);
l_dG = l_nY - 0.34414 * (l_nU - 128) - 0.71414 * (l_nV - 128);
l_dB = l_nY + 1.772 * (l_nU - 128);
// This prevents colour distortions in rgb image
if (l_dR < 0)
l_dR = 0;
else if (l_dR > 255)
l_dR = 255;
if (l_dG < 0)
l_dG = 0;
else if (l_dG > 255)
l_dG = 255;
if (l_dB < 0)
l_dB = 0;
else if (l_dB > 255)
l_dB = 255;
// 1st pixel of RGB
l_pcRGBbuffer[0] = l_dR;
l_pcRGBbuffer[1] = l_dG;
l_pcRGBbuffer[2] = l_dB;
l_nY = l_pcY[1];
l_nU = l_pcU[0];
l_nV = l_pcV[0];
l_dR = l_nY + 1.402 * (l_nV - 128);
l_dG = l_nY - 0.34414 * (l_nU - 128) - 0.71414 * (l_nV - 128);
l_dB = l_nY + 1.772 * (l_nU - 128);
if (l_dR < 0)
l_dR = 0;
else if (l_dR > 255)
l_dR = 255;
if (l_dG < 0)
l_dG = 0;
else if (l_dG > 255)
l_dG = 255;
if (l_dB < 0)
l_dB = 0;
else if (l_dB > 255)
l_dB = 255;
// 2nd pixel of RGB
l_pcRGBbuffer[3] = l_dR;
l_pcRGBbuffer[4] = l_dG;
l_pcRGBbuffer[5] = l_dB;
l_nY = l_pcY[2];
l_nU = l_pcU[0];
l_nV = l_pcV[0];
l_dR = l_nY + 1.402 * (l_nV - 128);
l_dG = l_nY - 0.34414 * (l_nU - 128) - 0.71414 * (l_nV - 128);
l_dB = l_nY + 1.772 * (l_nU - 128);
if (l_dR < 0)
l_dR = 0;
else if (l_dR > 255)
l_dR = 255;
if (l_dG < 0)
l_dG = 0;
else if (l_dG > 255)
l_dG = 255;
if (l_dB < 0)
l_dB = 0;
else if (l_dB > 255)
l_dB = 255;
// 3rd pixel of RGB
l_pcRGBbuffer[6] = l_dR;
l_pcRGBbuffer[7] = l_dG;
l_pcRGBbuffer[8] = l_dB;
l_nY = l_pcY[3];
l_nU = l_pcU[0];
l_nV = l_pcV[0];
// l_dR = 1.164*(l_nY-16 ) + 1.596*(l_nV-128 );
// l_dG = 1.164*(l_nY-16 ) - 0.813*(l_nV-128 ) - 0.391*(l_nU-128);
// l_dB = 1.164*(l_nY-16 ) + 2.018*(l_nU-128 );
l_dR = l_nY + 1.402 * (l_nV - 128);
l_dG = l_nY - 0.34414 * (l_nU - 128) - 0.71414 * (l_nV - 128);
l_dB = l_nY + 1.772 * (l_nU - 128);
if (l_dR < 0)
l_dR = 0;
else if (l_dR > 255)
l_dR = 255;
if (l_dG < 0)
l_dG = 0;
else if (l_dG > 255)
l_dG = 255;
if (l_dB < 0)
l_dB = 0;
else if (l_dB > 255)
l_dB = 255;
// 4th pixel of RGB
l_pcRGBbuffer[9] = l_dR;
l_pcRGBbuffer[10] = l_dG;
l_pcRGBbuffer[11] = l_dB;
l_pcY += 4;
l_pcU += 1;
l_pcV += 1;
l_pcRGBbuffer += 12;
}
fwrite(g_pcRGBbuffer, 1, 1920 * 1080 * 3, fp_rgb);
}
printf("Video converted to rgb file \n ");
}
else
{
printf("fail\n");
}
fclose(fp_rgb);
fclose(fp_source);
return 0;
}
Actually YUV 4:2:0 planar stores all Y pixels first,then U pixels,then V pixels
To extract correct pixels use the following forumla:
//Refer wikipedia for further details
size.total = size.width * size.height;
y = yuv[position.y * size.width + position.x];
u = yuv[(position.y / 2) * (size.width / 2) + (position.x / 2) + size.total];
v = yuv[(position.y / 2) * (size.width / 2) + (position.x / 2) + size.total + (size.total / 4)];
YUV2RGBTestApp2.cpp : Defines the entry point for the console application.
#include "stdafx.h"
#include <string>
#include <stdio.h>
unsigned char *g_pcRGBbuffer;
unsigned char *g_pcYUVBuffer;
int _tmain(int argc, _TCHAR* argv[])
{
int l_nSize = 1920 * 1080 * 1.5;
g_pcYUVBuffer = new unsigned char[l_nSize];
g_pcRGBbuffer = new unsigned char[1920 * 1080 * 3];
FILE *fp_source;
FILE *fp_rgb = NULL;
int l_ny, l_nu, l_nv, l_ni, RGBval;
int l_dr, l_dg, l_db;
fp_source = fopen("D:\\Sample_1920x1080.yuv", "rb");
int l_nj;
//converting yuv file to rgb file
if (fp_source) {
fp_rgb = fopen("D:\\Sample_1920x1080.rgb", "wb");
while (!feof(fp_source))
{
fread(g_pcYUVBuffer, 1, l_nSize, fp_source);
unsigned char *l_pcRGBbuffer = g_pcRGBbuffer;
for (int j = 0; j < 1080; j++)
{
for (int i = 0; i<1920; i++)
{
/*
Position for y,u,v components for yuv planar 4:2:0
Refer wikipedia for further reference
*/
int Y = g_pcYUVBuffer[j * 1920 + i];
int U = g_pcYUVBuffer[((j / 2) * 960) + (i / 2) + (1920 * 1080)];
int V = g_pcYUVBuffer[((j / 2) * 960) + (i / 2) + (1920 * 1080) + ((1920 * 1080) / 4)];
int R = 1.164*(Y - 16) + 1.596*(V - 128);
int G = 1.164*(Y - 16) - 0.813*(V - 128) - 0.391*(U - 128);
int B = 1.164*(Y - 16) + 2.018*(U - 128);
if (R>255)R = 255;
if (R<0)R = 0;
if (G>255)G = 255;
if (G<0)G = 0;
if (B>255)B = 255;
if (B<0)B = 0;
l_pcRGBbuffer[0] = R;
l_pcRGBbuffer[1] = G;
l_pcRGBbuffer[2] = B;
l_pcRGBbuffer += 3;
}
}
fwrite(g_pcRGBbuffer, 1, 1920 * 1080 * 3, fp_rgb);
}
printf("Video converted to rgb file \n ");
}
else {
printf("fail\n");
}
fclose(fp_rgb);
fclose(fp_source);
return 0;
}
I try to draw terrain using Directx9.
I set vertices and indices, but it's not work well.
some polygons are not visible like this picture.
why some polygons are not drawn? How do i fix this problem.
help me please.
code below is a part of the after unlock vertex and index buffer.
MYINDEX struct contain three index each word type.
TERRAINVERTEX struct contain DXVECTOR3 for position
and DXVECTOR2 for uv coordinate.
TERRAINVERTEX v;
pv = (TERRAINVERTEX *)pVertices;
MYINDEX i;
pi = (MYINDEX*)pIndices;
int offSet = 0;
for (int z = 0; z < m_iCz-1; ++z)
{
for (int x = 0; x < m_iCx-1; ++x)
{
// left top
v.point.x = (float)((x - m_iCx / 2) * m_vfScale.x);
v.point.z = -(float)((z - m_iCz / 2) * m_vfScale.z);
v.point.y = 0.0f;
v.texture.x = 0;
v.texture.y = 0;
pi->i_0 = offSet++;
*pv++ = v;
//right top
v.point.x = (float)(((x+1 - m_iCx / 2) * m_vfScale.x));
v.point.z = -(float)((z - m_iCz / 2) * m_vfScale.z);
v.point.y = 0.0f;
v.texture.x = 1;
v.texture.y = 0;
pi->i_1 = offSet++;
*pv++ = v;
//left down
v.point.x = (float)(((x - m_iCx / 2) * m_vfScale.x));
v.point.z = -(float)((z + 1 - m_iCz / 2) * m_vfScale.z);
v.point.y = 0.0f;
v.texture.x = 0;
v.texture.y = 1;
pi->i_2 = offSet++;
*pv++ = v;
++pi;
//right down
v.point.x = (float)(((x + 1 - m_iCx / 2) * m_vfScale.x));
v.point.z = -(float)((z + 1 - m_iCz / 2) * m_vfScale.z);
v.point.y = 0.0f;
v.texture.x = 1;
v.texture.y = 1;
pi->i_0 = offSet++;
*pv++ = v;
//left down
v.point.x = (float)(((x + 1 - m_iCx / 2) * m_vfScale.x));
v.point.z = -(float)((z + 1 - m_iCz / 2) * m_vfScale.z);
v.point.y = 0.0f;
v.texture.x = 0;
v.texture.y = 1;
pi->i_1 = offSet++;
*pv++ = v;
//right top
v.point.x = (float)(((x + 1 - m_iCx / 2) * m_vfScale.x));
v.point.z = -(float)((z - m_iCz / 2) * m_vfScale.z);
v.point.y = 0.0f;
v.texture.x = 1;
v.texture.y = 0;
pi->i_2 = offSet++;
*pv++ = v;
++pi;
}
}
I am working on soft body simulation. I am trying to do it with OpenGL in c++. However, I have some problems and I could not find anything on the internet. I am using the mass-spring method.
First, I did the simulation in 2d and it worked without a problem. There was a code available. However, when I directly applied it to 3d, it did not and I cannot find the problem. Is it UV sphere? People are using icosahedron sphere, I am aware, however, I cannot figure out how to initialize springs. Since the direction of the springs matter; when I changed the directions in 2d, it does not work. Or it may be the directions of the springs in the UV sphere. Also, I suspect force accumulation and Euler integrator. It may be normals, however, the simulation does not work in the first part where I apply pressure. So to be sure, I changed the normals as vectors from origin to the midpoint of the springs since the ball is located at the origin initially but it fails again. It's been a while since I took a physics course. I put the code below, I know it is not efficient and not well written, but I am interested in making the simulation work, but regardless I appreciate all comments. Anyways, thanks for reading thus far. I wish you all a wonderful day.
mass point initialization
void
InitPoints()
{
float dxy = (360.0 * DegreesToRadians) / CircleVertices;
float dz = (360.0 * DegreesToRadians) / NumCirclesx2;
points[0] = vec4( 0.0, 1.0, 0.0, 1.0);
for(int j=1;j<NumCirclesx2/2;j++){
for(int i=0;i<CircleVertices;i++){
points[(j-1)*CircleVertices + i+1] = vec4(BALLRADIUS * sin(i * dxy)*sin(j*dz), BALLRADIUS *cos(j*dz), BALLRADIUS *cos(i * dxy)*sin(j*dz), 1.0);
}
}
points[NumVertices-1] = vec4( 0.0, -1.0, 0.0, 1.0);
}
Springs initialization
void
InitEdges(){
int k = 0;
for(int j=0;j<CircleVertices;j++){
edges[4*j] = points[1+j];
edges[4*j+1] = points[0];
spring[k].p1 = 0;
spring[k].p2 = 1+j;
spring[k].index = 4*j;
spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
k++;
edges[4*j+2] = points[(1+j)];
spring[k].p1 = 1+j;
spring[k].index = 4*j+2;
if(2+j == CircleVertices){
edges[4*j+3] = points[(2+j)];
spring[k].p2 = 2+j;
}
else{
edges[4*j+3] = points[(2+j)%(CircleVertices)];
spring[k].p2 = (2+j)%(CircleVertices);
}
spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
k++;
}
for(int i=1;i<NumCirclesx2/2-1;i++){
for(int j=0;j<CircleVertices;j++){
edges[i*CircleVertices*4+4*j] = points[i*CircleVertices+1+j];
edges[i*CircleVertices*4+4*j+1] = points[(i-1)*CircleVertices+1+j];
spring[k].p1 = i*CircleVertices+1+j;
spring[k].p2 = (i-1)*CircleVertices+1+j;
spring[k].index = i*CircleVertices*4+4*j;
spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
k++;
edges[i*CircleVertices*4+4*j+2] = points[i*CircleVertices+1+j];
spring[k].p1 = i*CircleVertices+1+j;
spring[k].index = i*CircleVertices*4+4*j+2;
if(2+j == CircleVertices){
edges[i*CircleVertices*4+4*j+3] = points[i*CircleVertices+(2+j)];
spring[k].p2 = i*CircleVertices+(2+j);
}
else {
edges[i*CircleVertices*4+4*j+3] = points[i*CircleVertices+(2+j)%CircleVertices];
spring[k].p2 = i*CircleVertices+(2+j)%CircleVertices;
}
spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
k++;
}
}
for(int j=0;j<CircleVertices;j++){
edges[(NumCirclesx2/2-1)*CircleVertices*4+2*j] = points[NumVertices-1];
edges[(NumCirclesx2/2-1)*CircleVertices*4+2*j+1] = points[(NumCirclesx2/2-1)*CircleVertices-CircleVertices+j+1];
spring[k].p1 = (NumCirclesx2/2-1)*CircleVertices-CircleVertices+j+1;
spring[k].p2 = NumVertices-1;
spring[k].index = (NumCirclesx2/2-1)*CircleVertices*4+2*j;
spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
k++;
}
}
volume of the ball
float VolumeBall(){
float minx = 100000,miny = 100000,minz = 100000, maxx = -100000, maxy = -100000, maxz = -100000;
for(int i = 0; i<NumVertices; i++){
if(points[i].x < minx) minx = points[i].x;
if(points[i].y < miny) miny = points[i].y;
if(points[i].z < minz) minz = points[i].z;
if(points[i].x > maxx) maxx = points[i].x;
if(points[i].y > maxy) maxy = points[i].y;
if(points[i].z > maxz) maxz = points[i].z;
}
return (maxx - minx) * (maxz - minz) * (maxy - miny);
}
force accumulator
void AccumulateForces(){
vec3 point1, point2,point3,point4;
float r12;
vec3 v12;
float f;
vec3 F;
vec3 norm;
bool flag = true;
float volume=0;
float pressurev;
for(int i =0; i<NumVertices; i++){
mass[i].f.x = 0;
mass[i].f.z = 0;
mass[i].f.y = 0;
if(Pressure - FINAL_PRESSURE >= 0) mass[i].f.y = Mass * GY;
}
for(int i=0; i<NumEdges/2; i++){
point1 = vec3(points[spring[i].p1].x,points[spring[i].p1].y,points[spring[i].p1].z);
point2 = vec3(points[spring[i].p2].x,points[spring[i].p2].y,points[spring[i].p2].z);
r12 = distance(point1, point2);
if(r12 != 0){
v12 = mass[spring[i].p1].v - mass[spring[i].p2].v;
f = (r12 - spring[i].length) * KS + innerprod(v12,point1 - point2) * KD / r12;
F = (point1-point2)/r12 * f;
mass[spring[i].p1].f -= F;
mass[spring[i].p2].f += F;
}
spring[i].n = normalize(point1-point2);
}
volume = VolumeBall();
for(int i=0;i<NumEdges/2;i++){
point1 = vec3(points[spring[i].p1].x,points[spring[i].p1].y,points[spring[i].p1].z);
point2 = vec3(points[spring[i].p2].x,points[spring[i].p2].y,points[spring[i].p2].z);
r12 = distance(point1,point2);
pressurev = r12 * Pressure * (1.0f/volume);
mass[spring[i].p1].f += spring[i].n * pressurev;
mass[spring[i].p2].f += spring[i].n * pressurev;
}
}void AccumulateForces(){
vec3 point1, point2,point3,point4;
float r12;
vec3 v12;
float f;
vec3 F;
vec3 norm;
bool flag = true;
float volume=0;
float pressurev;
for(int i =0; i<NumVertices; i++){
mass[i].f.x = 0;
mass[i].f.z = 0;
mass[i].f.y = 0;
if(Pressure - FINAL_PRESSURE >= 0) mass[i].f.y = Mass * GY;
}
for(int i=0; i<NumEdges/2; i++){
point1 = vec3(points[spring[i].p1].x,points[spring[i].p1].y,points[spring[i].p1].z);
point2 = vec3(points[spring[i].p2].x,points[spring[i].p2].y,points[spring[i].p2].z);
r12 = distance(point1, point2);
if(r12 != 0){
v12 = mass[spring[i].p1].v - mass[spring[i].p2].v;
f = (r12 - spring[i].length) * KS + innerprod(v12,point1 - point2) * KD / r12;
F = (point1-point2)/r12 * f;
mass[spring[i].p1].f -= F;
mass[spring[i].p2].f += F;
}
spring[i].n = normalize(point1-point2);
}
volume = VolumeBall();
for(int i=0;i<NumEdges/2;i++){
point1 = vec3(points[spring[i].p1].x,points[spring[i].p1].y,points[spring[i].p1].z);
point2 = vec3(points[spring[i].p2].x,points[spring[i].p2].y,points[spring[i].p2].z);
r12 = distance(point1,point2);
pressurev = r12 * Pressure * (1.0f/volume);
mass[spring[i].p1].f += spring[i].n * pressurev;
mass[spring[i].p2].f += spring[i].n * pressurev;
}
}
euler integrator
void IntegrateEuler(){
float dry,drx,drz;
for(int i=0;i<NumVertices;i++){
mass[i].v.x = mass[i].v.x + (mass[i].f.x/Mass) * DT;
drx = mass[i].v.x * DT;
if(points[i].x + drx < -SCRSIZE){
drx = -SCRSIZE - points[i].x;
mass[i].v.x = -0.1 * mass[i].v.x;
mass[i].v.y = 0.95 * mass[i].v.y;
mass[i].v.z = 0.95 * mass[i].v.z;
}
if(points[i].x + drx > SCRSIZE){
drx = SCRSIZE - points[i].x;
mass[i].v.x = -0.1 * mass[i].v.x;
mass[i].v.y = 0.95 * mass[i].v.y;
mass[i].v.z = 0.95 * mass[i].v.z;
}
points[i].x = points[i].x + drx;
mass[i].v.y = mass[i].v.y + (mass[i].f.y/Mass) * DT;
dry = mass[i].v.y * DT;
if(points[i].y + dry < -SCRSIZE){
dry = -SCRSIZE - points[i].y;
mass[i].v.y = -0.1 * mass[i].v.y;
mass[i].v.x = 0.95 * mass[i].v.x;
mass[i].v.z = 0.95 * mass[i].v.z;
}
if(points[i].y + dry > SCRSIZE){
dry = SCRSIZE - points[i].y;
mass[i].v.y = -0.1 * mass[i].v.y;
mass[i].v.x = 0.95 * mass[i].v.x;
mass[i].v.z = 0.95 * mass[i].v.z;
}
points[i].y = points[i].y + dry;
mass[i].v.z = mass[i].v.z + (mass[i].f.z/Mass) * DT;
drz = mass[i].v.z * DT;
if(points[i].z + drz < -SCRSIZE){
drz = -SCRSIZE - points[i].z;
mass[i].v.z = -0.1 * mass[i].v.z;
mass[i].v.x = 0.95 * mass[i].v.x;
mass[i].v.y = 0.95 * mass[i].v.y;
}
if(points[i].z + drz > SCRSIZE){
drz = SCRSIZE - points[i].z;
mass[i].v.z = -0.1 * mass[i].v.z;
mass[i].v.x = 0.95 * mass[i].v.x;
mass[i].v.y = 0.95 * mass[i].v.y;
}
points[i].z = points[i].z + drz;
if(points[i].x > SCRSIZE)
points[i].x = SCRSIZE;
if(points[i].y > SCRSIZE)
points[i].y = SCRSIZE;
if(points[i].z > SCRSIZE)
points[i].z = SCRSIZE;
if(points[i].x < -SCRSIZE)
points[i].x = -SCRSIZE;
if(points[i].y < -SCRSIZE)
points[i].y = -SCRSIZE;
if(points[i].z < -SCRSIZE)
points[i].z = -SCRSIZE;
}
}
if you are interested, whole code with shaders.
#include "Angel.h"
#define Mass 1.0f
#define KS 1755.0f
#define KD 35.0f
#define GY -10.0f
#define BALLRADIUS 0.516f
#define DT 0.011f
#define FINAL_PRESSURE 85.0f
#define SCRSIZE 7
typedef Angel::vec4 color4;
typedef Angel::vec4 point4;
const int CircleVertices = 8;
const int NumCirclesx2 = 20;
const int NumVertices = CircleVertices * (NumCirclesx2/2-1) + 2;
const int NumEdges = (NumVertices-2)*4+CircleVertices*2;
point4 points[NumVertices];
GLfloat w = 512, h = 512;
//-----------------------------------------------------------------
float xLeft = -2.0;
float xRight = 2.0;
float yBottom = -2.0;
float yTop = 2.0;
float zNear = -4.0;
float zFar = 4.0;
float aspectx = 1;
float aspecty = 1;
//-----------------------------------------------------------------
GLuint vModel;
GLuint vProjection;
GLuint vView;
//------------------------------------------------------------------
typedef struct {
vec3 v;
vec3 f;
} PointMass;
typedef struct {
int p1,p2;
int index;
float length;
vec3 n;
} Spring;
PointMass mass[NumVertices];
Spring spring[NumEdges/2];
float Pressure = 0;
//------------------------------------------------------------------
point4 edges[NumEdges];
point4 b[5];
point4 c[5];
static int k = 0;
//view angle
const float dr = 5.0 * DegreesToRadians;
float theta = 0;
float phi = 0;
float distance(vec4 a, vec4 b){
return sqrt((a.x - b.x) * (a.x - b.x)+(a.y - b.y) * (a.y - b.y)+(a.z - b.z) * (a.z - b.z));
}
float distance(vec3 a, vec3 b){
return sqrt((a.x - b.x) * (a.x - b.x)+(a.y - b.y) * (a.y - b.y)+(a.z - b.z) * (a.z - b.z));
}
float innerprod(vec3 a, vec3 b){
vec3 c = a * b;
return c.x+c.y+c.z;
}
void
InitPoints()
{
float dxy = (360.0 * DegreesToRadians) / CircleVertices;
float dz = (360.0 * DegreesToRadians) / NumCirclesx2;
points[0] = vec4( 0.0, 1.0, 0.0, 1.0);
for(int j=1;j<NumCirclesx2/2;j++){
for(int i=0;i<CircleVertices;i++){
points[(j-1)*CircleVertices + i+1] = vec4(BALLRADIUS * sin(i * dxy)*sin(j*dz), BALLRADIUS *cos(j*dz), BALLRADIUS *cos(i * dxy)*sin(j*dz), 1.0);
}
}
points[NumVertices-1] = vec4( 0.0, -1.0, 0.0, 1.0);
}
void
InitEdges(){
int k = 0;
for(int j=0;j<CircleVertices;j++){
edges[4*j] = points[1+j];
edges[4*j+1] = points[0];
spring[k].p1 = 0;
spring[k].p2 = 1+j;
spring[k].index = 4*j;
spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
k++;
edges[4*j+2] = points[(1+j)];
spring[k].p1 = 1+j;
spring[k].index = 4*j+2;
if(2+j == CircleVertices){
edges[4*j+3] = points[(2+j)];
spring[k].p2 = 2+j;
}
else{
edges[4*j+3] = points[(2+j)%(CircleVertices)];
spring[k].p2 = (2+j)%(CircleVertices);
}
spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
k++;
}
for(int i=1;i<NumCirclesx2/2-1;i++){
for(int j=0;j<CircleVertices;j++){
edges[i*CircleVertices*4+4*j] = points[i*CircleVertices+1+j];
edges[i*CircleVertices*4+4*j+1] = points[(i-1)*CircleVertices+1+j];
spring[k].p1 = i*CircleVertices+1+j;
spring[k].p2 = (i-1)*CircleVertices+1+j;
spring[k].index = i*CircleVertices*4+4*j;
spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
k++;
edges[i*CircleVertices*4+4*j+2] = points[i*CircleVertices+1+j];
spring[k].p1 = i*CircleVertices+1+j;
spring[k].index = i*CircleVertices*4+4*j+2;
if(2+j == CircleVertices){
edges[i*CircleVertices*4+4*j+3] = points[i*CircleVertices+(2+j)];
spring[k].p2 = i*CircleVertices+(2+j);
}
else {
edges[i*CircleVertices*4+4*j+3] = points[i*CircleVertices+(2+j)%CircleVertices];
spring[k].p2 = i*CircleVertices+(2+j)%CircleVertices;
}
spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
k++;
}
}
for(int j=0;j<CircleVertices;j++){
edges[(NumCirclesx2/2-1)*CircleVertices*4+2*j] = points[NumVertices-1];
edges[(NumCirclesx2/2-1)*CircleVertices*4+2*j+1] = points[(NumCirclesx2/2-1)*CircleVertices-CircleVertices+j+1];
spring[k].p1 = (NumCirclesx2/2-1)*CircleVertices-CircleVertices+j+1;
spring[k].p2 = NumVertices-1;
spring[k].index = (NumCirclesx2/2-1)*CircleVertices*4+2*j;
spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
k++;
cout << NumVertices-1 << " " << (NumCirclesx2/2-1)*CircleVertices-CircleVertices+j+1 << endl;
}
}
void updateEdge(){
for(int j=0;j<CircleVertices;j++){
edges[4*j] = points[1+j];
edges[4*j+1] = points[0];
edges[4*j+2] = points[(1+j)];
if(2+j == CircleVertices){
edges[4*j+3] = points[(2+j)];
}
else{
edges[4*j+3] = points[(2+j)%(CircleVertices)];
}
}
for(int i=1;i<NumCirclesx2/2-1;i++){
for(int j=0;j<CircleVertices;j++){
edges[i*CircleVertices*4+4*j] = points[i*CircleVertices+1+j];
edges[i*CircleVertices*4+4*j+1] = points[(i-1)*CircleVertices+1+j];
edges[i*CircleVertices*4+4*j+2] = points[i*CircleVertices+1+j];
if(2+j == CircleVertices){
edges[i*CircleVertices*4+4*j+3] = points[i*CircleVertices+(2+j)];
}
else {
edges[i*CircleVertices*4+4*j+3] = points[i*CircleVertices+(2+j)%CircleVertices];
}
}
}
for(int j=0;j<CircleVertices;j++){
edges[(NumCirclesx2/2-1)*CircleVertices*4+2*j] = points[NumVertices-1];
edges[(NumCirclesx2/2-1)*CircleVertices*4+2*j+1] = points[(NumCirclesx2/2-1)*CircleVertices-CircleVertices+j+1];
}
}
float VolumeBall(){
float minx = 100000,miny = 100000,minz = 100000, maxx = -100000, maxy = -100000, maxz = -100000;
for(int i = 0; i<NumVertices; i++){
if(points[i].x < minx) minx = points[i].x;
if(points[i].y < miny) miny = points[i].y;
if(points[i].z < minz) minz = points[i].z;
if(points[i].x > maxx) maxx = points[i].x;
if(points[i].y > maxy) maxy = points[i].y;
if(points[i].z > maxz) maxz = points[i].z;
}
return (maxx - minx) * (maxz - minz) * (maxy - miny);
}
void AccumulateForces(){
vec3 point1, point2,point3,point4;
float r12;
vec3 v12;
float f;
vec3 F;
vec3 norm;
bool flag = true;
float volume=0;
float pressurev;
for(int i =0; i<NumVertices; i++){
mass[i].f.x = 0;
mass[i].f.z = 0;
mass[i].f.y = 0;
if(Pressure - FINAL_PRESSURE >= 0) mass[i].f.y = Mass * GY;
}
for(int i=0; i<NumEdges/2; i++){
point1 = vec3(points[spring[i].p1].x,points[spring[i].p1].y,points[spring[i].p1].z);
point2 = vec3(points[spring[i].p2].x,points[spring[i].p2].y,points[spring[i].p2].z);
r12 = distance(point1, point2);
if(r12 != 0){
v12 = mass[spring[i].p1].v - mass[spring[i].p2].v;
f = (r12 - spring[i].length) * KS + innerprod(v12,point1 - point2) * KD / r12;
F = (point1-point2)/r12 * f;
mass[spring[i].p1].f -= F;
mass[spring[i].p2].f += F;
}
spring[i].n = normalize(point1-point2);
// if(flag){
// point3 = vec3(points[spring[i+1].p1].x,points[spring[i+1].p1].y,points[spring[i+1].p1].z);
// point4 = vec3(points[spring[i+1].p2].x,points[spring[i+1].p2].y,points[spring[i+1].p2].z);
// norm = cross(point1-point2, point3-point4);
// norm = normalize(norm);
// spring[i].n = norm;
// flag = false;
// }
// else{
// spring[i].n = norm;
// flag = true;
// }
}
// for(int i=0; i< NumEdges/2; i++){
// point1 = vec3(points[spring[i].p1].x,points[spring[i].p1].y,points[spring[i].p1].z);
// point2 = vec3(points[spring[i].p2].x,points[spring[i].p2].y,points[spring[i].p2].z);
// r12 = distance(point1, point2);
// volume += 0.5 * abs(point1.x-point2.x) * abs(spring[i].n.x) * r12;
// }
volume = VolumeBall();
for(int i=0;i<NumEdges/2;i++){
point1 = vec3(points[spring[i].p1].x,points[spring[i].p1].y,points[spring[i].p1].z);
point2 = vec3(points[spring[i].p2].x,points[spring[i].p2].y,points[spring[i].p2].z);
r12 = distance(point1,point2);
pressurev = r12 * Pressure * (1.0f/volume);
mass[spring[i].p1].f += spring[i].n * pressurev;
mass[spring[i].p2].f += spring[i].n * pressurev;
}
}
void IntegrateEuler(){
float dry,drx,drz;
for(int i=0;i<NumVertices;i++){
mass[i].v.x = mass[i].v.x + (mass[i].f.x/Mass) * DT;
drx = mass[i].v.x * DT;
if(points[i].x + drx < -SCRSIZE){
drx = -SCRSIZE - points[i].x;
mass[i].v.x = -0.1 * mass[i].v.x;
mass[i].v.y = 0.95 * mass[i].v.y;
mass[i].v.z = 0.95 * mass[i].v.z;
}
if(points[i].x + drx > SCRSIZE){
drx = SCRSIZE - points[i].x;
mass[i].v.x = -0.1 * mass[i].v.x;
mass[i].v.y = 0.95 * mass[i].v.y;
mass[i].v.z = 0.95 * mass[i].v.z;
}
points[i].x = points[i].x + drx;
mass[i].v.y = mass[i].v.y + (mass[i].f.y/Mass) * DT;
dry = mass[i].v.y * DT;
if(points[i].y + dry < -SCRSIZE){
dry = -SCRSIZE - points[i].y;
mass[i].v.y = -0.1 * mass[i].v.y;
mass[i].v.x = 0.95 * mass[i].v.x;
mass[i].v.z = 0.95 * mass[i].v.z;
}
if(points[i].y + dry > SCRSIZE){
dry = SCRSIZE - points[i].y;
mass[i].v.y = -0.1 * mass[i].v.y;
mass[i].v.x = 0.95 * mass[i].v.x;
mass[i].v.z = 0.95 * mass[i].v.z;
}
points[i].y = points[i].y + dry;
mass[i].v.z = mass[i].v.z + (mass[i].f.z/Mass) * DT;
drz = mass[i].v.z * DT;
if(points[i].z + drz < -SCRSIZE){
drz = -SCRSIZE - points[i].z;
mass[i].v.z = -0.1 * mass[i].v.z;
mass[i].v.x = 0.95 * mass[i].v.x;
mass[i].v.y = 0.95 * mass[i].v.y;
}
if(points[i].z + drz > SCRSIZE){
drz = SCRSIZE - points[i].z;
mass[i].v.z = -0.1 * mass[i].v.z;
mass[i].v.x = 0.95 * mass[i].v.x;
mass[i].v.y = 0.95 * mass[i].v.y;
}
points[i].z = points[i].z + drz;
if(points[i].x > SCRSIZE)
points[i].x = SCRSIZE;
if(points[i].y > SCRSIZE)
points[i].y = SCRSIZE;
if(points[i].z > SCRSIZE)
points[i].z = SCRSIZE;
if(points[i].x < -SCRSIZE)
points[i].x = -SCRSIZE;
if(points[i].y < -SCRSIZE)
points[i].y = -SCRSIZE;
if(points[i].z < -SCRSIZE)
points[i].z = -SCRSIZE;
}
}
// OpenGL initialization
void
init()
{
InitPoints();
InitEdges();
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// Create and initialize a buffer object put all of the object in the same buffer to speed things up
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(edges), NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(edges), edges);
// Load shaders and use the resulting shader program
GLuint program = InitShader("vshader.glsl", "fshader.glsl");
glUseProgram(program);
// set up vertex arrays
GLuint vPosition = glGetAttribLocation(program, "vPosition");
glEnableVertexAttribArray(vPosition);
glVertexAttribPointer(vPosition, 4, GL_FLOAT, GL_FALSE, 0,
BUFFER_OFFSET(0));
// uniform variables in the shader
GLuint vColor = glGetUniformLocation(program, "vColor");
glUniform4fv(vColor, 1, color4(1.0,0.0,0.0,1.0));
vView = glGetUniformLocation(program, "vView");
vProjection = glGetUniformLocation(program, "vProjection");
//glEnable(GL_DEPTH_TEST);
glDisable(GL_DEPTH_TEST);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glClearColor(0.0, 0.0, 0.0, 0.0);
}
//----------------------------------------------------------------------------
void
display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
point4 at( 0.0, 0.0, 0.0, 1.0 );
point4 eye( 0.5*sin(theta)*cos(phi), 0.5*sin(phi), -cos(theta)*0.5*cos(phi), 1.0 );
vec4 up( 0.0, 1.0, 0.0, 0.0 );
updateEdge();
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(edges), edges);
mat4 view = LookAt( eye, at, up );
glUniformMatrix4fv(vView, 1, GL_TRUE, view);
glUniformMatrix4fv(vProjection, 1, GL_TRUE,
Ortho( -SCRSIZE, SCRSIZE, -SCRSIZE, SCRSIZE, zNear, zFar ));
// Ortho( aspectx*xLeft, aspectx*xRight, aspecty*yBottom, aspecty*yTop, zNear, zFar ));
glDrawArrays(GL_LINES, 0, NumEdges);
glutSwapBuffers();
}
//----------------------------------------------------------------------------
void
keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 'i':
case 'I': aspectx=aspectx*0.9;aspecty=aspecty*0.9;break;
case 'o':
case 'O': aspectx=aspectx*1.1;aspecty=aspecty*1.1;break;
case 033: // Escape Key
// 'q' exits
case 'q': case 'Q': exit(EXIT_SUCCESS); break;
}
}
//----------------------------------------------------------------------------
//special keyboard function catches special keyboard inputs such as arrow keys.
void SpecialKeyboard(int key, int x, int y)
{
switch (key)
{
case GLUT_KEY_LEFT: theta += dr; break;
case GLUT_KEY_RIGHT: theta -= dr; break;
case GLUT_KEY_UP: phi += dr; break;
case GLUT_KEY_DOWN: phi -= dr; break;
}
glutPostRedisplay();
}
//----------------------------------------------------------------------------
void timer(int)
{
AccumulateForces();
IntegrateEuler();
if(Pressure < FINAL_PRESSURE)
{
Pressure += FINAL_PRESSURE/100.0f;
printf("Pressure = %4.4f\n",Pressure);
}
glutPostRedisplay();
glutTimerFunc(1000, timer, 0);
}
// void
// idle(void)
// {
// AccumulateForces();
// IntegrateEuler();
// if(Pressure < FINAL_PRESSURE)
// {
// Pressure += FINAL_PRESSURE/100.0f;
// printf("Pressure = %4.4f\n",Pressure);
// }
// glutPostRedisplay();
// }
//----------------------------------------------------------------------------
void reshape(GLsizei ww, GLsizei hh)
{
glViewport( 0, 0, ww, hh );
aspectx = (GLfloat)ww/w;
aspecty = (GLfloat)hh/h;
w = ww;
h = hh;
}
int
main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutInitWindowSize(512, 512);
glutInitContextVersion(3, 2);
glutInitContextProfile(GLUT_CORE_PROFILE);
glutCreateWindow("Free Fall");
glewExperimental = GL_TRUE;
glewInit();
init();
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutSpecialFunc(SpecialKeyboard);
glutTimerFunc(1000.0/60.0, timer, 0);
// glutIdleFunc(idle);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
#version 150
in vec4 vPosition;
uniform vec4 vColor;
uniform mat4 vView;
uniform mat4 vProjection;
out vec4 color;
void main()
{
gl_Position = vProjection*vView*vPosition;
color = vColor;
}
#version 150
in vec4 color;
out vec4 fColor;
void main()
{
fColor = color;
}
I want to setup the phong shading in my program, and I use "glm.h" to help me read and draw the .obj model. Because not all of the model have the vertex normal data in the file, I count it by myself and I check it's right.
But the shader just can correct in flat shader when I use "glmDraw(myObj, GLM_FLAT)" , it will use face normal to count it. I can't get the right effect when I use "glmDraw(myObj, GLM_SMOOTH)" use vertex normal to count. What's wrong in my code? It's my main program wrong? Or my shder program?
My main code:
#define GLEW_STATIC
#include <Windows.h> // for solving the Code::Blocks errors
#include <stdlib.h>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <GL/glew.h>
#include <GL/glut.h>
#include "textfile.h"
#include "glm.h"
#define PI 3.1415926535897
using namespace std;
GLMmodel *myObj = NULL;
GLMmodel *myObj_inner = NULL;
int width, height;
int start_x, start_y;
GLdouble theta = -PI/2, phi = PI / 2;
GLdouble eye_x = 0.0, eye_y = 0.0, eye_z = 0.0,
center_x = eye_x + sin(phi) * cos(theta), center_y = eye_y + cos(phi), center_z = 4*sin(phi) * sin(theta),
up_x = 0.0, up_y = 1.0, up_z = 0.0;
bool ridingMode = false;
float delta_x = 0.0, delta_y = 0.0, delta_z = 0.0;
float angle=0;
GLfloat vertices[][3] =
{{-0.5,-0.5,-0.5},
{0.5,-0.5,-0.5},
{0.5,0.5,-0.5},
{-0.5,0.5,-0.5},
{-0.5,-0.5,0.5},
{0.5,-0.5,0.5},
{0.5,0.5,0.5},
{-0.5,0.5,0.5}};
GLdouble lightTheta = 10.0;
GLfloat light0_ambient[] = {0.9, 0.9, 0.9, 1.0};
GLfloat light0_diffuse[] = {0.7, 0.7, 0.7, 1.0};
GLfloat light0_specular[] = {0.7, 0.7, 0.7, 1.0};
GLfloat light0_pos[]={0.0, 0.0, 0.0, 1.0};
GLfloat light0_shininess = 50;
GLfloat min_x, max_x, min_y, max_y, min_z, max_z;
GLfloat bound_size[3];
GLfloat bound_center[3];
vector<int> *point_tri = NULL;
bool show = true;
void polygon(int a, int b, int c , int d)
{
/* draw a polygon via list of vertices */
glBegin(GL_POLYGON);
glVertex3fv(vertices[a]);
glVertex3fv(vertices[b]);
glVertex3fv(vertices[c]);
glVertex3fv(vertices[d]);
glEnd();
}
void cube(void)
{
/* map vertices to faces */
polygon(0,3,2,1);
polygon(2,3,7,6);
polygon(0,4,7,3);
polygon(1,2,6,5);
polygon(4,5,6,7);
polygon(0,1,5,4);
}
void draw_bounding_box()
{
glScalef(bound_size[0],bound_size[1],bound_size[2]);
glPolygonMode(GL_FRONT, GL_LINE);
glPolygonMode(GL_BACK, GL_LINE);
cube();
glPolygonMode(GL_FRONT, GL_FILL);
glPolygonMode(GL_BACK, GL_FILL);
glScalef(1/bound_size[0],1/bound_size[1],1/bound_size[2]);
}
void setShaders()
{
GLhandleARB v = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB),
f = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB),
p;
char *vs = NULL, *fs = NULL;
vs = textFileRead("myshader.vert");
fs = textFileRead("myshader.frag");
const char * vv = vs;
const char * ff = fs;
glShaderSourceARB(v, 1, &vv, NULL);
glShaderSourceARB(f, 1, &ff, NULL);
free(vs);free(fs);
glCompileShaderARB(v);
glCompileShaderARB(f);
p = glCreateProgramObjectARB();
glAttachObjectARB(p,v);
glAttachObjectARB(p,f);
glLinkProgramARB(p);
glUseProgramObjectARB(p);
glUniform1iARB(glGetUniformLocationARB(p, "texture"), 0);
glUniform3fARB(glGetUniformLocationARB(p, "light"), light0_pos[0], light0_pos[1], light0_pos[2]);
glUniform4fARB(glGetUniformLocationARB(p, "l_ambient"), light0_ambient[0], light0_ambient[1], light0_ambient[2], light0_ambient[3] );
glUniform4fARB(glGetUniformLocationARB(p, "l_diffuse"), light0_diffuse[0], light0_diffuse[1], light0_diffuse[2], light0_diffuse[3] );
glUniform4fARB(glGetUniformLocationARB(p, "l_specular"), light0_specular[0], light0_specular[1], light0_specular[2], light0_specular[3] );
glUniform1fARB(glGetUniformLocationARB(p, "l_shininess"), light0_shininess );
}
void display(void)
{
/* display callback, clear frame buffer and z buffer,
rotate cube and draw, swap buffers */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(eye_x, eye_y, eye_z, center_x, center_y, center_z, up_x, up_y, up_z);
//lighting
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light0_specular);
glLightfv(GL_LIGHT0, GL_POSITION, light0_pos);
setShaders();
glPushMatrix();
glTranslatef(-bound_center[0], -bound_center[1], -bound_center[2]);
if(show){
// glPolygonMode(GL_FRONT, GL_LINE);
// glPolygonMode(GL_BACK, GL_LINE);
// glmDraw(myObj, GLM_FLAT);
glmDraw(myObj,GLM_SMOOTH);
// glmDraw(myObj,GLM_NONE);
// glPolygonMode(GL_FRONT, GL_FILL);
// glPolygonMode(GL_BACK, GL_FILL);
}
glPopMatrix();
draw_bounding_box();
glutSwapBuffers();
glutPostRedisplay();
}
void mouse(int btn, int state, int x, int y)
{
if(state == GLUT_DOWN)
{
start_x = x;
start_y = y;
}
}
void mouseMotion(int x, int y)
{
theta += 2 * static_cast<double> (x - start_x) / width;
if(theta > 2 * PI) theta -= 2 * PI;
if(theta < -2 * PI) theta += 2 * PI;
GLdouble tmp = phi;
phi += 2 * static_cast<double> (y - start_y) / height;
if(phi > 0 && phi < PI)
center_y = eye_y + bound_size[1] * cos(phi);
else
phi = tmp;
center_x = eye_x + bound_size[0] * sin(phi) * cos(theta);
center_z = eye_z + bound_size[2] * sin(phi) * sin(theta);
start_x = x;
start_y = y;
}
void keyboard(unsigned char key,int x,int y)
{
//²¾°Ê
if(key == 'q' || key == 'Q') //quit
{
glmDelete(myObj);
delete point_tri;
exit(0);
}
if(key == 'w' || key == 'W') //move forward
{
eye_x += 0.1 * bound_size[0] * sin(phi) * cos(theta);
eye_y += 0.1 * bound_size[1] * cos(phi);
eye_z += 0.1 * bound_size[2] * sin(phi) * sin(theta);
center_x += 0.1 * bound_size[0] * sin(phi) * cos(theta);
center_y += 0.1 * bound_size[1] * cos(phi);
center_z += 0.1 * bound_size[2] * sin(phi) * sin(theta);
}
if(key == 's' || key == 'S') //move backward
{
eye_x -= 0.1 * bound_size[0] * sin(phi) * cos(theta);
eye_y -= 0.1 * bound_size[1] * cos(phi);
eye_z -= 0.1 * bound_size[2] * sin(phi) * sin(theta);
center_x -= 0.1 * bound_size[0] * sin(phi) * cos(theta);
center_y -= 0.1 * bound_size[1] * cos(phi);
center_z -= 0.1 * bound_size[2] * sin(phi) * sin(theta);
}
if(key == 'a' || key == 'A') //move left
{
eye_x += 0.1 * bound_size[0] * sin(phi) * sin(theta);
eye_z += -0.1 * bound_size[2] * sin(phi) * cos(theta);
center_x += 0.1 * bound_size[0] * sin(phi) * sin(theta);
center_z += -0.1 * bound_size[2] * sin(phi) * cos(theta);
}
if(key == 'd' || key == 'D') //move right
{
eye_x += -0.1 * bound_size[0] * sin(phi) * sin(theta);
eye_z += 0.1 * bound_size[2] * sin(phi) * cos(theta);
center_x += -0.1 * bound_size[0] * sin(phi) * sin(theta);
center_z += 0.1 * bound_size[2] * sin(phi) * cos(theta);
}
if(key == 'r' || key == 'R') // up
{
eye_y += 0.1 * bound_size[1];
center_y += 0.1 * bound_size[1];
}
if(key == 'f' || key == 'F') // down
{
eye_y -= 0.1 * bound_size[1];
center_y -= 0.1 * bound_size[1];
}
if(key == 'z' || key == 'Z')
{
theta = -PI/2, phi = PI / 2;
eye_x = 0.0, eye_y = 0.0, eye_z = 0.0 + 2.0 * bound_size[2],
center_x = eye_x + sin(phi) * cos(theta), center_y = eye_y + cos(phi), center_z = 4*sin(phi) * sin(theta);
}
if(key == 'b' || key == 'B') // down
{
show = !show;
}
if(key=='+')
{
lightTheta += 10.0;
}
else if(key=='-')
{
lightTheta -= 10.0;
}
if(key==27)
{
exit(0);
}
}
void special(int key, int x, int y)
{
if(key == GLUT_KEY_UP) // look up
if(phi - 0.02 > 0) phi -= 0.02;
if(key == GLUT_KEY_DOWN) // look down
if(phi + 0.02 < PI) phi += 0.02;
if(key == GLUT_KEY_LEFT) // turn left
{
theta -= 0.1;
if(theta <= -2 * PI) theta += 2 * PI;
}
if(key == GLUT_KEY_RIGHT) // turn right
{
theta += 0.1;
if(theta >= 2 * PI) theta -= 2 * PI;
}
center_x = eye_x + bound_size[0] * sin(phi) * cos(theta);
center_y = eye_y + bound_size[1] * cos(phi);
center_z = eye_z + bound_size[2] * sin(phi) * sin(theta);
}
void myReshape(int w, int h)
{
width = w;
height = h;
float ratio = w * 1.0 / h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, w, h);
gluPerspective(50.0, ratio, 0.1, 100000.0);
glMatrixMode(GL_MODELVIEW);
}
void bounding_box()
{
//cout << myObj->vertices[3 * 1 + 0] << " " << myObj->vertices[3 * 1 + 1] << " " << myObj->vertices[3 * 1 + 2] << endl;
min_x = max_x = myObj->vertices[3 * 1 + 0];
min_y = max_y = myObj->vertices[3 * 1 + 1];
min_z = max_z = myObj->vertices[3 * 1 + 2];
for(int i = 1 ; i <= myObj->numvertices ; i += 1)
{
if (myObj->vertices[3 * i + 0] < min_x) min_x = myObj->vertices[3 * i + 0];
if (myObj->vertices[3 * i + 0] > max_x) max_x = myObj->vertices[3 * i + 0];
if (myObj->vertices[3 * i + 1] < min_y) min_y = myObj->vertices[3 * i + 1];
if (myObj->vertices[3 * i + 1] > max_y) max_y = myObj->vertices[3 * i + 1];
if (myObj->vertices[3 * i + 2] < min_z) min_z = myObj->vertices[3 * i + 2];
if (myObj->vertices[3 * i + 2] > max_z) max_z = myObj->vertices[3 * i + 2];
}
bound_size[0] = max_x - min_x;
bound_size[1] = max_y - min_y;
bound_size[2] = max_z - min_z;
bound_center[0] = (max_x + min_x)/2.0;
bound_center[1] = (max_y + min_y)/2.0;
bound_center[2] = (max_z + min_z)/2.0;
eye_z = eye_z + 2.0 * bound_size[2];
light0_pos[0] += 1.25 * bound_size[0];
light0_pos[1] += 1.25 * bound_size[1];
light0_pos[2] += 1.25 * bound_size[2];
}
void recount_normal()
{
point_tri = new vector<int>[myObj->numvertices + 1];
for(int i = 0 ; i < myObj->numtriangles ; i += 1)
{
for(int j = 0 ; j < 3 ; j += 1)
{
bool add = true;
for(int k = 0 ; k < point_tri[myObj->triangles[i].vindices[j]].size() ; k += 1)
{
GLfloat *temp = &myObj->facetnorms[3 * point_tri[myObj->triangles[i].vindices[j]][k]];
if(*temp == myObj->facetnorms[3 * (i+1) + 0] && *(temp + 1) == myObj->facetnorms[3 * (i+1) + 1] && *(temp + 2) == myObj->facetnorms[3 * (i+1) + 2])
{
add = false;
break;
}
}
if(add)
point_tri[myObj->triangles[i].vindices[j]].push_back(i + 1);
}
}
for(int i = 1 ; i <= myObj->numvertices ; i += 1)
{
sort(point_tri[i].begin(),point_tri[i].begin() + point_tri[i].size());
}
myObj->numnormals = myObj->numvertices;
myObj->normals = new GLfloat[3 * (myObj->numnormals + 1)];
for(int i = 1 ; i <= myObj->numnormals ; i += 1)
{
GLfloat temp[3] = {0.0 , 0.0 , 0.0};
for(int j = 0 ; j < point_tri[i].size() ; j += 1)
{
temp[0] += myObj->facetnorms[3 * point_tri[i][j] + 0];
temp[1] += myObj->facetnorms[3 * point_tri[i][j] + 1];
temp[2] += myObj->facetnorms[3 * point_tri[i][j] + 2];
}
GLfloat normal_length = sqrt(pow(temp[0],2) + pow(temp[1],2) + pow(temp[2],2));
temp[0] /= normal_length;
temp[1] /= normal_length;
temp[2] /= normal_length;
myObj->normals[3 * i + 0] = temp[0];
myObj->normals[3 * i + 1] = temp[1];
myObj->normals[3 * i + 2] = temp[2];
}
myObj_inner->numnormals = myObj_inner->numvertices;
myObj_inner->normals = new GLfloat[3 * (myObj_inner->numnormals + 1)];
}
void init()
{
bounding_box();
recount_normal();
}
int main(int argc, char **argv)
{
myObj = glmReadOBJ("test_model/cube.obj");
myObj_inner = glmReadOBJ("test_model/cube.obj");
glmFacetNormals(myObj);
init();
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize(1000,1000);
glutCreateWindow("Zometool");
glutDisplayFunc(display);
glutReshapeFunc(myReshape);
glutMouseFunc(mouse);
glutMotionFunc(mouseMotion);
glutKeyboardFunc(keyboard);
glutSpecialFunc(special);
glEnable(GL_DEPTH_TEST); /* Enable hidden--surface--removal */
glewInit();
glutMainLoop();
return 0;
}
My vertex shader:
varying vec3 N;
varying vec3 v;
void main(void)
{
v = vec3(gl_ModelViewMatrix * gl_Vertex);
N = normalize(gl_ModelViewMatrix * gl_Normal);
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
My fragment shader:
uniform vec4 l_ambient;
uniform vec4 l_diffuse;
uniform vec4 l_specular;
uniform vec3 light;
uniform float l_shininess;
varying vec3 N;
varying vec3 v;
void main (void)
{
vec3 lightWeighting;
vec3 lightDirection = normalize(light.xyz - v);
vec3 normal = N;
float specularLightWeighting = 0.0;
vec3 eyeDirection = normalize(-v);
vec3 reflectionDirection = normalize(-reflect(L,N));
specularLightWeighting = pow(max(dot(reflectionDirection, eyeDirection), 0.0), l_shininess);
float diffuseLightWeighting = max(dot(normal, lightDirection), 0.0);
lightWeighting = l_ambient
+ l_specular * specularLightWeighting
+ l_diffuse * diffuseLightWeighting;
gl_FragColor = gl_FrontLightModelProduct.sceneColor + lightWeighting;
}
My cube.obj:
# Blender v2.62 (sub 0) OBJ File: ''
# www.blender.org
mtllib cube.mtl
o Cube
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -1.000000
v 1.000000 1.000000 1.000000
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
usemtl Material
s off
f 1 2 3 4
f 5 8 7 6
f 1 5 6 2
f 2 6 7 3
f 3 7 8 4
f 5 1 4 8
My cube.mtl:
# Blender MTL File: ''
# Material Count: 1
newmtl Material
Ns 96.078431
Ka 0.000000 0.000000 0.000000
Kd 0.640000 0.640000 0.640000
Ks 0.500000 0.500000 0.500000
Ni 1.000000
d 1.000000
illum 2
flat image:
smooth image: