java - LWJGL OpenGL 将顶点传递给着色器

标签 java opengl shader lwjgl vertex

如果我传递一个包含 3 个浮点的 float 组,表示没有 W 分量的顶点的 X Y Z,并将其传递给 VBO,然后告诉着色器中的输入变量使用 VBO 的内容,但是这个输入变量是vec4类型,w分量是否会被着色器设置为1?另外,顶点是否会被着色器标准化?

编辑

主显示类:

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 FloatBuffer vbo;
    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"));
            vbo = BufferUtils.createFloatBuffer(bunny.getFaces().size() * 3 * 3);
            float[] vertexData = new float[bunny.getFaces().size() * 3 * 3];
//            System.out.println("PRINTING 10 first faces info : ");
//            for (int i = 0; i < 10; i++) {
//                System.out.println("FACE #" +(i+1));
//                for (int j = 0; j < 3; j++) {
//                    System.out.println("VERTEX #" +(j + 1));
//                    System.out.println(bunny.getFaces().get(i).getVertices()[j].x + ", " +bunny.getFaces().get(i).getVertices()[j].y+ ", " +bunny.getFaces().get(i).getVertices()[j].z);
//                }
//            }
            for (int i = 0; i < bunny.getFaces().size(); i++) {
                for (int j = 0; j < 3; j++) {
                    //System.out.println("placing new vertex at cell #" +((i * 3 + j) * 3));
                    vertexData[(i * 3 + j) * 3] = bunny.getFaces().get(i).getVertices()[j].x;
                    //System.out.println("placing new vertex at cell #" +((i * 3 + j) * 3 + 1));
                    vertexData[(i * 3 + j) * 3 + 1] = bunny.getFaces().get(i).getVertices()[j].y;
                    //System.out.println("placing new vertex at cell #" +((i * 3 + j) * 3 + 2));
                    vertexData[(i * 3 + j) * 3 + 2] = bunny.getFaces().get(i).getVertices()[j].z;
                }
            }
            vbo.put(vertexData);
            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) * (float)(Math.PI / 180d)));
            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() {
        int fps = 0;
        long lastCheck = System.nanoTime();
        while (!Display.isCloseRequested()) {
            if (Display.isVisible()) {
                render();
            }
            if (Display.wasResized()) {
                resize(Display.getWidth(), Display.getHeight());
            }
            if (System.nanoTime() - lastCheck >= 1000000000) {
                System.out.println("FPS : " +fps);
                fps = 0;
                lastCheck = System.nanoTime();
            }
            fps++;
            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);
        fb1.flip();
        fb2.flip();
        fb3.flip();
        glUniformMatrix4(mProjectionID, false, fb1);
        glUniformMatrix4(mViewID, false, fb2);
        glUniformMatrix4(mModelID, false, fb3);
        glVertexAttribPointer (vPositionID, 3, GL_FLOAT, false, 0, 0);
        glDrawArrays(GL_TRIANGLES, 0, bunny.getFaces().size() * 3);
    }
    
    public void resize(int width, int height) {
        glViewport(0, 0, width, height);
    }
    
    public void dispose() {
        glDeleteProgram(shaderProgramID);
        glUseProgram(0);
        glDeleteBuffers(vboID);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
    }
    
    public void destroy() {
        dispose();
        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 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.Face;
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;
import org.lwjgl.util.vector.Vector3f;

/**
 *
 * @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<Vector3f> vertices = new ArrayList<>();
        List<Vector3f> normals = new ArrayList<>();
        List<Face> faces = 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(new Vector3f(x, y, 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(new Vector3f(x, y, z));
            } else if (line.startsWith("f ")) {
                Vector3f[] a = new Vector3f[3];
                Vector3f[] b = new Vector3f[3];
                a[0] = vertices.get(Integer.valueOf(line.split(" ")[1].split("//")[0]) - 1);
                a[1] = vertices.get(Integer.valueOf(line.split(" ")[2].split("//")[0]) - 1);
                a[2] = vertices.get(Integer.valueOf(line.split(" ")[3].split("//")[0]) - 1);
                b[0] = normals.get(Integer.valueOf(line.split(" ")[1].split("//")[1]) - 1);
                b[1] = normals.get(Integer.valueOf(line.split(" ")[2].split("//")[1]) - 1);
                b[2] = normals.get(Integer.valueOf(line.split(" ")[3].split("//")[1]) - 1);
                faces.add(new Face(a, b));
            }
        }
        br.close();
        m = new Model(faces);
        return m;
    }
    
}

模型类:

package com.dryadengine.core;

import java.util.List;

/**
 *
 * @author Roy
 */
public class Model {
    
    private List<Face> faces;
    
    /**
     * Construct a new model object.
     * @param faces
     */
    public Model(List<Face> faces) {
        this.faces = faces;
    }
    
    /**
     * 
     * @return the faces list
     */
    public List<Face> getFaces() {
        return faces;
    }
    
}

面部类别:

package com.dryadengine.core;

import org.lwjgl.util.vector.Vector3f;

/**
 *
 * @author Roy
 */
public class Face {
    
    private Vector3f[] vertices;
    private Vector3f[] normals;
    
    public Face() {
        vertices = new Vector3f[3];
        normals = new Vector3f[3];
    }
    
    public Face(Vector3f[] vertices, Vector3f[] normals) {
        this();
        this.vertices = vertices;
        this.normals = normals;
    }
    
    /**
     * 
     * @return the vertices array
     */
    public Vector3f[] getVertices() {
        return vertices;
    }
    
    /**
     * 
     * @return the normals array
     */
    public Vector3f[] getNormals() {
        return normals;
    }
    
    /**
     * Sets the vertices array
     * @param vertices 
     */
    public void setVertices(Vector3f[] vertices) {
        this.vertices = vertices;
    }
    
    /**
     * Sets the normals array
     * @param normals 
     */
    public void setNormals(Vector3f[] normals) {
        this.normals = 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 vOutputColor;

void main()
{
    vOutputColor = vec4(1.0, 1.0, 1.0, 1.0);
}

我使用的 bunny.obj 文件: http://rghost.net/54750078

最佳答案

是的,在这种情况下,w 将是 1.0。来自 OpenGL 3.3 规范中第 2.8.1 节(传输数组元素)的第一段:

If size is one then the x component of the attribute is specified by the array; the y, z, and w components are implicitly set to 0, 0, and 1, respectively. If size is two then the x and y components of the attribute are specified by the array; the z and w components are implicitly set to 0 and 1, respectively. If size is three then x, y, and z are specified, and w is implicitly set to 1. If size is four then all components are specified.

查看您发布的代码,我发现了一个问题,即您将顶点坐标复制到 vertexData:

vertexData[i * 3 + j] = bunny.getFaces().get(i).getVertices()[j].x;
vertexData[i * 3 + j] = bunny.getFaces().get(i).getVertices()[j].y;
vertexData[i * 3 + j] = bunny.getFaces().get(i).getVertices()[j].z;

这会将 x、y 和 z 坐标复制到同一数组位置。它应该看起来像这样:

vertexData[(i * 3 + j) * 3    ] = bunny.getFaces().get(i).getVertices()[j].x;
vertexData[(i * 3 + j) * 3 + 1] = bunny.getFaces().get(i).getVertices()[j].y;
vertexData[(i * 3 + j) * 3 + 2] = bunny.getFaces().get(i).getVertices()[j].z;

编辑:我想我又发现了一个问题。进一步研究 LWJGL 后,看起来矩阵的平移部分是 m30m31m32。所以我相信你需要改变你的模型矩阵:

mView.m23 = -5;

对此:

mView.m32 = -5;

关于java - LWJGL OpenGL 将顶点传递给着色器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23351572/

相关文章:

java - 使用 Eclipse Link 在 JPA 中映射 Joda Time "Period"的注释

c++ - 如何将着色器中生成的 float 据(而非颜色)拉回到 CPU?

java - LWJGL "discard"的透明度问题,一切都是不可见的?

opengl-es - SceneKit 使用纹理坐标绘制纹理

java - 如何设置颜色选择器?

java - Spring 。如何将 ObjectId 字段作为 String 返回以响应 Rest Controller ?

opengl - GLSL 几何着色器替换 glLineWidth

objective-c - OpenGL glBlendFuncSeparate

java - drawImage() 不绘制

c++ - 在哪里下载 opengl sdk(v.3 或 v.4)?