0
當我點擊它時,如何獲得3D空間中對象的z座標。 (它不是一個對象更多的圖形,我需要知道用戶選擇了什麼)我使用JOGL。有沒有一種簡單的方法來獲取OpenGL中對象的深度(JOGL)
當我點擊它時,如何獲得3D空間中對象的z座標。 (它不是一個對象更多的圖形,我需要知道用戶選擇了什麼)我使用JOGL。有沒有一種簡單的方法來獲取OpenGL中對象的深度(JOGL)
我剛剛完成從g-truck ogl-samples移植picking sample。
我會盡力給你一個關於代碼的快速解釋。
首先,我們啓用深度測試
private boolean initTest(GL4 gl4) {
gl4.glEnable(GL_DEPTH_TEST);
return true;
}
在我們:
glGenBuffers
glBufferData
將使用第一個參數指定的目標上的任何內容,在這種情況下爲GL_ELEMENT_ARRAY_BUFFER
GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
(這是一個全局參數)來確定存儲我們的變換變量的最小統一塊大小。如果我們想通過glBindBufferRange
來綁定它,我們不會使用這個函數來綁定我們的拾取緩衝區,這是必須的,這就是爲什麼我們只傳遞一個浮點數的原因,Float.BYTES
glBufferData
的最後一個參數只是一個提示(這取決於OpenGL和驅動程序做他們想要的),因爲你看到的是索引和頂點是靜態的,因爲我們不會改變它們,但是對於統一緩衝區是動態的,因爲我們會每隔一段時間更新它們幀。代碼:
private boolean initBuffer(GL4 gl4) {
gl4.glGenBuffers(Buffer.MAX.ordinal(), bufferName, 0);
gl4.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferName[Buffer.ELEMENT.ordinal()]);
ShortBuffer elementBuffer = GLBuffers.newDirectShortBuffer(elementData);
gl4.glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementSize, elementBuffer, GL_STATIC_DRAW);
gl4.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
gl4.glBindBuffer(GL_ARRAY_BUFFER, bufferName[Buffer.VERTEX.ordinal()]);
FloatBuffer vertexBuffer = GLBuffers.newDirectFloatBuffer(vertexData);
gl4.glBufferData(GL_ARRAY_BUFFER, vertexSize, vertexBuffer, GL_STATIC_DRAW);
gl4.glBindBuffer(GL_ARRAY_BUFFER, 0);
int[] uniformBufferOffset = {0};
gl4.glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, uniformBufferOffset, 0);
int uniformBlockSize = Math.max(projection.length * Float.BYTES, uniformBufferOffset[0]);
gl4.glBindBuffer(GL_UNIFORM_BUFFER, bufferName[Buffer.TRANSFORM.ordinal()]);
gl4.glBufferData(GL_UNIFORM_BUFFER, uniformBlockSize, null, GL_DYNAMIC_DRAW);
gl4.glBindBuffer(GL_UNIFORM_BUFFER, 0);
gl4.glBindBuffer(GL_TEXTURE_BUFFER, bufferName[Buffer.PICKING.ordinal()]);
gl4.glBufferData(GL_TEXTURE_BUFFER, Float.BYTES, null, GL_DYNAMIC_READ);
gl4.glBindBuffer(GL_TEXTURE_BUFFER, 0);
return true;
}
在我們初始化我們的紋理initTexture
,我們:
glGenTextures
GL_UNPACK_ALIGNMENT
爲1(默認值通常爲4字節),以避免任何問題(因爲您的水平紋理尺寸必須與對齊相匹配)。GL_TEXTURE0
,存在特定數量的紋理槽,並且在處理任何紋理之前需要指定它。glTexStorage2D
GL_UNPACK_ALIGNMENT
GL_TEXTURE0
我們的其它質地PICKING
PICKING
質地到PICKING
緩衝與關聯glTexBuffer
代碼:
private boolean initTexture(GL4 gl4) {
try {
jgli.Texture2D texture = new Texture2D(jgli.Load.load(TEXTURE_ROOT + "/" + TEXTURE_DIFFUSE));
jgli.Gl.Format format = jgli.Gl.instance.translate(texture.format());
gl4.glGenTextures(Texture.MAX.ordinal(), textureName, 0);
// Diffuse
{
gl4.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
gl4.glActiveTexture(GL_TEXTURE0);
gl4.glBindTexture(GL_TEXTURE_2D, textureName[Texture.DIFFUSE.ordinal()]);
gl4.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED);
gl4.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_GREEN);
gl4.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_BLUE);
gl4.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ALPHA);
gl4.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
gl4.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, texture.levels() - 1);
gl4.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
gl4.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gl4.glTexStorage2D(GL_TEXTURE_2D, texture.levels(), format.internal.value,
texture.dimensions(0)[0], texture.dimensions(0)[1]);
for (int level = 0; level < texture.levels(); ++level) {
gl4.glTexSubImage2D(GL_TEXTURE_2D, level,
0, 0,
texture.dimensions(level)[0], texture.dimensions(level)[1],
format.external.value, format.type.value,
texture.data(0, 0, level));
}
gl4.glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
}
// Piking
{
gl4.glBindTexture(GL_TEXTURE_BUFFER, textureName[Texture.PICKING.ordinal()]);
gl4.glTexBuffer(GL_TEXTURE_BUFFER, GL_R32F, bufferName[Buffer.PICKING.ordinal()]);
gl4.glBindTexture(GL_TEXTURE_BUFFER, 0);
}
} catch (IOException ex) {
Logger.getLogger(Gl_420_picking.class.getName()).log(Level.SEVERE, null, ex);
}
return true;
}
在我們初始化我們的程序,由initProgram
:
glGenProgramPipelines
vertShaderCode
,其中GL_VERTEX_SHADER
是着色器類型,SHADERS_ROOT
是其中着色器源位於的地方,SHADERS_SOURCE_UPDATE
是名稱和"vert"
是擴展名。programName
glProgramParameteri
shaderProgram
和鏈接和編譯它,link
pipelineName
有,glUseProgramStages代碼:
private boolean initProgram(GL4 gl4) {
boolean validated = true;
gl4.glGenProgramPipelines(1, pipelineName, 0);
// Create program
if (validated) {
ShaderProgram shaderProgram = new ShaderProgram();
ShaderCode vertShaderCode = ShaderCode.create(gl4, GL_VERTEX_SHADER,
this.getClass(), SHADERS_ROOT, null, SHADERS_SOURCE_UPDATE, "vert", null, true);
ShaderCode fragShaderCode = ShaderCode.create(gl4, GL_FRAGMENT_SHADER,
this.getClass(), SHADERS_ROOT, null, SHADERS_SOURCE_UPDATE, "frag", null, true);
shaderProgram.init(gl4);
programName = shaderProgram.program();
gl4.glProgramParameteri(programName, GL_PROGRAM_SEPARABLE, GL_TRUE);
shaderProgram.add(vertShaderCode);
shaderProgram.add(fragShaderCode);
shaderProgram.link(gl4, System.out);
}
if (validated) {
gl4.glUseProgramStages(pipelineName[0], GL_VERTEX_SHADER_BIT | GL_FRAGMENT_SHADER_BIT, programName);
}
return validated & checkError(gl4, "initProgram");
}
在initVertexArray
我們:
glGenVertexArrays
,並將其綁定,glBindVertexArray
Semantic.Attr.POSITION
(這將匹配頂點着色器中的一個),組件大小2
,類型GL_FLOAT
,規格化的false
,步幅或每個頂點屬性2 * 2 * Float.BYTES
的總大小以及此屬性0
中的偏移量標識。同樣的顏色。glVertexAttribPointer
,以便OpenGL可以知道這些參數指向哪個緩衝區。glEnableVertexAttribArray
代碼:
private boolean initVertexArray(GL4 gl4) {
gl4.glGenVertexArrays(1, vertexArrayName, 0);
gl4.glBindVertexArray(vertexArrayName[0]);
{
gl4.glBindBuffer(GL_ARRAY_BUFFER, bufferName[Buffer.VERTEX.ordinal()]);
gl4.glVertexAttribPointer(Semantic.Attr.POSITION, 2, GL_FLOAT, false, 2 * 2 * Float.BYTES, 0);
gl4.glVertexAttribPointer(Semantic.Attr.TEXCOORD, 2, GL_FLOAT, false, 2 * 2 * Float.BYTES, 2 * Float.BYTES);
gl4.glBindBuffer(GL_ARRAY_BUFFER, 0);
gl4.glEnableVertexAttribArray(Semantic.Attr.POSITION);
gl4.glEnableVertexAttribArray(Semantic.Attr.TEXCOORD);
gl4.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferName[Buffer.ELEMENT.ordinal()]);
}
gl4.glBindVertexArray(0);
return true;
}
在render
我們:
TRANSFORM
緩衝區,它將包含我們的轉換格式離子矩陣。pointer
。pointer
中並倒回緩衝區(再次將位置設置爲0)。depthValue
和顏色緩衝器,與彩色{1.0f, 0.5f, 0.0f, 1.0f}
glDrawElementsInstancedBaseVertexBaseInstance
被過度使用,但最重要的是基本類型GL_TRIANGLES
,指數elementCount
的數量和它們的類型GL_UNSIGNED_SHORT
代碼:
@Override
protected boolean render(GL gl) {
GL4 gl4 = (GL4) gl;
{
gl4.glBindBuffer(GL_UNIFORM_BUFFER, bufferName[Buffer.TRANSFORM.ordinal()]);
ByteBuffer pointer = gl4.glMapBufferRange(
GL_UNIFORM_BUFFER, 0, projection.length * Float.BYTES,
GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
FloatUtil.makePerspective(projection, 0, true, (float) Math.PI * 0.25f,
(float) windowSize.x/windowSize.y, 0.1f, 100.0f);
FloatUtil.makeIdentity(model);
FloatUtil.multMatrix(projection, view());
FloatUtil.multMatrix(projection, model);
for (float f : projection) {
pointer.putFloat(f);
}
pointer.rewind();
// Make sure the uniform buffer is uploaded
gl4.glUnmapBuffer(GL_UNIFORM_BUFFER);
}
gl4.glViewportIndexedf(0, 0, 0, windowSize.x, windowSize.y);
float[] depthValue = {1.0f};
gl4.glClearBufferfv(GL_DEPTH, 0, depthValue, 0);
gl4.glClearBufferfv(GL_COLOR, 0, new float[]{1.0f, 0.5f, 0.0f, 1.0f}, 0);
gl4.glBindProgramPipeline(pipelineName[0]);
gl4.glActiveTexture(GL_TEXTURE0);
gl4.glBindTexture(GL_TEXTURE_2D, textureName[Texture.DIFFUSE.ordinal()]);
gl4.glBindImageTexture(Semantic.Image.PICKING, textureName[Texture.PICKING.ordinal()],
0, false, 0, GL_WRITE_ONLY, GL_R32F);
gl4.glBindVertexArray(vertexArrayName[0]);
gl4.glBindBufferBase(GL_UNIFORM_BUFFER, Semantic.Uniform.TRANSFORM0, bufferName[Buffer.TRANSFORM.ordinal()]);
gl4.glDrawElementsInstancedBaseVertexBaseInstance(GL_TRIANGLES, elementCount, GL_UNSIGNED_SHORT, 0, 5, 0, 0);
gl4.glBindBuffer(GL_ARRAY_BUFFER, bufferName[Buffer.PICKING.ordinal()]);
ByteBuffer pointer = gl4.glMapBufferRange(GL_ARRAY_BUFFER, 0, Float.BYTES, GL_MAP_READ_BIT);
float depth = pointer.getFloat();
gl4.glUnmapBuffer(GL_ARRAY_BUFFER);
System.out.printf("Depth: %2.3f\n", depth);
return true;
}
在我們的頂點着色器,爲每個頂點執行,我們:
Semantic
未來一致,如std140和column_mayor(沒用,爲矩陣初始值)Transform
均勻緩衝器Block
塊輸出texCoord
內部和內部gl_Position
我們在裁剪空間位置頂點。傳入的position
頂點位於模型空間 - > *模型矩陣=世界空間中的頂點,*視圖/相機矩陣=相機/視圖空間中的頂點,*投影矩陣=在剪輯空間中的頂點。代碼:
#version 420 core
#define POSITION 0
#define COLOR 3
#define TEXCOORD 4
#define TRANSFORM0 1
precision highp float;
precision highp int;
layout(std140, column_major) uniform;
layout(binding = TRANSFORM0) uniform Transform
{
mat4 mvp;
} transform;
layout(location = POSITION) in vec3 position;
layout(location = TEXCOORD) in vec2 texCoord;
out gl_PerVertex
{
vec4 gl_Position;
};
out Block
{
vec2 texCoord;
} outBlock;
void main()
{
outBlock.texCoord = texCoord;
gl_Position = transform.mvp * vec4(position, 1.0);
}
可能有是頂點着色器之後的其他階段,比如鑲嵌控制/評價和幾何形狀,但它們不是必需的。 最後階段是片段着色器,每個片段/像素執行一次,啓動類似的,那麼我們:
diffuse
上binding 0
,與我們glActiveTexture(GL_TEXTURE0)
的render
和ImageBuffer的picking
內部匹配,我們將拯救我們的深度由binding 1
鑑定,符合我們的Semantic.Image.PICKING
裏面我們render.glBindImageTexture
Block
塊保持的紋理座標color
gl_FragCoord
(內置函數)對應於拾取座標pickingCoord
,保存ImageBuffer的depth
內的當前z值gl_FragCoord.z
並將輸出color
設置爲vec4(1, 0, 1, 1)
,否則我們將其設置爲等於texture(diffuse, inBlock.texCoord.st)
的漫反射紋理。 st
是stqp選擇的一部分,是xywz或rgba的同義詞。代碼:
#version 420 core
#define FRAG_COLOR 0
precision highp float;
precision highp int;
layout(std140, column_major) uniform;
in vec4 gl_FragCoord;
layout(binding = 0) uniform sampler2D diffuse;
layout(binding = 1, r32f) writeonly uniform imageBuffer depth;
uvec2 pickingCoord = uvec2(320, 240);
in Block
{
vec2 texCoord;
} inBlock;
layout(location = FRAG_COLOR, index = 0) out vec4 color;
void main()
{
if(all(equal(pickingCoord, uvec2(gl_FragCoord.xy))))
{
imageStore(depth, 0, vec4(gl_FragCoord.z, 0, 0, 0));
color = vec4(1, 0, 1, 1);
}
else
color = texture(diffuse, inBlock.texCoord.st);
}
終於在end
我們清理我們所有的OpenGL資源:
@Override
protected boolean end(GL gl) {
GL4 gl4 = (GL4) gl;
gl4.glDeleteProgramPipelines(1, pipelineName, 0);
gl4.glDeleteProgram(programName);
gl4.glDeleteBuffers(Buffer.MAX.ordinal(), bufferName, 0);
gl4.glDeleteTextures(Texture.MAX.ordinal(), textureName, 0);
gl4.glDeleteVertexArrays(1, vertexArrayName, 0);
return true;
}
的OpenGL不知道 「對象」 任何東西。它只是呈現三角形。 –
你可以用'glReadPixels'做很多工作,但這不是魔術。 –
嗨,你可以使用後臺緩衝區中的獨特顏色渲染每個不同的元素,甚至無需交換緩衝區,然後通過函數Dietrich建議 – elect