我正在尝试渲染一个兔子的3D模型。
我尝试渲染.obj文件但屏幕上没有显示任何内容,这是代码:
MainDisplay类:
Code:
package com.dryadengine.gui;
import com.dryadengine.core.Model;
import com.dryadengine.framework.OBJLoader;
import com.dryadengine.framework.ShaderFactory;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.FloatBuffer;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.lwjgl.LWJGLException;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import org.lwjgl.util.vector.Matrix4f;
/**
*
* @author Roy
*/
public class MainDisplay {
private Model bunny;
private Matrix4f mProjection;
private Matrix4f mView;
private Matrix4f mModel;
private int shaderProgramID;
private int vboID;
private int vPositionID;
private int mProjectionID;
private int mViewID;
private int mModelID;
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
MainDisplay md = new MainDisplay();
md.create();
md.init();
md.run();
}
public MainDisplay() {
}
public void create() {
try {
Display.setDisplayMode(new DisplayMode(800, 600));
Display.setTitle("Dryad Engine 1.0.0");
Display.setFullscreen(false);
Display.setResizable(true);
Display.create();
} catch (LWJGLException ex) {
Logger.getLogger(MainDisplay.class.getName()).log(Level.SEVERE, null, ex);
System.exit(-1);
}
}
public void init() {
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
try {
shaderProgramID = ShaderFactory.createShaderProgram("vertexShader", "fragmentShader");
glUseProgram(shaderProgramID);
bunny = OBJLoader.parseOBJ(new File("src/com/dryadengine/assets/bunny.obj"));
FloatBuffer vbo = BufferUtils.createFloatBuffer(bunny.getVertices().length);
vbo.put(bunny.getVertices());
vbo.flip();
vboID = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, vbo, GL_STATIC_DRAW);
vPositionID = glGetAttribLocation(shaderProgramID, "vPosition");
glEnableVertexAttribArray(vPositionID);
mProjection = new Matrix4f();
float fieldOfView = 60f;
float aspectRatio = (float)Display.getWidth() / (float)Display.getHeight();
float nearPlane = 0.1f;
float farPlane = 100f;
float yScale = (float)(1.0f / Math.tan((fieldOfView / 2.0f) * Math.PI / 180));//this.coTangent(this.degreesToRadians(fieldOfView / 2f));
float xScale = yScale / aspectRatio;
float frustum_length = farPlane - nearPlane;
mProjection.m00 = xScale;
mProjection.m11 = yScale;
mProjection.m22 = -((farPlane + nearPlane) / frustum_length);
mProjection.m23 = -1;
mProjection.m32 = -((2 * nearPlane * farPlane) / frustum_length);
mProjection.m33 = 0;
mView = new Matrix4f();
mView.m23 = -5;
mModel = new Matrix4f();
mProjectionID = glGetUniformLocation(shaderProgramID, "mProjection");
mViewID = glGetUniformLocation(shaderProgramID, "mView");
mModelID = glGetUniformLocation(shaderProgramID, "mModel");
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glEnable(GL_DEPTH_TEST);
} catch (FileNotFoundException ex) {
Logger.getLogger(MainDisplay.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(MainDisplay.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void run() {
while (!Display.isCloseRequested()) {
if (Display.isVisible()) {
render();
}
if (Display.wasResized()) {
reshape();
}
Display.update();
Display.sync(60);
}
destroy();
}
public void render() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
FloatBuffer fb1 = BufferUtils.createFloatBuffer(16);
FloatBuffer fb2 = BufferUtils.createFloatBuffer(16);;
FloatBuffer fb3 = BufferUtils.createFloatBuffer(16);;
mProjection.store(fb1);
mView.store(fb2);
mModel.store(fb3);
glUniformMatrix4(mProjectionID, true, fb1);
glUniformMatrix4(mViewID, true, fb2);
glUniformMatrix4(mModelID, true, fb3);
for (int i = 0; i < bunny.getVertices().length / 3; i += 3) {
glVertexAttribPointer(vPositionID, 3, GL_FLOAT, false, 0, i);
glDrawArrays(GL_TRIANGLES, 0, 3);
}
}
public void reshape() {
glViewport(0, 0, Display.getWidth(), Display.getHeight());
}
public void dispose() {
glDeleteProgram(shaderProgramID);
glUseProgram(0);
glDeleteBuffers(vboID);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
public void destroy() {
Display.destroy();
}
}
ShaderFactory类:
package com.dryadengine.framework;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL20.*;
/**
*
* @author Roy
*/
public class ShaderFactory {
private static final String COMMON_SHADERS_PATH = "/com/dryadengine/shaders/";
private static final String SHADER_EXTENSION = ".dsf";
/**
*
* @param vertexShaderName
* @param fragmentShaderName
* @return a shader program
* @throws FileNotFoundException
* @throws IOException
*/
public static int createShaderProgram(String vertexShaderName, String fragmentShaderName) throws FileNotFoundException, IOException {
ArrayList<Integer> shaders = new ArrayList();
shaders.add(ShaderFactory.compileShader(GL_VERTEX_SHADER, getShaderFileCode(COMMON_SHADERS_PATH + vertexShaderName + SHADER_EXTENSION)));
shaders.add(ShaderFactory.compileShader(GL_FRAGMENT_SHADER, getShaderFileCode(COMMON_SHADERS_PATH + fragmentShaderName + SHADER_EXTENSION)));
return ShaderFactory.linkProgram(shaders);
}
/**
*
* @param shaderFilePath
* @return a shader file code
* @throws FileNotFoundException
* @throws IOException
*/
private static String getShaderFileCode(String shaderFilePath) throws FileNotFoundException, IOException {
StringBuilder shaderCode = new StringBuilder();
String line;
try {
try (BufferedReader br = new BufferedReader(new InputStreamReader(ShaderFactory.class.getResourceAsStream(shaderFilePath)))) {
while ((line = br.readLine()) != null) {
shaderCode.append(line).append("\n");
}
}
} catch (FileNotFoundException e) {
throw new FileNotFoundException(e.getMessage());
}
return shaderCode.toString();
}
/**
*
* @param shaderType
* @param shaderCode
* @return a compiled shader file id
*/
public static int compileShader(int shaderType, String shaderCode) {
int shaderID = glCreateShader(shaderType);
glShaderSource(shaderID, shaderCode);
glCompileShader(shaderID);
int status = glGetShaderi(shaderID, GL_COMPILE_STATUS);
if (status == GL_FALSE) {
glDeleteShader(shaderID);
throw new RuntimeException(glGetShaderInfoLog(shaderID, glGetShaderi(shaderID, GL_INFO_LOG_LENGTH)));
}
return shaderID;
}
/**
* Link the vertex shader and the fragment shader to the shader program
* @param shaders
* @return a shader program
*/
public static int linkProgram(ArrayList <Integer> shaders) {
int shaderProgramID = glCreateProgram();
for (Integer shader : shaders) {
glAttachShader(shaderProgramID, shader);
}
glLinkProgram(shaderProgramID);
int status = glGetProgrami(shaderProgramID, GL_LINK_STATUS);
if (status == GL_FALSE) {
glDeleteProgram(shaderProgramID);
throw new RuntimeException(glGetShaderInfoLog(shaderProgramID, glGetProgrami(shaderProgramID, GL_INFO_LOG_LENGTH)));
}
for (int shader : shaders) {
glDeleteShader(shader);
}
return shaderProgramID;
}
}
OBJLoader类:
package com.dryadengine.framework;
import com.dryadengine.core.Model;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author Roy
*/
public class OBJLoader {
/**
* Parse .obj file and make a model from it.
* @param f
* @return a model object
* @throws FileNotFoundException
* @throws IOException
*/
public static Model parseOBJ(File f) throws FileNotFoundException, IOException {
BufferedReader br = new BufferedReader(new FileReader(f));
String line;
Model m;
List<Float> vertices = new ArrayList<>();
List<Float> normals = new ArrayList<>();
while ((line = br.readLine()) != null) {
if (line.startsWith("v")) {
float x = Float.valueOf(line.split(" ")[1]);
float y = Float.valueOf(line.split(" ")[2]);
float z = Float.valueOf(line.split(" ")[3]);
vertices.add(x);
vertices.add(y);
vertices.add(z);
} else if (line.startsWith("vn")) {
float x = Float.valueOf(line.split(" ")[1]);
float y = Float.valueOf(line.split(" ")[2]);
float z = Float.valueOf(line.split(" ")[3]);
normals.add(x);
normals.add(y);
normals.add(z);
}
}
br.close();
float[] a = new float[vertices.size()];
float[] b = new float[normals.size()];
for (int i = 0; i < vertices.size(); i++) {
a[i] = vertices.get(i);
}
for (int i = 0; i < normals.size(); i++) {
b[i] = normals.get(i);
}
m = new Model(a, b);
return m;
}
}
模特课:
package com.dryadengine.core;
/**
*
* @author Roy
*/
public class Model {
private float[] vertices;
private float[] normals;
/**
* Construct a new model object.
* @param vertices
* @param normals
*/
public Model(float[] vertices, float[] normals) {
this.vertices = vertices;
this.normals = normals;
}
/**
*
* @return the model vertices array
*/
public float[] getVertices() {
return vertices;
}
/**
*
* @return the model normals array
*/
public float[] getNormals() {
return normals;
}
}
顶点着色器代码:
#version 330
uniform mat4 mProjection;
uniform mat4 mView;
uniform mat4 mModel;
in vec4 vPosition;
void main()
{
gl_Position = mProjection * mView * mModel * vPosition;
}
片段着色器代码:
#version 330
out vec4 color;
void main()
{
color = vec4(1.0, 0.0, 0.0, 1.0);
}
答案 0 :(得分:1)
我不确定是否还有其他错误,因为我对GL没有太多经验,但我注意到在你的OBJLoader课程中,你要检查一行是否以&#39开头; v&#39;第一
if (line.startsWith("v")) {
} else if (line.startsWith("vn")) {
}
这意味着如果它检测到&#39; vn&#39;那么它将由语句的第一部分处理,因为&#39; vn&#39;以&#39; v&#39;开头。声明的第二部分永远不会被执行。你可以检查&#39; vn&#39;首先,或者在&#39; v&#39;之后添加一个空格,检查&#39; v&#39;。
答案 1 :(得分:0)
你在render (...)
方法中做了一些非常奇怪的事情;每个三角形发出一次绘制调用。
通过布局数据的方式,如果传递数组中的顶点数而不是设置不同的顶点指针并传递值 3 。
glVertexAttribPointer (vPositionID, 3, GL_FLOAT, false, 0, 0);
glDrawArrays (GL_TRIANGLES, 0, bunny.getVertices ().length / 3);
您还可以通过将 true 传递给glUniformMatrix4
来告知GL 转置 您的矩阵。如果转置矩阵,则需要在顶点着色器中反转矩阵乘法的顺序,以便进行适当的变换。
void main()
{
gl_Position = vPosition * mModel * mView * mProjection;
}
这与你应该在OpenGL(列主要矩阵)中学习的所有东西背道而驰,所以不应该修改你的顶点着色器,而应该只是停止传递 true 。