我试图在绘制单个球体的openGl片段着色器中实现简单的光线跟踪算法。
有时它绘制了一个扭曲的球体,但是大多数时候它什么也没有画。
使用实际的球体原点和半径,我在右上角得到了一个略微还原的球体。
#version 430 core
uniform ivec2 viewportDimensions;
uniform mat4 gl_ProjectionMatrix;
uniform ivec4 viewport;
out vec3 color;
struct Ray {
vec3 origin;
vec3 direction;
};
struct Sphere {
vec3 origin;
float radius;
};
float zNear = -0.1f;
float zFar = -100.0f;
float fieldOfViewX = 3.1415926535897932384626433832795 / 2.0f;
float sampleRay(Ray ray,Sphere s, float distance);
Ray computeEyeRay(float, float, int, int);
bool intersect(Ray r, Sphere s);
bool solveQuadratic(float a, float b, float c);
Ray calcEyeFromWindow(vec3 windowSpace);
void main() {
// Ray r = computeEyeRay(gl_FragCoord.x + 0.5f, gl_FragCoord.y + 0.5f, viewportDimensions.x, viewportDimensions.y);
Ray r = calcEyeFromWindow(vec3(gl_FragCoord.x + 0.5f, gl_FragCoord.y + 0.5f, 1f));
Sphere s;
s.origin = vec3(0.5f,-0.5f,-0.7f);
s.radius = 0.8f;
if (intersect(r,s))
color = vec3(1,1,1);
else
color = vec3(0,0,0);
}
Ray calcEyeFromWindow(vec3 windowSpace)
{
vec4 ndcPos;
ndcPos.xy = ((2.0 * gl_FragCoord.xy) - (2.0 * viewport.xy)) / (viewport.zw) - 1;
ndcPos.z = (2.0 * gl_FragCoord.z - gl_DepthRange.near - gl_DepthRange.far) /
(gl_DepthRange.far - gl_DepthRange.near);
ndcPos.w = 1.0;
vec4 clipPos = ndcPos / gl_FragCoord.w;
vec4 eyePos = inverse(gl_ProjectionMatrix) * clipPos;
Ray r;
r.origin = eyePos.xyz;
r.direction =normalize(eyePos.xyz);
return r;
}
Ray computeEyeRay(float x, float y, int width, int height) {
const float aspect = float(height) / float(width);
const float s = -2.0f * tan(fieldOfViewX * 0.5f);
const vec3 start = vec3( (float(x) / float(width) - 0.5) * s,
-(float(y) / float(height) - 0.5f) * s * aspect,
1.0f) * zNear;
float startLength = sqrt( (start.x * start.x) + (start.y * start.y) + (start.z * start.z) );
Ray e;
e.origin = start;
e.direction = normalize(start);
return e;
}
bool intersect(Ray r, Sphere s) {
float a = dot(r.direction,r.direction);
float b = dot(r.direction, 2.0 * (r.origin-s.origin));
float c = dot(s.origin, s.origin) + dot(r.origin,r.origin) +-2.0*dot(r.origin,s.origin) - (s.radius*s.radius);
float disc = b*b + (-4.0)*a*c;
if (disc < 0)
return false;
return true;
}
bool solveQuadratic(float a, float b, float c) {
float t, t_1;
float disc = a * b - 4 * a * c;
if (disc < 0)
return false;
else {
if (disc == 0)
t = -0.5 * b / a;
else {
float q = (b > 0) ? -0.5 * (b+sqrt(disc)) : -0.5 * (b-sqrt(disc));
t = q / a;
t_1 = c / q;
}
}
return true;
}
如果有人要编译和测试它,这里是程序的其余部分。
#include <stdio.h>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include <glm\glm.hpp>
// include opengl headers
#include <GL/glew.h>
#include <GL/freeglut.h>
const int VIEWPORT_DIMENSION_X = 1280;
const int VIEWPORT_DIMENSION_Y = 1280;
void glutInitialization(int argc, char **argv);
void glewInitialization();
void display();
void resize(int w, int h);
void idle();
void drawSphere(float x, float y, float z);
GLuint LoadShaders(const char * vertex_file_path,const char * fragment_file_path);
GLuint VertexArrayID;
GLuint vertexbuffer; // This will identify our vertex buffer
GLuint programID;
static const GLfloat quadvertices[] = {
-1.0f, 1.0f, .0f,
-1.0f, -1.0f, .0f,
1.0f, -1.0f, .0f,
1.0f, -1.0f, .0f,
1.0f, 1.0f, .0f,
-1.0f, 1.0f, .0f
};
static const GLfloat g_vertex_buffer_data[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
int main(int argc, char **argv)
{
glutInitialization(argc, argv);
glewInitialization();
// create VAO
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
// Generate 1 buffer
glGenBuffers(1, &vertexbuffer);
// Give our vertices to OpenGL.
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(quadvertices), quadvertices, GL_STATIC_DRAW);
glVertexAttribPointer(
0, //
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glEnableVertexAttribArray(0);
glClearColor(0.0,0.0,0.0,0.0);
// Create and compile our GLSL program from the shaders
programID = LoadShaders( "vertex.glsl", "fragment.glsl" );
glViewport(0,0,1280,1280);
// create uniform variables
GLint viewportDimensionsHandle = glGetUniformLocation(programID, "viewportDimensions");
glProgramUniform2i(programID, viewportDimensionsHandle, VIEWPORT_DIMENSION_X, VIEWPORT_DIMENSION_Y);
GLint viewportHandle =glGetUniformLocation(programID, "viewport");
glProgramUniform4i(programID, viewportHandle, 0,0,1280,1280);
// start mainloop
glutMainLoop();
return 0;
}
void glutInitialization(int argc, char **argv) {
// GLUT initializing
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(100,100);
glutInitWindowSize(1280,1280);
glutCreateWindow("raycasting");
// register GLUT callbacks
glutDisplayFunc(display);
glutReshapeFunc(resize);
}
void glewInitialization() {
// GLEW initializing
glewInit();
if (glewIsSupported("GL_VERSION_4_3"))
printf("Ready for OpenGL 4.3\n");
else {
printf("OpenGL 4.3 not supported\n");
exit(1);
}
}
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Use our shader
glUseProgram(programID);
// Bind VAO
glBindVertexArray(VertexArrayID);
// Draw the triangle
glDrawArrays(GL_TRIANGLES, 0, 6); // Starting from vertex 0; 3 vertices total -> 1 triangle
// Unbind VAO
glBindVertexArray(0);
glutSwapBuffers();
}
void resize(int w, int h) {
}
void idle() {
}
void drawSphere(float x, float y, float z) {
glPushMatrix();
}
GLuint LoadShaders(const char * vertex_file_path,const char * fragment_file_path){
// Create the shaders
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
// Read the Vertex Shader code from the file
std::string VertexShaderCode;
std::ifstream VertexShaderStream(vertex_file_path, std::ios::in);
if(VertexShaderStream.is_open())
{
std::string Line = "";
while(getline(VertexShaderStream, Line))
VertexShaderCode += "\n" + Line;
VertexShaderStream.close();
}
// Read the Fragment Shader code from the file
std::string FragmentShaderCode;
std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in);
if(FragmentShaderStream.is_open()){
std::string Line = "";
while(getline(FragmentShaderStream, Line))
FragmentShaderCode += "\n" + Line;
FragmentShaderStream.close();
}
GLint Result = GL_FALSE;
int InfoLogLength;
// Compile Vertex Shader
printf("Compiling shader : %s\n", vertex_file_path);
char const * VertexSourcePointer = VertexShaderCode.c_str();
glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
glCompileShader(VertexShaderID);
// Check Vertex Shader
glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
std::vector<char> VertexShaderErrorMessage(InfoLogLength);
glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]);
// Compile Fragment Shader
printf("Compiling shader : %s\n", fragment_file_path);
char const * FragmentSourcePointer = FragmentShaderCode.c_str();
glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);
glCompileShader(FragmentShaderID);
// Check Fragment Shader
glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
std::vector<char> FragmentShaderErrorMessage(InfoLogLength);
glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
fprintf(stdout, "%s\n", &FragmentShaderErrorMessage[0]);
// Link the program
fprintf(stdout, "Linking program\n");
GLuint ProgramID = glCreateProgram();
glAttachShader(ProgramID, VertexShaderID);
glAttachShader(ProgramID, FragmentShaderID);
glLinkProgram(ProgramID);
// Check the program
glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
std::vector<char> ProgramErrorMessage( std::max(InfoLogLength, int(1)) );
glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
fprintf(stdout, "%s\n", &ProgramErrorMessage[0]);
glDeleteShader(VertexShaderID);
glDeleteShader(FragmentShaderID);
return ProgramID;
}
最佳答案
我敢肯定这不是一个完整的解决方案,但它最终吸引了一个 Realm :
#version 430 core
uniform ivec2 viewportDimensions;
uniform mat4 gl_ProjectionMatrix;
uniform ivec4 viewport;
uniform float imageAspectRatio;
uniform float angle;
out vec3 color;
struct Ray {
vec3 origin;
vec3 direction;
};
struct Sphere {
vec3 origin;
float radius;
};
bool intersect(Ray r, Sphere s);
void main() {
focal = 60;
angle = tan(focal * 0.5 * 3.1415926535897932384626433832795 / 180); // convert from degree to radian
float xx = (2 * (gl_FragCoord.x + 0.5) / viewportDimensions.x - 1) * angle * imageAspectRatio;
float yy = (1 - 2 * (gl_FragCoord.y + 0.5) / viewportDimensions.y) * angle;
vec3 rayOrigin = vec3(0,0,0);
vec3 rayDirection = normalize(vec3(xx, yy, -1) - rayOrigin);
Ray r;
r.origin = rayOrigin;
r.direction = rayDirection;
Sphere s;
s.origin = vec3(0.0f,0.0f,-1.1f);
s.radius =0.55f;
if (intersect(r,s))
color = vec3(1,0,1);
else
color = vec3(0,0,0);
}
bool intersect(Ray r, Sphere s) {
float a = dot(r.direction,r.direction);
float b = dot(r.direction, 2.0 * (r.origin-s.origin));
float c = dot(s.origin, s.origin) + dot(r.origin,r.origin) +-2.0*dot(r.origin,s.origin) - (s.radius*s.radius);
float disc = b*b + (-4.0)*a*c;
if (disc < 0)
return false;
return true;
}
关于c++ - GLSL的光线追踪,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24702767/