Ich habe versucht, meine eigene grundlegende .obj (Wavefront) -Renderer mit dem OpenGL 3.x Kernprofil zu machen. Ich benutze die OpenGL SuperBible 5. Ausgabe. und die Swiftless Tutorials als Referenzmaterial.OpenGL 3.x .obj Loader mit ADS Phong "veiny-looking" Kugel
Die Geometrie scheint korrekt geladen zu werden, also versuche ich jetzt, ein ADS Phong Beleuchtungsmodell zum Laufen zu bringen, aber etwas ist verrückt, und ich denke, es hat etwas mit meinen OpenGL-Aufrufen zu tun oder auch den Weg Ich lade meine Normalen, aber ich kann nicht herausfinden, wie ich es beheben kann. (Es könnte auch ein anderes Problem sein, da ich kein OpenGL-Experte bin).
Wenn ein einfacher Würfel Rendering, sieht es fast richtig, aber es ist eine seltsame Lichtpunkt auf einer Seite:
Wenn eine Kugel-Rendering, die Beleuchtung zeigt sich mit „Adern“:
Etwas ist offensichtlich sehr falsch mit meinem Code. Hier sind die Codeabschnitte, von denen ich denke, dass sie relevant sind. Ich werde glücklich sein, mehr/den ganzen Code bei Bedarf zu veröffentlichen ... lass mich wissen, ob ich mehr posten sollte.
Datei: objFileRenderer.cpp
#include "objFileRenderer.hpp"
namespace def
{
objFileRenderer::objFileRenderer(const char* fileToRender, float objScale)
{
windowWidth = 800;
windowHeight = 600;
settings.majorVersion = 3;
settings.minorVersion = 1;
app = NULL;
shader = NULL;
vaoID = NULL;
vboID = NULL;
iboID = NULL;
vaoID = new unsigned int[1];
vboID = new unsigned int[3];
iboID = new unsigned int[2];
rotSpeed = 50.0f;
rot = 0.0f;
initSFML();
initOpenGL();
std::string objFilename(fileToRender);
std::vector<float> vertices;
std::vector< unsigned short > indices;
std::vector<float> normals;
std::vector< unsigned short > normalIndices;
loadObj(objFilename, vertices, indices, normals, normalIndices);
std::vector<float> colorA;
std::vector<float> colorD;
std::vector<float> colorS;
loadMtl(objFilename, colorA, colorD, colorS);
float* vertexArray = NULL;
int numVertices = 0;
unsigned short* indexArray = NULL;
int numFaces = 0;
vertexArray = vertexVectorToVertexArray(vertices, numVertices);
indexArray = indexVectorToIndexArray(indices, numFaces);
float* colorArrayA = NULL;
float* colorArrayD = NULL;
float* colorArrayS = NULL;
int numColoredObjects = 0;
colorVectorsToColorArrays(colorA, colorD, colorS, colorArrayA, colorArrayD, colorArrayS, numColoredObjects);
float* normalArray = NULL;
unsigned short* normalIndicesArray = NULL;
int numNormals = 0;
int numNormalIndices = 0;
normalVectorsToNormalArrays(normals, normalIndices, normalArray, normalIndicesArray, numNormals, numNormalIndices);
setupScene();
putArraysIntoVAO(vertexArray, numVertices, indexArray, numFaces, normalArray, numNormals, normalIndicesArray, numNormalIndices);
mainLoop(numVertices, numFaces, colorArrayA, colorArrayD, colorArrayD, normalArray, objScale);
delete [] vertexArray;
delete [] indexArray;
delete [] colorArrayA;
delete [] colorArrayD;
delete [] colorArrayS;
delete [] normalArray;
delete [] normalIndicesArray;
}
objFileRenderer::~objFileRenderer()
{
shutdownSFML();
}
void objFileRenderer::loadObj(std::string& objFilename, std::vector<float>& vertices, std::vector< unsigned short >& indices, std::vector<float>& normals, std::vector< unsigned short >& normalIndices)
{
std::ifstream objFile(objFilename.c_str());
if (!objFile.is_open())
{
std::cerr << "Error: unable to open .obj file: " << objFilename << std::endl;
exit(1);
}
std::string line;
while (objFile.good())
{
getline(objFile, line);
// vertices
if (line[0] == 'v' && line[1] == ' ') // if line in .obj file contains vertices
{
std::vector<std::string> tmpStrVerts;
std::string subline;
subline = line.substr(2);
boost::split(tmpStrVerts, subline, boost::is_any_of("\t "));
std::vector<std::string>::iterator it;
for (it = tmpStrVerts.begin(); it != tmpStrVerts.end(); it++)
{
float vertex;
std::stringstream ss;
ss << *it;
ss >> vertex;
vertices.push_back(vertex);
}
}
// normals
else if (line[0] == 'v' && line[1] == 'n')
{
std::vector<std::string> tmpStrNorms;
std::string subline;
subline = line.substr(3);
boost::split(tmpStrNorms, subline, boost::is_any_of("\t "));
std::vector<std::string>::iterator it;
for (it = tmpStrNorms.begin(); it != tmpStrNorms.end(); it++)
{
float normal;
std::stringstream ss;
ss << *it;
ss >> normal;
normals.push_back(normal);
//std::cout << normal << std::endl;
}
}
// indices and normalIndices
else if (line[0] == 'f' && line[1] == ' ') // else if line in .obj file contains indices
{
std::vector<std::string> tmpStrIndices;
std::string subline;
subline = line.substr(2);
// indices
boost::split(tmpStrIndices, subline, boost::is_any_of("\t "));
std::vector<std::string>::iterator it;
for (it = tmpStrIndices.begin(); it != tmpStrIndices.end(); it++)
{
unsigned short index;
std::stringstream ss;
ss << *it;
ss >> index;
indices.push_back(index);
}
// normalIndices
boost::split(tmpStrIndices, subline, boost::is_any_of("/"));
int count = 0;
std::vector<std::string>::iterator it2;
for (it2 = tmpStrIndices.begin(); it2 != tmpStrIndices.end(); it2++)
{
if (count == 2)
{
unsigned short index;
std::stringstream ss;
ss << *it2;
ss >> index;
normalIndices.push_back(index);
count = 0;
}
count++;
}
}
}
objFile.close();
return;
}
void objFileRenderer::loadMtl(std::string& objFilename, std::vector<float>& colorA, std::vector<float>& colorD, std::vector<float>& colorS)
{
int extpos = objFilename.find('.');
std::string mtlFilename = objFilename.substr(0, extpos+1) + "mtl";
std::ifstream mtlFile(mtlFilename.c_str());
if (!mtlFile.is_open())
{
std::cerr << "Error: unable to open .mtl file: " << mtlFilename << std::endl;
exit(1);
}
std::string line;
while (mtlFile.good())
{
getline(mtlFile, line);
if (line[0] == 'K' && line[1] == 'a')
{
std::vector<std::string> tmpStrColorA;
std::string subline;
subline = line.substr(3);
boost::split(tmpStrColorA, subline, boost::is_any_of("\t "));
std::vector<std::string>::iterator it;
for (it = tmpStrColorA.begin(); it != tmpStrColorA.end(); it++)
{
float rgbValue;
std::stringstream ss;
ss << *it;
ss >> rgbValue;
colorA.push_back(rgbValue);
}
}
if (line[0] == 'K' && line[1] == 'd')
{
std::vector<std::string> tmpStrColorD;
std::string subline;
subline = line.substr(3);
boost::split(tmpStrColorD, subline, boost::is_any_of("\t "));
std::vector<std::string>::iterator it;
for (it = tmpStrColorD.begin(); it != tmpStrColorD.end(); it++)
{
float rgbValue;
std::stringstream ss;
ss << *it;
ss >> rgbValue;
colorD.push_back(rgbValue);
}
}
if (line[0] == 'K' && line[1] == 's')
{
std::vector<std::string> tmpStrColorS;
std::string subline;
subline = line.substr(3);
boost::split(tmpStrColorS, subline, boost::is_any_of("\t "));
std::vector<std::string>::iterator it;
for (it = tmpStrColorS.begin(); it != tmpStrColorS.end(); it++)
{
float rgbValue;
std::stringstream ss;
ss << *it;
ss >> rgbValue;
colorS.push_back(rgbValue);
}
}
}
mtlFile.close();
return;
}
float* objFileRenderer::vertexVectorToVertexArray(std::vector<float>& vertices, int& numVertices)
{
numVertices = vertices.size()/3;
float* vertexArray = NULL;
vertexArray = new float[vertices.size()];
for (unsigned int i = 0; i < vertices.size(); i++)
{
vertexArray[i] = vertices[i];
}
return vertexArray;
}
unsigned short* objFileRenderer::indexVectorToIndexArray(std::vector< unsigned short >& indices, int& numFaces)
{
numFaces = indices.size()/3;
unsigned short* indexArray = NULL;
indexArray = new unsigned short[indices.size()];
for (unsigned int i = 0; i < indices.size(); i++)
{
indexArray[i] = indices[i]-1;
}
return indexArray;
}
void objFileRenderer::colorVectorsToColorArrays(std::vector<float>& colorA, std::vector<float>& colorD, std::vector<float>& colorS, float*& colorArrayA, float*& colorArrayD, float*& colorArrayS, int& numColoredObjects)
{
numColoredObjects = colorA.size()/3;
colorArrayA = new float[numColoredObjects*3];
colorArrayD = new float[numColoredObjects*3];
colorArrayS = new float[numColoredObjects*3];
for (int i = 0; i < numColoredObjects; i+=3)
{
colorArrayA[i] = colorA[i]; colorArrayA[i+1] = colorA[i+1]; colorArrayA[i+2] = colorA[i+2];
colorArrayD[i] = colorD[i]; colorArrayD[i+1] = colorD[i+1]; colorArrayD[i+2] = colorD[i+2];
colorArrayS[i] = colorS[i]; colorArrayS[i+1] = colorS[i+1]; colorArrayS[i+2] = colorS[i+2];
}
return;
}
void objFileRenderer::normalVectorsToNormalArrays(std::vector<float>& normals, std::vector< unsigned short >& normalIndices, float*& normalArray, unsigned short*& normalIndicesArray, int& numNormals, int& numNormalIndices)
{
numNormals = normals.size()/3;
numNormalIndices = normalIndices.size();
normalArray = new float[numNormalIndices];
normalIndicesArray = new unsigned short[numNormalIndices];
for (int i = 0; i < numNormalIndices; i+=3)
{
normalIndicesArray[i] = normalIndices[i]-1;
normalIndicesArray[i+1] = normalIndices[i+1]-1;
normalIndicesArray[i+2] = normalIndices[i+2]-1;
}
// load normals in index order
for (int i = 0; i < numNormalIndices; i+=3)
{
int index = normalIndicesArray[i];
normalArray[i] = normals[index];
normalArray[i+1] = normals[index+1];
normalArray[i+2] = normals[index+2];
}
return;
}
void objFileRenderer::putArraysIntoVAO(float* vertexArray, int& numVertices, unsigned short* indexArray, int& numFaces, float* normalArray, int& numNormals, unsigned short* normalIndicesArray, int& numNormalIndices)
{
glGenVertexArrays(1, &vaoID[0]); // create our vertex array object
glBindVertexArray(vaoID[0]); // bind our vertex array object so we can use it
glGenBuffers(2, &iboID[0]); // generate our index buffer object
glGenBuffers(2, &vboID[0]); // generate our vertex buffer object
// normalArray holds normals in index order, so I shouldn't use this
// glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID[1]); // bind our normal index buffer object
// glBufferData(GL_ELEMENT_ARRAY_BUFFER, (numNormalIndices) * sizeof(GLushort), normalIndicesArray, GL_STATIC_DRAW); // set the size and data of our IBO
glBindBuffer(GL_ARRAY_BUFFER, vboID[1]); // bind our normal vertex buffer object
glBufferData(GL_ARRAY_BUFFER, (numNormalIndices) * sizeof(GLfloat), normalArray, GL_STATIC_DRAW); // set the size and data of our VBO and set it to STATIC_DRAW
glVertexAttribPointer((GLuint)1, 3, GL_FLOAT, GL_FALSE, 0, 0); // set up our vertex attributes pointer
glEnableVertexAttribArray(1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID[0]); // bind our index buffer object
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (numFaces*3) * sizeof(GLushort), indexArray, GL_STATIC_DRAW); // set the size and data of our IBO
glBindBuffer(GL_ARRAY_BUFFER, vboID[0]); // bind our vertex buffer object
glBufferData(GL_ARRAY_BUFFER, (numVertices*3) * sizeof(GLfloat), vertexArray, GL_STATIC_DRAW); // set the size and data of our VBO and set it to STATIC_DRAW
glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0); // set up our vertex attributes pointer
glEnableVertexAttribArray(0);
glBindVertexArray(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
return;
}
void objFileRenderer::setupScene()
{
app->setFramerateLimit(60); // max 60 FPS
glClearColor(0.4f, 0.6f, 0.9f, 0.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glEnable(GL_CULL_FACE);
shader = new Shader("shader.vert", "shader.frag");
projectionMatrix = glm::perspective(60.0f, (float)windowWidth/(float)windowHeight, 0.1f, 100.0f);
return;
}
void objFileRenderer::renderScene(int& numVertices, int& numFaces, float*& colorArrayA, float*& colorArrayD, float*& colorArrayS, float*& normalArray, float objScale)
{
sf::Time elapsedTime = clock.getElapsedTime();
clock.restart();
if (rot > 360.0f)
rot = 0.0f;
rot += rotSpeed * elapsedTime.asSeconds();
float lightPosition[3] = { -100.0, -100.0, 100.0 };
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
viewMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, -3.0f, -10.0f)); // move back by 5 units
modelMatrix = glm::scale(glm::mat4(1.0f), glm::vec3(objScale)); // change last arg to 0.5f to shrink model by half
modelMatrix *= glm::rotate<float>(glm::mat4(1.0f), rot, glm::vec3(0, 1, 0));
shader->bind();
int projectionMatrixLocation = glGetUniformLocation(shader->id(), "projectionMatrix");
int viewMatrixLocation = glGetUniformLocation(shader->id(), "viewMatrix");
int modelMatrixLocation = glGetUniformLocation(shader->id(), "modelMatrix");
int ambientLocation = glGetUniformLocation(shader->id(), "ambientColor");
int diffuseLocation = glGetUniformLocation(shader->id(), "diffuseColor");
int specularLocation = glGetUniformLocation(shader->id(), "specularColor");
int lightPositionLocation = glGetUniformLocation(shader->id(), "lightPosition");
int normalMatrixLocation = glGetUniformLocation(shader->id(), "normalMatrix");
glUniformMatrix4fv(projectionMatrixLocation, 1, GL_FALSE, &projectionMatrix[0][0]);
glUniformMatrix4fv(viewMatrixLocation, 1, GL_FALSE, &viewMatrix[0][0]);
glUniformMatrix4fv(modelMatrixLocation, 1, GL_FALSE, &modelMatrix[0][0]);
glUniform3fv(ambientLocation, 1, colorArrayA);
glUniform3fv(diffuseLocation, 1, colorArrayD);
glUniform3fv(specularLocation, 1, colorArrayS);
glUniform3fv(lightPositionLocation, 1, lightPosition);
glUniformMatrix3fv(normalMatrixLocation, 1, GL_FALSE, normalArray);
glBindVertexArray(vaoID[0]);
glDrawRangeElements(GL_TRIANGLES, 0, numFaces*3, numFaces*3, GL_UNSIGNED_SHORT, NULL);
glBindVertexArray(0);
shader->unbind();
app->display();
return;
}
void objFileRenderer::handleEvents()
{
sf::Event event;
while (app->pollEvent(event))
{
if (event.type == sf::Event::Closed)
{
app->close();
}
if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape))
{
app->close();
}
if (event.type == sf::Event::Resized)
{
glViewport(0, 0, event.size.width, event.size.height);
}
}
return;
}
void objFileRenderer::mainLoop(int& numVertices, int& numFaces, float*& colorArrayA, float*& colorArrayD, float*& colorArrayS, float*& normalArray, float objScale)
{
while (app->isOpen())
{
renderScene(numVertices, numFaces, colorArrayA, colorArrayD, colorArrayS, normalArray, objScale);
handleEvents();
}
}
}
Datei: shader.cpp
#include "shader.h"
#include <string.h>
#include <iostream>
#include <stdlib.h>
using namespace std;
static char* textFileRead(const char *fileName) {
char* text = NULL;
if (fileName != NULL) {
FILE *file = fopen(fileName, "rt");
if (file != NULL) {
fseek(file, 0, SEEK_END);
int count = ftell(file);
rewind(file);
if (count > 0) {
text = (char*)malloc(sizeof(char) * (count + 1));
count = fread(text, sizeof(char), count, file);
text[count] = '\0';
}
fclose(file);
}
}
return text;
}
Shader::Shader() {
}
Shader::Shader(const char *vsFile, const char *fsFile) {
init(vsFile, fsFile);
}
void Shader::init(const char *vsFile, const char *fsFile) {
shader_vp = glCreateShader(GL_VERTEX_SHADER);
shader_fp = glCreateShader(GL_FRAGMENT_SHADER);
const char* vsText = NULL;
const char* fsText = NULL;
vsText = textFileRead(vsFile);
fsText = textFileRead(fsFile);
if (vsText == NULL)
{
cerr << "Error: vertex shader file not found" << endl;
}
if (fsText == NULL) {
cerr << "Error: fragment shader file not found." << endl;
}
if (vsText == NULL || fsText == NULL)
return;
glShaderSource(shader_vp, 1, &vsText, 0);
glShaderSource(shader_fp, 1, &fsText, 0);
glCompileShader(shader_vp);
glCompileShader(shader_fp);
shader_id = glCreateProgram();
glAttachShader(shader_id, shader_fp);
glAttachShader(shader_id, shader_vp);
glLinkProgram(shader_id);
glBindAttribLocation(shader_id, 0, "in_Position");
//glBindAttribLocation(shader_id, 1, "in_Color");
glBindAttribLocation(shader_id, 1, "in_Normal");
}
Shader::~Shader() {
glDetachShader(shader_id, shader_fp);
glDetachShader(shader_id, shader_vp);
glDeleteShader(shader_fp);
glDeleteShader(shader_vp);
glDeleteProgram(shader_id);
}
unsigned int Shader::id() {
return shader_id;
}
void Shader::bind() {
glUseProgram(shader_id);
}
void Shader::unbind() {
glUseProgram(0);
}
Datei: shader.vert
#version 150 core
in vec3 in_Position;
in vec3 in_Normal;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
uniform vec3 lightPosition;
uniform mat3 normalMatrix;
smooth out vec3 vVaryingNormal;
smooth out vec3 vVaryingLightDir;
void main()
{
// derive MVP and MV matrices
mat4 modelViewProjectionMatrix = projectionMatrix * viewMatrix * modelMatrix;
mat4 modelViewMatrix = viewMatrix * modelMatrix;
// get surface normal in eye coordinates
vVaryingNormal = normalMatrix * in_Normal;
// get vertex position in eye coordinates
vec4 vPosition4 = modelViewMatrix * vec4(in_Position, 1.0);
vec3 vPosition3 = vPosition4.xyz/vPosition4.w;
// get vector to light source
vVaryingLightDir = normalize(lightPosition - vPosition3);
// Set the position of the current vertex
gl_Position = modelViewProjectionMatrix * vec4(in_Position, 1.0);
}
Datei: shader.frag
#version 150 core
out vec4 out_Color;
uniform vec3 ambientColor;
uniform vec3 diffuseColor;
uniform vec3 specularColor;
smooth in vec3 vVaryingNormal;
smooth in vec3 vVaryingLightDir;
void main()
{
// dot product gives us diffuse intensity
float diff = max(0.0, dot(normalize(vVaryingNormal), normalize(vVaryingLightDir)));
// multiply intensity by diffuse color, force alpha to 1.0
out_Color = vec4(diff * diffuseColor, 1.0);
// add in ambient light
out_Color += vec4(ambientColor, 1.0);
// specular light
vec3 vReflection = normalize(reflect(-normalize(vVaryingLightDir), normalize(vVaryingNormal)));
float spec = max(0.0, dot(normalize(vVaryingNormal), vReflection));
if (diff != 0)
{
float fSpec = pow(spec, 128.0);
// Set the output color of our current pixel
out_Color.rgb += vec3(fSpec, fSpec, fSpec);
}
}
Ich weiß, dass es viel zu sehen gibt, aber ich wäre sehr glücklich, Hilfe zu bekommen, um diesem Problem auf den Grund zu gehen, also danke im Voraus an jeden, der Zeit hat, mir dabei zu helfen, dies herauszufinden!
Es ist für Ihr Problem nicht verwandt, aber Sie haben einen Speicherverlust. Sie löschen nie vsText oder psText in shader.cpp, obwohl Sie malloc verwenden, um Speicher für sie zuzuweisen. In der Tat sollten Sie nie Malloc verwenden müssen. In diesem Fall würde ich einen Verweis auf einen std :: vector übergeben, den Vektor auf die Größe der Datei skalieren, ihn füllen und dann diesen anstelle eines rohen Zeichens * verwenden. Sie könnten auch eine std :: shared_ptr verwenden, um Ihre char-Arrays zu halten und diese von der Funktion zu erhalten. Alles außer Malloc !!! :-). –
Robinson