зеркало из https://github.com/AvaloniaUI/angle.git
384 строки
14 KiB
C++
384 строки
14 KiB
C++
//
|
|
// Copyright 2017 The ANGLE Project Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
//
|
|
// This sample shows basic usage of the GL_OVR_multiview2 extension.
|
|
|
|
#include "SampleApplication.h"
|
|
|
|
#include "util/geometry_utils.h"
|
|
#include "util/shader_utils.h"
|
|
|
|
#include <iostream>
|
|
|
|
namespace
|
|
{
|
|
|
|
void FillTranslationMatrix(float xOffset, float yOffset, float zOffset, float *matrix)
|
|
{
|
|
matrix[0] = 1.0f;
|
|
matrix[1] = 0.0f;
|
|
matrix[2] = 0.0f;
|
|
matrix[3] = xOffset;
|
|
|
|
matrix[4] = 0.0f;
|
|
matrix[5] = 1.0f;
|
|
matrix[6] = 0.0f;
|
|
matrix[7] = yOffset;
|
|
|
|
matrix[8] = 0.0f;
|
|
matrix[9] = 0.0f;
|
|
matrix[10] = 1.0f;
|
|
matrix[11] = zOffset;
|
|
|
|
matrix[12] = 0.0f;
|
|
matrix[13] = 0.0f;
|
|
matrix[14] = 0.0f;
|
|
matrix[15] = 1.0f;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
class MultiviewSample : public SampleApplication
|
|
{
|
|
public:
|
|
MultiviewSample(int argc, char **argv)
|
|
: SampleApplication("Multiview", argc, argv, 3, 0),
|
|
mMultiviewProgram(0),
|
|
mMultiviewPersperiveUniformLoc(-1),
|
|
mMultiviewLeftEyeCameraUniformLoc(-1),
|
|
mMultiviewRightEyeCameraUniformLoc(-1),
|
|
mMultiviewTranslationUniformLoc(-1),
|
|
mMultiviewFBO(0),
|
|
mColorTexture(0),
|
|
mDepthTexture(0),
|
|
mQuadVAO(0),
|
|
mQuadVBO(0),
|
|
mCubeVAO(0),
|
|
mCubePosVBO(0),
|
|
mCubeNormalVBO(0),
|
|
mCubeIBO(0),
|
|
mCombineProgram(0)
|
|
{}
|
|
|
|
bool initialize() override
|
|
{
|
|
// Check whether the GL_OVR_multiview(2) extension is supported. If not, abort
|
|
// initialization.
|
|
const char *allExtensions = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));
|
|
const std::string paddedExtensions = std::string(" ") + allExtensions + std::string(" ");
|
|
if ((paddedExtensions.find(std::string(" GL_OVR_multiview2 ")) == std::string::npos) &&
|
|
(paddedExtensions.find(std::string(" GL_OVR_multiview ")) == std::string::npos))
|
|
{
|
|
std::cout << "GL_OVR_multiview(2) is not available." << std::endl;
|
|
return false;
|
|
}
|
|
|
|
// A view covers horizontally half of the screen.
|
|
int viewWidth = getWindow()->getWidth() / 2;
|
|
int viewHeight = getWindow()->getHeight();
|
|
|
|
// Create color and depth texture arrays with two layers to which we render each view.
|
|
glGenTextures(1, &mColorTexture);
|
|
glBindTexture(GL_TEXTURE_2D_ARRAY, mColorTexture);
|
|
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, viewWidth, viewHeight, 2, 0, GL_RGBA,
|
|
GL_UNSIGNED_BYTE, nullptr);
|
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
glGenTextures(1, &mDepthTexture);
|
|
glBindTexture(GL_TEXTURE_2D_ARRAY, mDepthTexture);
|
|
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT32F, viewWidth, viewHeight, 2, 0,
|
|
GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
|
|
|
|
// Generate multiview framebuffer for layered rendering.
|
|
glGenFramebuffers(1, &mMultiviewFBO);
|
|
glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
|
|
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mColorTexture, 0, 0,
|
|
2);
|
|
glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, mDepthTexture, 0, 0,
|
|
2);
|
|
GLenum drawBuffer = GL_COLOR_ATTACHMENT0;
|
|
glDrawBuffers(1, &drawBuffer);
|
|
|
|
// Check that the framebuffer is complete. Abort initialization otherwise.
|
|
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Create multiview program and query the uniform locations.
|
|
// The program has two code paths based on the gl_ViewID_OVR attribute which tells us which
|
|
// view is currently being rendered to. Based on it we decide which eye's camera matrix to
|
|
// use.
|
|
constexpr char kMultiviewVS[] =
|
|
"#version 300 es\n"
|
|
"#extension GL_OVR_multiview2 : require\n"
|
|
"layout(num_views = 2) in;\n"
|
|
"layout(location=0) in vec3 posIn;\n"
|
|
"layout(location=1) in vec3 normalIn;\n"
|
|
"uniform mat4 uPerspective;\n"
|
|
"uniform mat4 uCameraLeftEye;\n"
|
|
"uniform mat4 uCameraRightEye;\n"
|
|
"uniform mat4 uTranslation;\n"
|
|
"out vec3 oNormal;\n"
|
|
"void main()\n"
|
|
"{\n"
|
|
" vec4 p = uTranslation * vec4(posIn,1.);\n"
|
|
" if (gl_ViewID_OVR == 0u) {\n"
|
|
" p = uCameraLeftEye * p;\n"
|
|
" } else {\n"
|
|
" p = uCameraRightEye * p;\n"
|
|
" }\n"
|
|
" oNormal = normalIn;\n"
|
|
" gl_Position = uPerspective * p;\n"
|
|
"}\n";
|
|
|
|
constexpr char kMultiviewFS[] =
|
|
"#version 300 es\n"
|
|
"#extension GL_OVR_multiview2 : require\n"
|
|
"precision mediump float;\n"
|
|
"out vec4 color;\n"
|
|
"in vec3 oNormal;\n"
|
|
"void main()\n"
|
|
"{\n"
|
|
" vec3 col = 0.5 * oNormal + vec3(0.5);\n"
|
|
" color = vec4(col, 1.);\n"
|
|
"}\n";
|
|
|
|
mMultiviewProgram = CompileProgram(kMultiviewVS, kMultiviewFS);
|
|
if (!mMultiviewProgram)
|
|
{
|
|
return false;
|
|
}
|
|
mMultiviewPersperiveUniformLoc = glGetUniformLocation(mMultiviewProgram, "uPerspective");
|
|
mMultiviewLeftEyeCameraUniformLoc =
|
|
glGetUniformLocation(mMultiviewProgram, "uCameraLeftEye");
|
|
mMultiviewRightEyeCameraUniformLoc =
|
|
glGetUniformLocation(mMultiviewProgram, "uCameraRightEye");
|
|
mMultiviewTranslationUniformLoc = glGetUniformLocation(mMultiviewProgram, "uTranslation");
|
|
|
|
// Create a normal program to combine both layers of the color array texture.
|
|
constexpr char kCombineVS[] =
|
|
"#version 300 es\n"
|
|
"in vec2 vIn;\n"
|
|
"out vec2 uv;\n"
|
|
"void main()\n"
|
|
"{\n"
|
|
" gl_Position = vec4(vIn, 0., 1.);\n"
|
|
" uv = vIn * .5 + vec2(.5);\n"
|
|
"}\n";
|
|
|
|
constexpr char kCombineFS[] =
|
|
"#version 300 es\n"
|
|
"precision mediump float;\n"
|
|
"precision mediump sampler2DArray;\n"
|
|
"uniform sampler2DArray uMultiviewTex;\n"
|
|
"in vec2 uv;\n"
|
|
"out vec4 color;\n"
|
|
"void main()\n"
|
|
"{\n"
|
|
" float scaledX = 2.0 * uv.x;\n"
|
|
" float layer = floor(scaledX);\n"
|
|
" vec2 adjustedUV = vec2(fract(scaledX), uv.y);\n"
|
|
" vec3 texColor = texture(uMultiviewTex, vec3(adjustedUV, layer)).rgb;\n"
|
|
" color = vec4(texColor, 1.);\n"
|
|
"}\n";
|
|
|
|
mCombineProgram = CompileProgram(kCombineVS, kCombineFS);
|
|
if (!mCombineProgram)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Generate a quad which covers the whole screen.
|
|
glGenVertexArrays(1, &mQuadVAO);
|
|
glBindVertexArray(mQuadVAO);
|
|
|
|
glGenBuffers(1, &mQuadVBO);
|
|
glBindBuffer(GL_ARRAY_BUFFER, mQuadVBO);
|
|
const float kQuadPositionData[] = {1.f, -1.f, 1.f, 1.f, -1.f, -1.f, -1.f, 1.f};
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 8, kQuadPositionData, GL_STATIC_DRAW);
|
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
|
|
glEnableVertexAttribArray(0);
|
|
glBindVertexArray(0);
|
|
|
|
// Generate a cube.
|
|
GenerateCubeGeometry(1.0f, &mCube);
|
|
glGenVertexArrays(1, &mCubeVAO);
|
|
glBindVertexArray(mCubeVAO);
|
|
|
|
glGenBuffers(1, &mCubePosVBO);
|
|
glBindBuffer(GL_ARRAY_BUFFER, mCubePosVBO);
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(angle::Vector3) * mCube.positions.size(),
|
|
mCube.positions.data(), GL_STATIC_DRAW);
|
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
|
|
glEnableVertexAttribArray(0);
|
|
|
|
glGenBuffers(1, &mCubeNormalVBO);
|
|
glBindBuffer(GL_ARRAY_BUFFER, mCubeNormalVBO);
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(angle::Vector3) * mCube.normals.size(),
|
|
mCube.normals.data(), GL_STATIC_DRAW);
|
|
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
|
|
glEnableVertexAttribArray(1);
|
|
|
|
glGenBuffers(1, &mCubeIBO);
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mCubeIBO);
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * mCube.indices.size(),
|
|
mCube.indices.data(), GL_STATIC_DRAW);
|
|
|
|
glBindVertexArray(0);
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
|
|
|
return true;
|
|
}
|
|
|
|
void destroy() override
|
|
{
|
|
glDeleteProgram(mMultiviewProgram);
|
|
glDeleteFramebuffers(1, &mMultiviewFBO);
|
|
glDeleteTextures(1, &mColorTexture);
|
|
glDeleteTextures(1, &mDepthTexture);
|
|
glDeleteVertexArrays(1, &mQuadVAO);
|
|
glDeleteBuffers(1, &mQuadVBO);
|
|
glDeleteVertexArrays(1, &mCubeVAO);
|
|
glDeleteBuffers(1, &mQuadVBO);
|
|
glDeleteBuffers(1, &mCubePosVBO);
|
|
glDeleteBuffers(1, &mCubeNormalVBO);
|
|
glDeleteBuffers(1, &mCubeIBO);
|
|
glDeleteProgram(mCombineProgram);
|
|
}
|
|
|
|
void draw() override
|
|
{
|
|
// Draw to multiview fbo.
|
|
{
|
|
// Generate the perspective projection matrix.
|
|
const int viewWidth = getWindow()->getWidth() / 2;
|
|
const int viewHeight = getWindow()->getHeight();
|
|
const float kFOV = 90.f;
|
|
const float kNear = 1.0f;
|
|
const float kFar = 100.0f;
|
|
const float kPlaneDifference = kFar - kNear;
|
|
const float kXYScale = 1.f / (tanf(kFOV / 2.0f));
|
|
const float kAspectRatio = static_cast<float>(viewWidth) / viewHeight;
|
|
float kPerspectiveProjectionMatrix[16];
|
|
kPerspectiveProjectionMatrix[0] = kXYScale / kAspectRatio;
|
|
kPerspectiveProjectionMatrix[1] = .0f;
|
|
kPerspectiveProjectionMatrix[2] = .0f;
|
|
kPerspectiveProjectionMatrix[3] = .0f;
|
|
|
|
kPerspectiveProjectionMatrix[4] = .0f;
|
|
kPerspectiveProjectionMatrix[5] = kXYScale;
|
|
kPerspectiveProjectionMatrix[6] = .0f;
|
|
kPerspectiveProjectionMatrix[7] = .0f;
|
|
|
|
kPerspectiveProjectionMatrix[8] = .0f;
|
|
kPerspectiveProjectionMatrix[9] = .0;
|
|
kPerspectiveProjectionMatrix[10] = -kFar / kPlaneDifference;
|
|
kPerspectiveProjectionMatrix[11] = -1.f;
|
|
|
|
kPerspectiveProjectionMatrix[12] = .0f;
|
|
kPerspectiveProjectionMatrix[13] = .0;
|
|
kPerspectiveProjectionMatrix[14] = -kFar * kNear / kPlaneDifference;
|
|
kPerspectiveProjectionMatrix[15] = .0;
|
|
|
|
// Generate the camera matrices for the left and right eye.
|
|
const float kXOffset = 1.5f;
|
|
const float kYOffset = 1.5f;
|
|
const float kZOffset = 5.0f;
|
|
float kLeftCameraMatrix[16];
|
|
FillTranslationMatrix(kXOffset, -kYOffset, -kZOffset, kLeftCameraMatrix);
|
|
float kRightCameraMatrix[16];
|
|
FillTranslationMatrix(-kXOffset, -kYOffset, -kZOffset, kRightCameraMatrix);
|
|
|
|
// Bind and clear the multiview framebuffer.
|
|
glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
|
|
glClearColor(0, 0, 0, 1);
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
// Set the viewport to be the size as one of the views.
|
|
glViewport(0, 0, viewWidth, viewHeight);
|
|
|
|
// Bind multiview program and set matrices.
|
|
glUseProgram(mMultiviewProgram);
|
|
glUniformMatrix4fv(mMultiviewPersperiveUniformLoc, 1, GL_TRUE,
|
|
kPerspectiveProjectionMatrix);
|
|
glUniformMatrix4fv(mMultiviewLeftEyeCameraUniformLoc, 1, GL_TRUE, kLeftCameraMatrix);
|
|
glUniformMatrix4fv(mMultiviewRightEyeCameraUniformLoc, 1, GL_TRUE, kRightCameraMatrix);
|
|
|
|
glBindVertexArray(mCubeVAO);
|
|
|
|
// Draw first cube.
|
|
float kTranslationMatrix[16];
|
|
FillTranslationMatrix(0.0f, 0.0f, 0.0f, kTranslationMatrix);
|
|
glUniformMatrix4fv(mMultiviewTranslationUniformLoc, 1, GL_TRUE, kTranslationMatrix);
|
|
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(mCube.indices.size()),
|
|
GL_UNSIGNED_SHORT, nullptr);
|
|
|
|
// Draw second cube.
|
|
FillTranslationMatrix(1.0f, 1.0f, -2.0f, kTranslationMatrix);
|
|
glUniformMatrix4fv(mMultiviewTranslationUniformLoc, 1, GL_TRUE, kTranslationMatrix);
|
|
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(mCube.indices.size()),
|
|
GL_UNSIGNED_SHORT, nullptr);
|
|
|
|
glBindVertexArray(0);
|
|
}
|
|
|
|
// Combine both views.
|
|
{
|
|
// Bind the default framebuffer object and clear.
|
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
// Set the viewport to cover the whole screen.
|
|
glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
|
|
|
|
glUseProgram(mCombineProgram);
|
|
|
|
// Bind the 2D array texture to be used as a sampler.
|
|
glUniform1i(glGetUniformLocation(mCombineProgram, "uMultiviewTex"), 0);
|
|
glBindTexture(GL_TEXTURE_2D_ARRAY, mMultiviewFBO);
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
// Draw a quad which covers the whole screen. Layer and texture coordinates are
|
|
// calculated in the vertex shader based on the UV coordinates of the quad.
|
|
glBindVertexArray(mQuadVAO);
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
|
glBindVertexArray(0);
|
|
}
|
|
}
|
|
|
|
private:
|
|
GLuint mMultiviewProgram;
|
|
GLint mMultiviewPersperiveUniformLoc;
|
|
GLint mMultiviewLeftEyeCameraUniformLoc;
|
|
GLint mMultiviewRightEyeCameraUniformLoc;
|
|
GLint mMultiviewTranslationUniformLoc;
|
|
|
|
GLuint mMultiviewFBO;
|
|
GLuint mColorTexture;
|
|
GLuint mDepthTexture;
|
|
|
|
GLuint mQuadVAO;
|
|
GLuint mQuadVBO;
|
|
|
|
CubeGeometry mCube;
|
|
GLuint mCubeVAO;
|
|
GLuint mCubePosVBO;
|
|
GLuint mCubeNormalVBO;
|
|
GLuint mCubeIBO;
|
|
|
|
GLuint mCombineProgram;
|
|
};
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
MultiviewSample app(argc, argv);
|
|
return app.run();
|
|
}
|