为什么几何着色器没有按预期从 1 个点生成 4 个点?
Why the geometry shader is not generating 4 points from 1 point as intended?
我想了解着色器在 OpenGL 中的工作原理。我想实现以下目标:
INPUT:
1 VAO WITH 1 VBO WHICH CONTAINS 1 vec2(x,y) (i.e. just a point defined in vec2)
---->
VERTEX SHADER:
JUST TURNS THE vec2(x,y) INTO A vec4(x,y,0.0,1.0)
---->
GEOMETRY SHADER:
RECEIVES vec4(x,y,0.0,1.0) POINT AND TRANSLATES INTO 4 POINTS
vec4(x-0.2,y-0.2,0.0,1.0)
vec4(x-0.2,y+0.2,0.0,1.0)
vec4(x+0.2,y+0.2,0.0,1.0)
vec4(x+0.2,y-0.2,0.0,1.0)
---->
FRAGMENT SHADER:
DRAWS EACH ONE OF THE 4 PIXELS IN BLUE
所以基本上我将 vec2 中的一对 x、y 坐标传递给顶点着色器,我希望在该点周围绘制 4 个点(在两个坐标中与该点相隔 0.2)。这就像画一个正方形的 4 个点,当你通过它只是那个假想的正方形的中心。
这是我试过的代码:
顶点着色器:
#version 330 core
layout (location = 0) in vec2 squareCenterPosition;
void main()
{
gl_Position = vec4(squareCenterPosition.x, squareCenterPosition.y, 0.0, 1.0);
}
几何着色器:
#version 330 core
layout (points) in;
layout (points, max_vertices = 1) out;
void main() {
vec4 gl_Position;
gl_Position = gl_in[0].gl_Position + vec4(-0.2, -0.2, 0.0, 0.0);
EmitVertex();
EndPrimitive();
gl_Position = gl_in[0].gl_Position + vec4(-0.2, +0.2, 0.0, 0.0);
EmitVertex();
EndPrimitive();
gl_Position = gl_in[0].gl_Position + vec4(+0.2, +0.2, 0.0, 0.0);
EmitVertex();
EndPrimitive();
gl_Position = gl_in[0].gl_Position + vec4(+0.2, -0.2, 0.0, 0.0);
EmitVertex();
EndPrimitive();
}
片段着色器:
#version 330 core
in vec4 vertexColor;
out vec4 color;
void main(void) {
color = vec4(1.0, 0.0, 0.0, 1.0);
}
JOGL class 实施:
package openglexample1;
import com.jogamp.common.nio.Buffers;
import com.jogamp.opengl.GL2;
import com.jogamp.opengl.GL3;
import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.GLCapabilities;
import com.jogamp.opengl.GLEventListener;
import com.jogamp.opengl.GLProfile;
import com.jogamp.opengl.awt.GLCanvas;
import com.jogamp.opengl.glu.GLU;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.FloatBuffer;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Vector;
import java.util.stream.Stream;
import javax.swing.JFrame;
public class WindowC extends JFrame implements GLEventListener {
/**
* @return the glcanvas
*/
public GLCanvas getGlcanvas() {
return glcanvas;
}
//getting the capabilities object of GL2 profile
final private GLProfile profile;
final private GLCapabilities capabilities;
final private GLCanvas glcanvas;
// GL PROGAM
private int glProgram;
// VAO AND VBOs
private int vao[] = new int[1]; // VAO GROUPS VBOs, ONLY ONE USED
private int vbo[] = new int[2]; // 2 VBOs FOR 2 SQUARES
public WindowC() {
// OpenGL CAPABILITIES
profile = GLProfile.get(GLProfile.GL2);
capabilities = new GLCapabilities(profile);
// CANVAS
glcanvas = new GLCanvas(capabilities);
glcanvas.addGLEventListener(this);
glcanvas.setSize(400, 400);
// JFRAME
this.getContentPane().add(glcanvas);
this.setSize(this.getContentPane().getPreferredSize());
}
@Override
public void display(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
// USE PROGRAM
gl.glUseProgram(glProgram);
// USE VBOs
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vbo[0]);
gl.glVertexAttribPointer(0, 2, gl.GL_FLOAT, false, 0, 0); // associate 0th vertex attribute with active buffer
gl.glEnableVertexAttribArray(0); // enable the 0th vertex attribute
// DRAW POINT
gl.glDrawArrays(GL2.GL_POINTS, 0, 1);
}
@Override
public void init(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
// CREATE PROGRAM
glProgram = gl.glCreateProgram();
// CREATE VERTEX SHADER
int vertexShader = gl.glCreateShader(GL2.GL_VERTEX_SHADER);
int geometryShader = gl.glCreateShader(GL2.GL_GEOMETRY_SHADER_BIT);
int fragmentShader = gl.glCreateShader(GL2.GL_FRAGMENT_SHADER);
// LOAD SOURCE CODE
String[] vertexShaderSource = readShader("VertexShader1.glsl");
gl.glShaderSource(vertexShader, vertexShaderSource.length, vertexShaderSource, null, 0);
gl.glCompileShader(vertexShader);
String[] geometryShaderSource = readShader("GeometryShader1.glsl");
gl.glShaderSource(geometryShader, geometryShaderSource.length, geometryShaderSource, null, 0);
gl.glCompileShader(geometryShader);
String[] fragmentShaderSource = readShader("FragmentShader1.glsl");
gl.glShaderSource(fragmentShader, fragmentShaderSource.length, fragmentShaderSource, null, 0);
gl.glCompileShader(fragmentShader);
// ATTACH VERTEX SHADER TO PROGRAM, LINK AND DELETE SHADERS
gl.glAttachShader(glProgram, vertexShader);
gl.glAttachShader(glProgram, geometryShader);
gl.glAttachShader(glProgram, fragmentShader);
gl.glLinkProgram(glProgram);
gl.glDeleteShader(vertexShader);
gl.glDeleteShader(geometryShader);
gl.glDeleteShader(fragmentShader);
// CREATE VAO
gl.glGenVertexArrays(1, vao, 0);
gl.glBindVertexArray(vao[0]);
// COORDINATES SQUARES
float[] coordinatesSquare1 = new float[]{0.5f, 0.5f};
// CREATE VBOs
gl.glGenBuffers(1, vbo, 0);
// POPULATE VBO 1 FOR SQUARE 1
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vbo[0]);
FloatBuffer bufferSquare1 = Buffers.newDirectFloatBuffer(coordinatesSquare1);
gl.glBufferData(gl.GL_ARRAY_BUFFER, bufferSquare1.limit()*4, bufferSquare1, gl.GL_STATIC_DRAW);
}
@Override
public void dispose(GLAutoDrawable drawable) {
}
@Override
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
System.out.println("reshape");
this.display(drawable);
}
private String[] readShader(String filename) {
Vector<String> lines = new Vector<String>();
try (Stream<String> stream = Files.lines(Paths.get(filename))) {
stream.forEach(x -> lines.add(x));
} catch (IOException e) {
e.printStackTrace();
}
// CONVERT VECTOR TO ARRAY
Object[] objArray = lines.toArray();
String[] array = Arrays.copyOf(objArray, objArray.length, String[].class);
return array;
}
}
Java "main" class 使用 GLCanvas 调用 JFrame:
package openglexample1;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.swing.WindowConstants;
public class OpenGLExample2 {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// THIRD WINDOW
WindowC basicFrame3 = new WindowC();
basicFrame3.setTitle("WindowC");
basicFrame3.setLocation(400,400);
basicFrame3.setVisible(true);
basicFrame3.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
}
但我在 (0.5,0.5) 坐标处得到的只是一个白色像素(不是蓝色),而不是四个蓝色像素。欢迎任何关于如何进一步调试它的提示。
---
编辑:
根据下面的回答,我按如下方式编辑代码。仅使用 GL3 并实施答案中所述的更改,但结果仍然相同。
Java OpenGL class:
package openglexample1;
import com.jogamp.common.nio.Buffers;
import com.jogamp.opengl.GL3;
import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.GLCapabilities;
import com.jogamp.opengl.GLEventListener;
import com.jogamp.opengl.GLProfile;
import com.jogamp.opengl.awt.GLCanvas;
import com.jogamp.opengl.glu.GLU;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.FloatBuffer;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Vector;
import java.util.stream.Stream;
import javax.swing.JFrame;
public class WindowC extends JFrame implements GLEventListener {
/**
* @return the glcanvas
*/
public GLCanvas getGlcanvas() {
return glcanvas;
}
//getting the capabilities object of GL2 profile
final private GLProfile profile;
final private GLCapabilities capabilities;
final private GLCanvas glcanvas;
// GL PROGAM
private int glProgram;
// VAO AND VBOs
private int vao[] = new int[1]; // VAO GROUPS VBOs, ONLY ONE USED
private int vbo[] = new int[2]; // 2 VBOs FOR 2 SQUARES
public WindowC() {
// OpenGL CAPABILITIES
profile = GLProfile.get(GLProfile.GL3);
capabilities = new GLCapabilities(profile);
// CANVAS
glcanvas = new GLCanvas(capabilities);
glcanvas.addGLEventListener(this);
glcanvas.setSize(400, 400);
// JFRAME
this.getContentPane().add(glcanvas);
this.setSize(this.getContentPane().getPreferredSize());
}
@Override
public void display(GLAutoDrawable drawable) {
GL3 gl = drawable.getGL().getGL3();
// USE PROGRAM
gl.glUseProgram(glProgram);
// USE VBOs
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vbo[0]);
gl.glVertexAttribPointer(0, 2, gl.GL_FLOAT, false, 0, 0); // associate 0th vertex attribute with active buffer
gl.glEnableVertexAttribArray(0); // enable the 0th vertex attribute
// DRAW POINT
gl.glDrawArrays(GL3.GL_POINTS, 0, 1);
}
@Override
public void init(GLAutoDrawable drawable) {
GL3 gl = drawable.getGL().getGL3();
// CREATE PROGRAM
glProgram = gl.glCreateProgram();
// CREATE VERTEX SHADER
int vertexShader = gl.glCreateShader(GL3.GL_VERTEX_SHADER);
int geometryShader = gl.glCreateShader(GL3.GL_GEOMETRY_SHADER);
int fragmentShader = gl.glCreateShader(GL3.GL_FRAGMENT_SHADER);
// LOAD SOURCE CODE
String[] vertexShaderSource = readShader("VertexShader1.glsl");
gl.glShaderSource(vertexShader, vertexShaderSource.length, vertexShaderSource, null, 0);
gl.glCompileShader(vertexShader);
String[] geometryShaderSource = readShader("GeometryShader1.glsl");
gl.glShaderSource(geometryShader, geometryShaderSource.length, geometryShaderSource, null, 0);
gl.glCompileShader(geometryShader);
String[] fragmentShaderSource = readShader("FragmentShader1.glsl");
gl.glShaderSource(fragmentShader, fragmentShaderSource.length, fragmentShaderSource, null, 0);
gl.glCompileShader(fragmentShader);
// ATTACH VERTEX SHADER TO PROGRAM, LINK AND DELETE SHADERS
gl.glAttachShader(glProgram, vertexShader);
gl.glAttachShader(glProgram, geometryShader);
gl.glAttachShader(glProgram, fragmentShader);
gl.glLinkProgram(glProgram);
gl.glDeleteShader(vertexShader);
gl.glDeleteShader(geometryShader);
gl.glDeleteShader(fragmentShader);
// CREATE VAO
gl.glGenVertexArrays(1, vao, 0);
gl.glBindVertexArray(vao[0]);
// COORDINATES SQUARES
float[] coordinatesSquare1 = new float[]{0.5f, 0.5f};
// CREATE VBOs
gl.glGenBuffers(1, vbo, 0);
// POPULATE VBO 1 FOR SQUARE 1
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vbo[0]);
FloatBuffer bufferSquare1 = Buffers.newDirectFloatBuffer(coordinatesSquare1);
gl.glBufferData(gl.GL_ARRAY_BUFFER, bufferSquare1.limit()*4, bufferSquare1, gl.GL_STATIC_DRAW);
}
@Override
public void dispose(GLAutoDrawable drawable) {
}
@Override
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
System.out.println("reshape");
this.display(drawable);
}
private String[] readShader(String filename) {
Vector<String> lines = new Vector<String>();
try (Stream<String> stream = Files.lines(Paths.get(filename))) {
stream.forEach(x -> lines.add(x));
} catch (IOException e) {
e.printStackTrace();
}
// CONVERT VECTOR TO ARRAY
Object[] objArray = lines.toArray();
String[] array = Arrays.copyOf(objArray, objArray.length, String[].class);
return array;
}
}
几何着色器:
#version 330 core
layout (points) in;
layout (points, max_vertices = 4) out;
void main() {
gl_Position = gl_in[0].gl_Position + vec4(-0.2, -0.2, 0.0, 0.0);
EmitVertex();
EndPrimitive();
gl_Position = gl_in[0].gl_Position + vec4(-0.2, +0.2, 0.0, 0.0);
EmitVertex();
EndPrimitive();
gl_Position = gl_in[0].gl_Position + vec4(+0.2, +0.2, 0.0, 0.0);
EmitVertex();
EndPrimitive();
gl_Position = gl_in[0].gl_Position + vec4(+0.2, -0.2, 0.0, 0.0);
EmitVertex();
EndPrimitive();
}
有一些问题
您已在几何着色器中声明了一个局部变量 vec4 gl_Position;
。这应该会导致编译错误,因为所有以 gl_
开头的名称都保留用于实现。无论如何,几何着色器永远不会写入每个顶点输出 gl_Position
。参见 Geometry Shader- Outputs。
删除声明:
vec4 gl_Position;
最大顶点的规格为:
layout (points, max_vertices = 1) out;
max_vertices
是一个编译时常量,它定义了单次调用将写入的最大顶点数。参见 Geometry Shader。
int geometryShader = gl.glCreateShader(GL2.GL_GEOMETRY_SHADER_BIT);
最大顶点数必须为 4:
layout (points, max_vertices = 4) out;
着色器类型必须是 GL32.GL_GEOMETRY_SHADER
而不是 GL2.GL_GEOMETRY_SHADER_BIT
:
int geometryShader = gl.glCreateShader(GL2.GL_GEOMETRY_SHADER_BIT);
int geometryShader = gl.glCreateShader(GL32.GL_GEOMETRY_SHADER);
GL_GEOMETRY_SHADER_BIT
不是 glCreateShader
的有效参数,将导致 INVALID_ENUM
错误。
要使用 Geometry Shader,您必须创建一个 OpenGL 3.2 上下文(至少):
(参见 Class GLProfile
)
profile = GLProfile.get(GLProfile.GL2);
profile = GLProfile.get(GLProfile.GL3);
我想了解着色器在 OpenGL 中的工作原理。我想实现以下目标:
INPUT:
1 VAO WITH 1 VBO WHICH CONTAINS 1 vec2(x,y) (i.e. just a point defined in vec2)
---->
VERTEX SHADER:
JUST TURNS THE vec2(x,y) INTO A vec4(x,y,0.0,1.0)
---->
GEOMETRY SHADER:
RECEIVES vec4(x,y,0.0,1.0) POINT AND TRANSLATES INTO 4 POINTS
vec4(x-0.2,y-0.2,0.0,1.0)
vec4(x-0.2,y+0.2,0.0,1.0)
vec4(x+0.2,y+0.2,0.0,1.0)
vec4(x+0.2,y-0.2,0.0,1.0)
---->
FRAGMENT SHADER:
DRAWS EACH ONE OF THE 4 PIXELS IN BLUE
所以基本上我将 vec2 中的一对 x、y 坐标传递给顶点着色器,我希望在该点周围绘制 4 个点(在两个坐标中与该点相隔 0.2)。这就像画一个正方形的 4 个点,当你通过它只是那个假想的正方形的中心。
这是我试过的代码:
顶点着色器:
#version 330 core
layout (location = 0) in vec2 squareCenterPosition;
void main()
{
gl_Position = vec4(squareCenterPosition.x, squareCenterPosition.y, 0.0, 1.0);
}
几何着色器:
#version 330 core
layout (points) in;
layout (points, max_vertices = 1) out;
void main() {
vec4 gl_Position;
gl_Position = gl_in[0].gl_Position + vec4(-0.2, -0.2, 0.0, 0.0);
EmitVertex();
EndPrimitive();
gl_Position = gl_in[0].gl_Position + vec4(-0.2, +0.2, 0.0, 0.0);
EmitVertex();
EndPrimitive();
gl_Position = gl_in[0].gl_Position + vec4(+0.2, +0.2, 0.0, 0.0);
EmitVertex();
EndPrimitive();
gl_Position = gl_in[0].gl_Position + vec4(+0.2, -0.2, 0.0, 0.0);
EmitVertex();
EndPrimitive();
}
片段着色器:
#version 330 core
in vec4 vertexColor;
out vec4 color;
void main(void) {
color = vec4(1.0, 0.0, 0.0, 1.0);
}
JOGL class 实施:
package openglexample1;
import com.jogamp.common.nio.Buffers;
import com.jogamp.opengl.GL2;
import com.jogamp.opengl.GL3;
import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.GLCapabilities;
import com.jogamp.opengl.GLEventListener;
import com.jogamp.opengl.GLProfile;
import com.jogamp.opengl.awt.GLCanvas;
import com.jogamp.opengl.glu.GLU;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.FloatBuffer;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Vector;
import java.util.stream.Stream;
import javax.swing.JFrame;
public class WindowC extends JFrame implements GLEventListener {
/**
* @return the glcanvas
*/
public GLCanvas getGlcanvas() {
return glcanvas;
}
//getting the capabilities object of GL2 profile
final private GLProfile profile;
final private GLCapabilities capabilities;
final private GLCanvas glcanvas;
// GL PROGAM
private int glProgram;
// VAO AND VBOs
private int vao[] = new int[1]; // VAO GROUPS VBOs, ONLY ONE USED
private int vbo[] = new int[2]; // 2 VBOs FOR 2 SQUARES
public WindowC() {
// OpenGL CAPABILITIES
profile = GLProfile.get(GLProfile.GL2);
capabilities = new GLCapabilities(profile);
// CANVAS
glcanvas = new GLCanvas(capabilities);
glcanvas.addGLEventListener(this);
glcanvas.setSize(400, 400);
// JFRAME
this.getContentPane().add(glcanvas);
this.setSize(this.getContentPane().getPreferredSize());
}
@Override
public void display(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
// USE PROGRAM
gl.glUseProgram(glProgram);
// USE VBOs
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vbo[0]);
gl.glVertexAttribPointer(0, 2, gl.GL_FLOAT, false, 0, 0); // associate 0th vertex attribute with active buffer
gl.glEnableVertexAttribArray(0); // enable the 0th vertex attribute
// DRAW POINT
gl.glDrawArrays(GL2.GL_POINTS, 0, 1);
}
@Override
public void init(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
// CREATE PROGRAM
glProgram = gl.glCreateProgram();
// CREATE VERTEX SHADER
int vertexShader = gl.glCreateShader(GL2.GL_VERTEX_SHADER);
int geometryShader = gl.glCreateShader(GL2.GL_GEOMETRY_SHADER_BIT);
int fragmentShader = gl.glCreateShader(GL2.GL_FRAGMENT_SHADER);
// LOAD SOURCE CODE
String[] vertexShaderSource = readShader("VertexShader1.glsl");
gl.glShaderSource(vertexShader, vertexShaderSource.length, vertexShaderSource, null, 0);
gl.glCompileShader(vertexShader);
String[] geometryShaderSource = readShader("GeometryShader1.glsl");
gl.glShaderSource(geometryShader, geometryShaderSource.length, geometryShaderSource, null, 0);
gl.glCompileShader(geometryShader);
String[] fragmentShaderSource = readShader("FragmentShader1.glsl");
gl.glShaderSource(fragmentShader, fragmentShaderSource.length, fragmentShaderSource, null, 0);
gl.glCompileShader(fragmentShader);
// ATTACH VERTEX SHADER TO PROGRAM, LINK AND DELETE SHADERS
gl.glAttachShader(glProgram, vertexShader);
gl.glAttachShader(glProgram, geometryShader);
gl.glAttachShader(glProgram, fragmentShader);
gl.glLinkProgram(glProgram);
gl.glDeleteShader(vertexShader);
gl.glDeleteShader(geometryShader);
gl.glDeleteShader(fragmentShader);
// CREATE VAO
gl.glGenVertexArrays(1, vao, 0);
gl.glBindVertexArray(vao[0]);
// COORDINATES SQUARES
float[] coordinatesSquare1 = new float[]{0.5f, 0.5f};
// CREATE VBOs
gl.glGenBuffers(1, vbo, 0);
// POPULATE VBO 1 FOR SQUARE 1
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vbo[0]);
FloatBuffer bufferSquare1 = Buffers.newDirectFloatBuffer(coordinatesSquare1);
gl.glBufferData(gl.GL_ARRAY_BUFFER, bufferSquare1.limit()*4, bufferSquare1, gl.GL_STATIC_DRAW);
}
@Override
public void dispose(GLAutoDrawable drawable) {
}
@Override
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
System.out.println("reshape");
this.display(drawable);
}
private String[] readShader(String filename) {
Vector<String> lines = new Vector<String>();
try (Stream<String> stream = Files.lines(Paths.get(filename))) {
stream.forEach(x -> lines.add(x));
} catch (IOException e) {
e.printStackTrace();
}
// CONVERT VECTOR TO ARRAY
Object[] objArray = lines.toArray();
String[] array = Arrays.copyOf(objArray, objArray.length, String[].class);
return array;
}
}
Java "main" class 使用 GLCanvas 调用 JFrame:
package openglexample1;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.swing.WindowConstants;
public class OpenGLExample2 {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// THIRD WINDOW
WindowC basicFrame3 = new WindowC();
basicFrame3.setTitle("WindowC");
basicFrame3.setLocation(400,400);
basicFrame3.setVisible(true);
basicFrame3.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
}
但我在 (0.5,0.5) 坐标处得到的只是一个白色像素(不是蓝色),而不是四个蓝色像素。欢迎任何关于如何进一步调试它的提示。
---
编辑:
根据下面的回答,我按如下方式编辑代码。仅使用 GL3 并实施答案中所述的更改,但结果仍然相同。
Java OpenGL class:
package openglexample1;
import com.jogamp.common.nio.Buffers;
import com.jogamp.opengl.GL3;
import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.GLCapabilities;
import com.jogamp.opengl.GLEventListener;
import com.jogamp.opengl.GLProfile;
import com.jogamp.opengl.awt.GLCanvas;
import com.jogamp.opengl.glu.GLU;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.FloatBuffer;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Vector;
import java.util.stream.Stream;
import javax.swing.JFrame;
public class WindowC extends JFrame implements GLEventListener {
/**
* @return the glcanvas
*/
public GLCanvas getGlcanvas() {
return glcanvas;
}
//getting the capabilities object of GL2 profile
final private GLProfile profile;
final private GLCapabilities capabilities;
final private GLCanvas glcanvas;
// GL PROGAM
private int glProgram;
// VAO AND VBOs
private int vao[] = new int[1]; // VAO GROUPS VBOs, ONLY ONE USED
private int vbo[] = new int[2]; // 2 VBOs FOR 2 SQUARES
public WindowC() {
// OpenGL CAPABILITIES
profile = GLProfile.get(GLProfile.GL3);
capabilities = new GLCapabilities(profile);
// CANVAS
glcanvas = new GLCanvas(capabilities);
glcanvas.addGLEventListener(this);
glcanvas.setSize(400, 400);
// JFRAME
this.getContentPane().add(glcanvas);
this.setSize(this.getContentPane().getPreferredSize());
}
@Override
public void display(GLAutoDrawable drawable) {
GL3 gl = drawable.getGL().getGL3();
// USE PROGRAM
gl.glUseProgram(glProgram);
// USE VBOs
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vbo[0]);
gl.glVertexAttribPointer(0, 2, gl.GL_FLOAT, false, 0, 0); // associate 0th vertex attribute with active buffer
gl.glEnableVertexAttribArray(0); // enable the 0th vertex attribute
// DRAW POINT
gl.glDrawArrays(GL3.GL_POINTS, 0, 1);
}
@Override
public void init(GLAutoDrawable drawable) {
GL3 gl = drawable.getGL().getGL3();
// CREATE PROGRAM
glProgram = gl.glCreateProgram();
// CREATE VERTEX SHADER
int vertexShader = gl.glCreateShader(GL3.GL_VERTEX_SHADER);
int geometryShader = gl.glCreateShader(GL3.GL_GEOMETRY_SHADER);
int fragmentShader = gl.glCreateShader(GL3.GL_FRAGMENT_SHADER);
// LOAD SOURCE CODE
String[] vertexShaderSource = readShader("VertexShader1.glsl");
gl.glShaderSource(vertexShader, vertexShaderSource.length, vertexShaderSource, null, 0);
gl.glCompileShader(vertexShader);
String[] geometryShaderSource = readShader("GeometryShader1.glsl");
gl.glShaderSource(geometryShader, geometryShaderSource.length, geometryShaderSource, null, 0);
gl.glCompileShader(geometryShader);
String[] fragmentShaderSource = readShader("FragmentShader1.glsl");
gl.glShaderSource(fragmentShader, fragmentShaderSource.length, fragmentShaderSource, null, 0);
gl.glCompileShader(fragmentShader);
// ATTACH VERTEX SHADER TO PROGRAM, LINK AND DELETE SHADERS
gl.glAttachShader(glProgram, vertexShader);
gl.glAttachShader(glProgram, geometryShader);
gl.glAttachShader(glProgram, fragmentShader);
gl.glLinkProgram(glProgram);
gl.glDeleteShader(vertexShader);
gl.glDeleteShader(geometryShader);
gl.glDeleteShader(fragmentShader);
// CREATE VAO
gl.glGenVertexArrays(1, vao, 0);
gl.glBindVertexArray(vao[0]);
// COORDINATES SQUARES
float[] coordinatesSquare1 = new float[]{0.5f, 0.5f};
// CREATE VBOs
gl.glGenBuffers(1, vbo, 0);
// POPULATE VBO 1 FOR SQUARE 1
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vbo[0]);
FloatBuffer bufferSquare1 = Buffers.newDirectFloatBuffer(coordinatesSquare1);
gl.glBufferData(gl.GL_ARRAY_BUFFER, bufferSquare1.limit()*4, bufferSquare1, gl.GL_STATIC_DRAW);
}
@Override
public void dispose(GLAutoDrawable drawable) {
}
@Override
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
System.out.println("reshape");
this.display(drawable);
}
private String[] readShader(String filename) {
Vector<String> lines = new Vector<String>();
try (Stream<String> stream = Files.lines(Paths.get(filename))) {
stream.forEach(x -> lines.add(x));
} catch (IOException e) {
e.printStackTrace();
}
// CONVERT VECTOR TO ARRAY
Object[] objArray = lines.toArray();
String[] array = Arrays.copyOf(objArray, objArray.length, String[].class);
return array;
}
}
几何着色器:
#version 330 core
layout (points) in;
layout (points, max_vertices = 4) out;
void main() {
gl_Position = gl_in[0].gl_Position + vec4(-0.2, -0.2, 0.0, 0.0);
EmitVertex();
EndPrimitive();
gl_Position = gl_in[0].gl_Position + vec4(-0.2, +0.2, 0.0, 0.0);
EmitVertex();
EndPrimitive();
gl_Position = gl_in[0].gl_Position + vec4(+0.2, +0.2, 0.0, 0.0);
EmitVertex();
EndPrimitive();
gl_Position = gl_in[0].gl_Position + vec4(+0.2, -0.2, 0.0, 0.0);
EmitVertex();
EndPrimitive();
}
有一些问题
您已在几何着色器中声明了一个局部变量 vec4 gl_Position;
。这应该会导致编译错误,因为所有以 gl_
开头的名称都保留用于实现。无论如何,几何着色器永远不会写入每个顶点输出 gl_Position
。参见 Geometry Shader- Outputs。
删除声明:
vec4 gl_Position;
最大顶点的规格为:
layout (points, max_vertices = 1) out;
max_vertices
是一个编译时常量,它定义了单次调用将写入的最大顶点数。参见 Geometry Shader。
int geometryShader = gl.glCreateShader(GL2.GL_GEOMETRY_SHADER_BIT);
最大顶点数必须为 4:
layout (points, max_vertices = 4) out;
着色器类型必须是 GL32.GL_GEOMETRY_SHADER
而不是 GL2.GL_GEOMETRY_SHADER_BIT
:
int geometryShader = gl.glCreateShader(GL2.GL_GEOMETRY_SHADER_BIT);
int geometryShader = gl.glCreateShader(GL32.GL_GEOMETRY_SHADER);
GL_GEOMETRY_SHADER_BIT
不是 glCreateShader
的有效参数,将导致 INVALID_ENUM
错误。
要使用 Geometry Shader,您必须创建一个 OpenGL 3.2 上下文(至少):
(参见 Class GLProfile
)
profile = GLProfile.get(GLProfile.GL2);
profile = GLProfile.get(GLProfile.GL3);