Support reversed Z rendering and float32 offscreen depth buffer

Combined, both options greatly improve camera depth accuracy compared to
OpenGL default Z mapping and int24 depth buffer.

Requires GL_ARB_clip_control and ARB_depth_buffer_float extensions
This commit is contained in:
Levi Burner
2023-06-14 14:42:42 -04:00
parent e1549376f6
commit fc7b212369
10 changed files with 193 additions and 17 deletions
+15
View File
@@ -39,6 +39,15 @@ typedef enum mjtFramebuffer_ { // OpenGL framebuffer option
mjFB_OFFSCREEN // offscreen buffer mjFB_OFFSCREEN // offscreen buffer
} mjtFramebuffer; } mjtFramebuffer;
typedef enum mjtDepthMapping_ { // OpenGL depth buffer mapping (from znear to zfar)
mjDB_NEGONETOONE = 0, // Negative one to one (OpenGL default)
mjDB_ONETOZERO // Reversed Z buffer (decreases numerical error)
} mjtDepthMapping;
typedef enum mjtDepthPrecision_ { // OpenGL depth buffer precision
mjDB_INT24 = 0, // 24 bit integer buffer (OpenGL default)
mjDB_FLOAT32 // 32 bit float buffer
} mjtDepthPrecision;
typedef enum mjtFontScale_ { // font scale, used at context creation typedef enum mjtFontScale_ { // font scale, used at context creation
mjFONTSCALE_50 = 50, // 50% scale, suitable for low-res rendering mjFONTSCALE_50 = 50, // 50% scale, suitable for low-res rendering
@@ -151,6 +160,12 @@ struct mjrContext_ { // custom OpenGL context
// pixel output format // pixel output format
int readPixelFormat; // default color pixel format for mjr_readPixels int readPixelFormat; // default color pixel format for mjr_readPixels
// depth buffer mode
int depthMapping; // depth buffer mapping from [znear zfar] to normalized device coordinates: mjDB_NEGONETOONE or mjDB_ONETOZERO
// depth buffer precision
int depthPrecision; // depth buffer precision: mjDB_INT24 or mjDB_FLOAT32
}; };
typedef struct mjrContext_ mjrContext; typedef struct mjrContext_ mjrContext;
+18
View File
@@ -621,6 +621,24 @@ ENUMS: Mapping[str, EnumDecl] = dict([
('mjFB_OFFSCREEN', 1), ('mjFB_OFFSCREEN', 1),
]), ]),
)), )),
('mjtDepthMapping',
EnumDecl(
name='mjtDepthMapping',
declname='enum mjtDepthMapping_',
values=dict([
('mjDB_NEGONETOONE', 0),
('mjDB_ONETOZERO', 1),
]),
)),
('mjtDepthPrecision',
EnumDecl(
name='mjtDepthPrecision',
declname='enum mjtDepthPrecision_',
values=dict([
('mjDB_INT24', 0),
('mjDB_FLOAT32', 1),
]),
)),
('mjtFontScale', ('mjtFontScale',
EnumDecl( EnumDecl(
name='mjtFontScale', name='mjtFontScale',
+10
View File
@@ -7126,6 +7126,16 @@ STRUCTS: Mapping[str, StructDecl] = dict([
type=ValueType(name='int'), type=ValueType(name='int'),
doc='default color pixel format for mjr_readPixels', doc='default color pixel format for mjr_readPixels',
), ),
StructFieldDecl(
name='depthMapping',
type=ValueType(name='int'),
doc='depth buffer mapping from [znear zfar] to normalized device coordinates: mjDB_NEGONETOONE or mjDB_ONETOZERO', # pylint: disable=line-too-long
),
StructFieldDecl(
name='depthPrecision',
type=ValueType(name='int'),
doc='depth buffer precision: mjDB_INT24 or mjDB_FLOAT32',
),
), ),
)), )),
('mjuiState', ('mjuiState',
+34
View File
@@ -34,6 +34,10 @@ class MjWrapper<raw::MjrContext> : public WrapperBase<raw::MjrContext> {
public: public:
MjWrapper(); MjWrapper();
MjWrapper(const MjModelWrapper& model, int fontscale); MjWrapper(const MjModelWrapper& model, int fontscale);
MjWrapper(const MjModelWrapper& model,
int fontscale,
mjtDepthMapping depthmapping,
mjtDepthPrecision depthprecision);
MjWrapper(const MjWrapper&) = delete; MjWrapper(const MjWrapper&) = delete;
MjWrapper(MjWrapper&&) = default; MjWrapper(MjWrapper&&) = default;
~MjWrapper() = default; ~MjWrapper() = default;
@@ -122,6 +126,35 @@ MjrContextWrapper::MjWrapper(const MjModelWrapper& model, int fontscale)
X_SKIN(skinfaceVBO), X_SKIN(skinfaceVBO),
X(charWidth), X(charWidth),
X(charWidthBig) {} X(charWidthBig) {}
MjrContextWrapper::MjWrapper(const MjModelWrapper& model,
int fontscale,
mjtDepthMapping depthmapping,
mjtDepthPrecision depthprecision)
: WrapperBase([fontscale, depthmapping, depthprecision](const raw::MjModel* m) {
raw::MjrContext *const ctx = new raw::MjrContext;
mjr_defaultContext(ctx);
ctx->depthMapping = depthmapping;
ctx->depthPrecision = depthprecision;
InterceptMjErrors(mjr_makeContext)(m, ctx, fontscale);
return ctx;
}(model.get()), &MjrContextCapsuleDestructor),
X(fogRGBA),
X(auxWidth),
X(auxHeight),
X(auxSamples),
X(auxFBO),
X(auxFBO_r),
X(auxColor),
X(auxColor_r),
X(textureType),
X(texture),
X_SKIN(skinvertVBO),
X_SKIN(skinnormalVBO),
X_SKIN(skintexcoordVBO),
X_SKIN(skinfaceVBO),
X(charWidth),
X(charWidthBig) {}
#undef X_SKIN #undef X_SKIN
#undef X #undef X
@@ -166,6 +199,7 @@ PYBIND11_MODULE(_render, pymodule) {
py::class_<MjrContextWrapper> mjrContext(pymodule, "MjrContext"); py::class_<MjrContextWrapper> mjrContext(pymodule, "MjrContext");
mjrContext.def(py::init<>()); mjrContext.def(py::init<>());
mjrContext.def(py::init<const MjModelWrapper&, int>()); mjrContext.def(py::init<const MjModelWrapper&, int>());
mjrContext.def(py::init<const MjModelWrapper&, int, mjtDepthMapping, mjtDepthPrecision>());
mjrContext.def( mjrContext.def(
"free", [](MjrContextWrapper& self) { self.Free(); }, "free", [](MjrContextWrapper& self) { self.Free(); },
py::doc("Frees resources in current active OpenGL context, sets struct " py::doc("Frees resources in current active OpenGL context, sets struct "
+1
View File
@@ -27,6 +27,7 @@ void PlatformUIAdapter::FreeMjrContext() {
bool PlatformUIAdapter::RefreshMjrContext(const mjModel* m, int fontscale) { bool PlatformUIAdapter::RefreshMjrContext(const mjModel* m, int fontscale) {
if (m != last_model_ || fontscale != last_fontscale_) { if (m != last_model_ || fontscale != last_fontscale_) {
// con_.depthMapping = mjDB_ONETOZERO;
mjr_makeContext(m, &con_, fontscale); mjr_makeContext(m, &con_, fontscale);
last_model_ = m; last_model_ = m;
last_fontscale_ = fontscale; last_fontscale_ = fontscale;
+15 -3
View File
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// //
// Based on the OpenGL loader generated by glad 0.1.35 on Mon Mar 21 12:42:33 2022. // Based on the OpenGL loader generated by glad 0.1.34 on Thu Jun 22 14:40:03 2023.
// //
// The original generated code is distributed under CC0. // The original generated code is distributed under CC0.
// https://creativecommons.org/publicdomain/zero/1.0/ // https://creativecommons.org/publicdomain/zero/1.0/
@@ -22,6 +22,8 @@
// APIs: gl=1.5 // APIs: gl=1.5
// Profile: compatibility // Profile: compatibility
// Extensions: // Extensions:
// GL_ARB_clip_control,
// GL_ARB_depth_buffer_float,
// GL_ARB_framebuffer_object, // GL_ARB_framebuffer_object,
// GL_ARB_seamless_cube_map, // GL_ARB_seamless_cube_map,
// GL_ARB_vertex_buffer_object, // GL_ARB_vertex_buffer_object,
@@ -32,9 +34,9 @@
// Reproducible: False // Reproducible: False
// //
// Commandline: // Commandline:
// --profile="compatibility" --api="gl=1.5" --generator="c" --spec="gl" --extensions="GL_ARB_framebuffer_object,GL_ARB_seamless_cube_map,GL_ARB_vertex_buffer_object,GL_KHR_debug" // --profile="compatibility" --api="gl=1.5" --generator="c" --spec="gl" --extensions="GL_ARB_clip_control,GL_ARB_depth_buffer_float,GL_ARB_framebuffer_object,GL_ARB_seamless_cube_map,GL_ARB_vertex_buffer_object,GL_KHR_debug"
// Online: // Online:
// https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D1.5&extensions=GL_ARB_framebuffer_object&extensions=GL_ARB_seamless_cube_map&extensions=GL_ARB_vertex_buffer_object&extensions=GL_KHR_debug // https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D1.5&extensions=GL_ARB_clip_control&extensions=GL_ARB_depth_buffer_float&extensions=GL_ARB_framebuffer_object&extensions=GL_ARB_seamless_cube_map&extensions=GL_ARB_vertex_buffer_object&extensions=GL_KHR_debug
#if defined(__GNUC__) && !defined(__clang__) #if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push #pragma GCC diagnostic push
@@ -829,10 +831,13 @@ PFNGLWINDOWPOS3IPROC mjGlad_glWindowPos3i = NULL;
PFNGLWINDOWPOS3IVPROC mjGlad_glWindowPos3iv = NULL; PFNGLWINDOWPOS3IVPROC mjGlad_glWindowPos3iv = NULL;
PFNGLWINDOWPOS3SPROC mjGlad_glWindowPos3s = NULL; PFNGLWINDOWPOS3SPROC mjGlad_glWindowPos3s = NULL;
PFNGLWINDOWPOS3SVPROC mjGlad_glWindowPos3sv = NULL; PFNGLWINDOWPOS3SVPROC mjGlad_glWindowPos3sv = NULL;
int mjGLAD_GL_ARB_clip_control = 0;
int mjGLAD_GL_ARB_depth_buffer_float = 0;
int mjGLAD_GL_ARB_framebuffer_object = 0; int mjGLAD_GL_ARB_framebuffer_object = 0;
int mjGLAD_GL_ARB_seamless_cube_map = 0; int mjGLAD_GL_ARB_seamless_cube_map = 0;
int mjGLAD_GL_ARB_vertex_buffer_object = 0; int mjGLAD_GL_ARB_vertex_buffer_object = 0;
int mjGLAD_GL_KHR_debug = 0; int mjGLAD_GL_KHR_debug = 0;
PFNGLCLIPCONTROLPROC mjGlad_glClipControl = NULL;
PFNGLISRENDERBUFFERPROC mjGlad_glIsRenderbuffer = NULL; PFNGLISRENDERBUFFERPROC mjGlad_glIsRenderbuffer = NULL;
PFNGLBINDRENDERBUFFERPROC mjGlad_glBindRenderbuffer = NULL; PFNGLBINDRENDERBUFFERPROC mjGlad_glBindRenderbuffer = NULL;
PFNGLDELETERENDERBUFFERSPROC mjGlad_glDeleteRenderbuffers = NULL; PFNGLDELETERENDERBUFFERSPROC mjGlad_glDeleteRenderbuffers = NULL;
@@ -1355,6 +1360,10 @@ static void mjGlad_load_GL_VERSION_1_5(GLADloadproc load) {
mjGlad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)load("glGetBufferParameteriv"); mjGlad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)load("glGetBufferParameteriv");
mjGlad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC)load("glGetBufferPointerv"); mjGlad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC)load("glGetBufferPointerv");
} }
static void mjGlad_load_GL_ARB_clip_control(GLADloadproc load) {
if(!mjGLAD_GL_ARB_clip_control) return;
mjGlad_glClipControl = (PFNGLCLIPCONTROLPROC)load("glClipControl");
}
static void mjGlad_load_GL_ARB_framebuffer_object(GLADloadproc load) { static void mjGlad_load_GL_ARB_framebuffer_object(GLADloadproc load) {
if(!mjGLAD_GL_ARB_framebuffer_object) return; if(!mjGLAD_GL_ARB_framebuffer_object) return;
mjGlad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)load("glIsRenderbuffer"); mjGlad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)load("glIsRenderbuffer");
@@ -1419,6 +1428,8 @@ static void mjGlad_load_GL_KHR_debug(GLADloadproc load) {
} }
static int mjGlad_find_extensionsGL(void) { static int mjGlad_find_extensionsGL(void) {
if (!mjGlad_get_exts()) return 0; if (!mjGlad_get_exts()) return 0;
mjGLAD_GL_ARB_clip_control = mjGlad_has_ext("GL_ARB_clip_control");
mjGLAD_GL_ARB_depth_buffer_float = mjGlad_has_ext("GL_ARB_depth_buffer_float");
mjGLAD_GL_ARB_framebuffer_object = mjGlad_has_ext("GL_ARB_framebuffer_object"); mjGLAD_GL_ARB_framebuffer_object = mjGlad_has_ext("GL_ARB_framebuffer_object");
mjGLAD_GL_ARB_seamless_cube_map = mjGlad_has_ext("GL_ARB_seamless_cube_map"); mjGLAD_GL_ARB_seamless_cube_map = mjGlad_has_ext("GL_ARB_seamless_cube_map");
mjGLAD_GL_ARB_vertex_buffer_object = mjGlad_has_ext("GL_ARB_vertex_buffer_object"); mjGLAD_GL_ARB_vertex_buffer_object = mjGlad_has_ext("GL_ARB_vertex_buffer_object");
@@ -1491,6 +1502,7 @@ int mjGladLoadGLUnsafe(void) {
mjGlad_load_GL_VERSION_1_5(mjGlad_get_proc); mjGlad_load_GL_VERSION_1_5(mjGlad_get_proc);
if (!mjGlad_find_extensionsGL()) return 0; if (!mjGlad_find_extensionsGL()) return 0;
mjGlad_load_GL_ARB_clip_control(mjGlad_get_proc);
mjGlad_load_GL_ARB_framebuffer_object(mjGlad_get_proc); mjGlad_load_GL_ARB_framebuffer_object(mjGlad_get_proc);
mjGlad_load_GL_ARB_vertex_buffer_object(mjGlad_get_proc); mjGlad_load_GL_ARB_vertex_buffer_object(mjGlad_get_proc);
mjGlad_load_GL_KHR_debug(mjGlad_get_proc); mjGlad_load_GL_KHR_debug(mjGlad_get_proc);
+25 -3
View File
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// //
// Based on the OpenGL loader generated by glad 0.1.35 on Mon Mar 21 12:42:33 2022. // Based on the OpenGL loader generated by glad 0.1.34 on Thu Jun 22 14:40:03 2023.
// //
// The original generated code is distributed under CC0. // The original generated code is distributed under CC0.
// https://creativecommons.org/publicdomain/zero/1.0/ // https://creativecommons.org/publicdomain/zero/1.0/
@@ -22,6 +22,8 @@
// APIs: gl=1.5 // APIs: gl=1.5
// Profile: compatibility // Profile: compatibility
// Extensions: // Extensions:
// GL_ARB_clip_control,
// GL_ARB_depth_buffer_float,
// GL_ARB_framebuffer_object, // GL_ARB_framebuffer_object,
// GL_ARB_seamless_cube_map, // GL_ARB_seamless_cube_map,
// GL_ARB_vertex_buffer_object, // GL_ARB_vertex_buffer_object,
@@ -32,9 +34,9 @@
// Reproducible: False // Reproducible: False
// //
// Commandline: // Commandline:
// --profile="compatibility" --api="gl=1.5" --generator="c" --spec="gl" --extensions="GL_ARB_framebuffer_object,GL_ARB_seamless_cube_map,GL_ARB_vertex_buffer_object,GL_KHR_debug" // --profile="compatibility" --api="gl=1.5" --generator="c" --spec="gl" --extensions="GL_ARB_clip_control,GL_ARB_depth_buffer_float,GL_ARB_framebuffer_object,GL_ARB_seamless_cube_map,GL_ARB_vertex_buffer_object,GL_KHR_debug"
// Online: // Online:
// https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D1.5&extensions=GL_ARB_framebuffer_object&extensions=GL_ARB_seamless_cube_map&extensions=GL_ARB_vertex_buffer_object&extensions=GL_KHR_debug // https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D1.5&extensions=GL_ARB_clip_control&extensions=GL_ARB_depth_buffer_float&extensions=GL_ARB_framebuffer_object&extensions=GL_ARB_seamless_cube_map&extensions=GL_ARB_vertex_buffer_object&extensions=GL_KHR_debug
#ifndef MUJOCO_SRC_RENDER_GLAD_GLAD_H_ #ifndef MUJOCO_SRC_RENDER_GLAD_GLAD_H_
#define MUJOCO_SRC_RENDER_GLAD_GLAD_H_ #define MUJOCO_SRC_RENDER_GLAD_GLAD_H_
@@ -2304,6 +2306,15 @@ typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC)(GLenum target, GLenum pname,
GLAPI PFNGLGETBUFFERPOINTERVPROC mjGlad_glGetBufferPointerv; GLAPI PFNGLGETBUFFERPOINTERVPROC mjGlad_glGetBufferPointerv;
#define glGetBufferPointerv mjGlad_glGetBufferPointerv #define glGetBufferPointerv mjGlad_glGetBufferPointerv
#endif #endif
#define GL_LOWER_LEFT 0x8CA1
#define GL_UPPER_LEFT 0x8CA2
#define GL_NEGATIVE_ONE_TO_ONE 0x935E
#define GL_ZERO_TO_ONE 0x935F
#define GL_CLIP_ORIGIN 0x935C
#define GL_CLIP_DEPTH_MODE 0x935D
#define GL_DEPTH_COMPONENT32F 0x8CAC
#define GL_DEPTH32F_STENCIL8 0x8CAD
#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD
#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 #define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 #define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210
#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 #define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211
@@ -2487,6 +2498,17 @@ GLAPI PFNGLGETBUFFERPOINTERVPROC mjGlad_glGetBufferPointerv;
#define GL_STACK_OVERFLOW_KHR 0x0503 #define GL_STACK_OVERFLOW_KHR 0x0503
#define GL_STACK_UNDERFLOW_KHR 0x0504 #define GL_STACK_UNDERFLOW_KHR 0x0504
#define GL_DISPLAY_LIST 0x82E7 #define GL_DISPLAY_LIST 0x82E7
#ifndef GL_ARB_clip_control
#define GL_ARB_clip_control 1
GLAPI int mjGLAD_GL_ARB_clip_control;
typedef void (APIENTRYP PFNGLCLIPCONTROLPROC)(GLenum origin, GLenum depth);
GLAPI PFNGLCLIPCONTROLPROC mjGlad_glClipControl;
#define glClipControl mjGlad_glClipControl
#endif
#ifndef GL_ARB_depth_buffer_float
#define GL_ARB_depth_buffer_float 1
GLAPI int mjGLAD_GL_ARB_depth_buffer_float;
#endif
#ifndef GL_ARB_framebuffer_object #ifndef GL_ARB_framebuffer_object
#define GL_ARB_framebuffer_object 1 #define GL_ARB_framebuffer_object 1
GLAPI int mjGLAD_GL_ARB_framebuffer_object; GLAPI int mjGLAD_GL_ARB_framebuffer_object;
+28 -8
View File
@@ -1062,7 +1062,11 @@ static void makeShadow(const mjModel* m, mjrContext* con) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); if (con->depthMapping == mjDB_ONETOZERO) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_GEQUAL);
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
}
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY); glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
@@ -1121,16 +1125,17 @@ static void makeOff(mjrContext* con) {
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, con->offColor); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, con->offColor);
// create depth and stencil buffer // create depth and stencil buffer
GLenum depth_buffer_format = con->depthPrecision == mjDB_FLOAT32 ? GL_DEPTH32F_STENCIL8 : GL_DEPTH24_STENCIL8;
glGenRenderbuffers(1, &con->offDepthStencil); glGenRenderbuffers(1, &con->offDepthStencil);
if (!con->offDepthStencil) { if (!con->offDepthStencil) {
mju_error("Could not allocate offscreen depth and stencil buffer"); mju_error("Could not allocate offscreen depth and stencil buffer");
} }
glBindRenderbuffer(GL_RENDERBUFFER, con->offDepthStencil); glBindRenderbuffer(GL_RENDERBUFFER, con->offDepthStencil);
if (con->offSamples) { if (con->offSamples) {
glRenderbufferStorageMultisample(GL_RENDERBUFFER, con->offSamples, GL_DEPTH24_STENCIL8, glRenderbufferStorageMultisample(GL_RENDERBUFFER, con->offSamples, depth_buffer_format,
con->offWidth, con->offHeight); con->offWidth, con->offHeight);
} else { } else {
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, con->offWidth, con->offHeight); glRenderbufferStorage(GL_RENDERBUFFER, depth_buffer_format, con->offWidth, con->offHeight);
} }
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, con->offDepthStencil); GL_RENDERBUFFER, con->offDepthStencil);
@@ -1169,7 +1174,7 @@ static void makeOff(mjrContext* con) {
mju_error("Could not allocate offscreen depth and stencil buffer_r"); mju_error("Could not allocate offscreen depth and stencil buffer_r");
} }
glBindRenderbuffer(GL_RENDERBUFFER, con->offDepthStencil_r); glBindRenderbuffer(GL_RENDERBUFFER, con->offDepthStencil_r);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, con->offWidth, con->offHeight); glRenderbufferStorage(GL_RENDERBUFFER, depth_buffer_format, con->offWidth, con->offHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, con->offDepthStencil_r); GL_RENDERBUFFER, con->offDepthStencil_r);
@@ -1489,6 +1494,12 @@ void mjr_makeContext_offSize(const mjModel* m, mjrContext* con, int fontscale,
if (!mjGLAD_GL_ARB_vertex_buffer_object) { if (!mjGLAD_GL_ARB_vertex_buffer_object) {
mju_error("OpenGL ARB_vertex_buffer_object required"); mju_error("OpenGL ARB_vertex_buffer_object required");
} }
if (!mjGLAD_GL_ARB_clip_control) {
mju_error("OpenGL ARB_clip_control required");
}
if (!mjGLAD_GL_ARB_depth_buffer_float) {
mju_error("OpenGL ARB_depth_buffer_float required");
}
con->glInitialized = 1; con->glInitialized = 1;
// determine window availability (could be EGL-headless) // determine window availability (could be EGL-headless)
@@ -1535,8 +1546,15 @@ void mjr_makeContext_offSize(const mjModel* m, mjrContext* con, int fontscale,
glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_PACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// free previous context // free previous context but keep depth settings
// Doing this is the only way users can control these
// settings without breaking changes to either the
// behaviour of mjr_makeContext or the signature
int oldDepthMapping = con->depthMapping;
int oldDepthPrecision = con->depthPrecision;
mjr_freeContext(con); mjr_freeContext(con);
con->depthMapping = oldDepthMapping;
con->depthPrecision = oldDepthPrecision;
// no model: offscreen and font only // no model: offscreen and font only
if (!m) { if (!m) {
@@ -1828,12 +1846,14 @@ MJAPI void mjr_resizeOffscreen(int width, int height, mjrContext* con) {
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, con->offWidth, con->offHeight); glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, con->offWidth, con->offHeight);
} }
GLenum depth_buffer_format = con->depthPrecision == mjDB_FLOAT32 ? GL_DEPTH32F_STENCIL8 : GL_DEPTH24_STENCIL8;
glBindRenderbuffer(GL_RENDERBUFFER, con->offDepthStencil); glBindRenderbuffer(GL_RENDERBUFFER, con->offDepthStencil);
if (con->offSamples) { if (con->offSamples) {
glRenderbufferStorageMultisample(GL_RENDERBUFFER, con->offSamples, GL_DEPTH24_STENCIL8, glRenderbufferStorageMultisample(GL_RENDERBUFFER, con->offSamples, depth_buffer_format,
con->offWidth, con->offHeight); con->offWidth, con->offHeight);
} else { } else {
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, con->offWidth, con->offHeight); glRenderbufferStorage(GL_RENDERBUFFER, depth_buffer_format, con->offWidth, con->offHeight);
} }
if (con->offSamples) { if (con->offSamples) {
@@ -1841,6 +1861,6 @@ MJAPI void mjr_resizeOffscreen(int width, int height, mjrContext* con) {
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, con->offWidth, con->offHeight); glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, con->offWidth, con->offHeight);
glBindRenderbuffer(GL_RENDERBUFFER, con->offDepthStencil_r); glBindRenderbuffer(GL_RENDERBUFFER, con->offDepthStencil_r);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, con->offWidth, con->offHeight); glRenderbufferStorage(GL_RENDERBUFFER, depth_buffer_format, con->offWidth, con->offHeight);
} }
} }
+39 -3
View File
@@ -498,6 +498,11 @@ static void initGL3(const mjvScene* scn, const mjrContext* con) {
// common options // common options
glDisable(GL_BLEND); glDisable(GL_BLEND);
glEnable(GL_NORMALIZE); glEnable(GL_NORMALIZE);
if (con->depthMapping == mjDB_ONETOZERO) {
glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
} else {
glClipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
}
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE); glDepthMask(GL_TRUE);
if (scn->flags[mjRND_CULL_FACE]) { if (scn->flags[mjRND_CULL_FACE]) {
@@ -506,11 +511,19 @@ static void initGL3(const mjvScene* scn, const mjrContext* con) {
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
} }
glShadeModel(GL_SMOOTH); glShadeModel(GL_SMOOTH);
glDepthFunc(GL_LEQUAL); if (con->depthMapping == mjDB_ONETOZERO) {
glDepthFunc(GL_GEQUAL);
} else {
glDepthFunc(GL_LEQUAL);
}
glDepthRange(0, 1); glDepthRange(0, 1);
glAlphaFunc(GL_GEQUAL, 0.99f); glAlphaFunc(GL_GEQUAL, 0.99f);
glClearColor(0, 0, 0, 0); glClearColor(0, 0, 0, 0);
glClearDepth(1); if (con->depthMapping == mjDB_ONETOZERO) {
glClearDepth(0);
} else {
glClearDepth(1);
}
glClearStencil(0); glClearStencil(0);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
@@ -600,6 +613,11 @@ static void setView(int view, mjrRect viewport, const mjvScene* scn, const mjrCo
// set projection // set projection
glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);
glLoadIdentity(); glLoadIdentity();
if (con->depthMapping == mjDB_ONETOZERO) {
// account for GL_ZERO_TO_ONE and reverse Z
glTranslatef(0,0,0.5);
glScalef(1,1,-0.5);
}
glFrustum(cam.frustum_center - halfwidth, glFrustum(cam.frustum_center - halfwidth,
cam.frustum_center + halfwidth, cam.frustum_center + halfwidth,
cam.frustum_bottom, cam.frustum_bottom,
@@ -672,12 +690,25 @@ void mjr_render(mjrRect viewport, mjvScene* scn, const mjrContext* con) {
float temp[4], headpos[3], forward[3], skyboxdst; float temp[4], headpos[3], forward[3], skyboxdst;
float camProject[16], camView[16], lightProject[16], lightView[16]; float camProject[16], camView[16], lightProject[16], lightView[16];
double clipplane[4]; double clipplane[4];
float biasMatrix[16] = { float biasMatrixOneToZero[16] = {
0.5f, 0.0f, 0.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.0f, 1.0f
};
float biasMatrixNegOneToOne[16] = {
0.5f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f 0.5f, 0.5f, 0.5f, 1.0f
}; };
float* biasMatrix;
if (con->depthMapping == mjDB_ONETOZERO) {
biasMatrix = biasMatrixOneToZero;
} else {
biasMatrix = biasMatrixNegOneToOne;
}
float tempMatrix[16], textureMatrix[16]; float tempMatrix[16], textureMatrix[16];
mjvGeom *thisgeom, tempgeom; mjvGeom *thisgeom, tempgeom;
mjvLight *thislight; mjvLight *thislight;
@@ -1025,6 +1056,11 @@ void mjr_render(mjrRect viewport, mjvScene* scn, const mjrContext* con) {
// set projection: from light viewpoint // set projection: from light viewpoint
glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);
glLoadIdentity(); glLoadIdentity();
if (con->depthMapping == mjDB_ONETOZERO) {
// account for GL_ZERO_TO_ONE and reverse Z
glTranslatef(0,0,0.5);
glScalef(1,1,-0.5);
}
if (thislight->directional) { if (thislight->directional) {
glOrtho(-con->shadowClip, con->shadowClip, glOrtho(-con->shadowClip, con->shadowClip,
-con->shadowClip, con->shadowClip, -con->shadowClip, con->shadowClip,
+8
View File
@@ -389,6 +389,14 @@ public enum mjtFramebuffer : int{
mjFB_WINDOW = 0, mjFB_WINDOW = 0,
mjFB_OFFSCREEN = 1, mjFB_OFFSCREEN = 1,
} }
public enum mjtDepthMapping : int{
mjDB_NEGONETOONE = 0,
mjDB_ONETOZERO = 1,
}
public enum mjtDepthPrecision : int{
mjDB_INT24 = 0,
mjDB_FLOAT32 = 1,
}
public enum mjtFontScale : int{ public enum mjtFontScale : int{
mjFONTSCALE_50 = 50, mjFONTSCALE_50 = 50,
mjFONTSCALE_100 = 100, mjFONTSCALE_100 = 100,