In place change to reverse Z rendering and 32 bit float offscreen depth buffer

This commit is contained in:
Levi Burner
2023-07-11 14:10:14 -04:00
parent 14f1386fc0
commit d32eb6bd12
9 changed files with 24 additions and 161 deletions
-15
View File
@@ -39,15 +39,6 @@ typedef enum mjtFramebuffer_ { // OpenGL framebuffer option
mjFB_OFFSCREEN // offscreen buffer
} 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
mjFONTSCALE_50 = 50, // 50% scale, suitable for low-res rendering
@@ -160,12 +151,6 @@ struct mjrContext_ { // custom OpenGL context
// pixel output format
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;
-18
View File
@@ -621,24 +621,6 @@ ENUMS: Mapping[str, EnumDecl] = dict([
('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',
EnumDecl(
name='mjtFontScale',
-10
View File
@@ -7126,16 +7126,6 @@ STRUCTS: Mapping[str, StructDecl] = dict([
type=ValueType(name='int'),
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',
-34
View File
@@ -34,10 +34,6 @@ class MjWrapper<raw::MjrContext> : public WrapperBase<raw::MjrContext> {
public:
MjWrapper();
MjWrapper(const MjModelWrapper& model, int fontscale);
MjWrapper(const MjModelWrapper& model,
int fontscale,
mjtDepthMapping depthmapping,
mjtDepthPrecision depthprecision);
MjWrapper(const MjWrapper&) = delete;
MjWrapper(MjWrapper&&) = default;
~MjWrapper() = default;
@@ -126,35 +122,6 @@ MjrContextWrapper::MjWrapper(const MjModelWrapper& model, int fontscale)
X_SKIN(skinfaceVBO),
X(charWidth),
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
@@ -199,7 +166,6 @@ PYBIND11_MODULE(_render, pymodule) {
py::class_<MjrContextWrapper> mjrContext(pymodule, "MjrContext");
mjrContext.def(py::init<>());
mjrContext.def(py::init<const MjModelWrapper&, int>());
mjrContext.def(py::init<const MjModelWrapper&, int, mjtDepthMapping, mjtDepthPrecision>());
mjrContext.def(
"free", [](MjrContextWrapper& self) { self.Free(); },
py::doc("Frees resources in current active OpenGL context, sets struct "
+7 -16
View File
@@ -32,9 +32,7 @@ class Renderer:
model: _structs.MjModel,
height: int = 240,
width: int = 320,
max_geom: int = 10000,
depth_mapping: _enums.mjtDepthMapping = _enums.mjtDepthMapping.mjDB_NEGONETOONE,
depth_precision: _enums.mjtDepthPrecision = _enums.mjtDepthPrecision.mjDB_INT24,
max_geom: int = 10000
) -> None:
"""Initializes a new `Renderer`.
@@ -45,8 +43,6 @@ class Renderer:
max_geom: Optional integer specifying the maximum number of geoms that can
be rendered in the same scene. If None this will be chosen automatically
based on the estimated maximum number of renderable geoms in the model.
depth_mapping: Type of mapping from znear to zfar to z buffer ndc values
depth_precision: Precision of z buffer
Raises:
ValueError: If `camera_id` is outside the valid range, or if `width` or
`height` exceed the dimensions of MuJoCo's offscreen framebuffer.
@@ -74,7 +70,6 @@ the clause:
self._width = width
self._height = height
self._model = model
self._depth_mapping = depth_mapping
self._scene = _structs.MjvScene(model=model, maxgeom=max_geom)
self._scene_option = _structs.MjvOption()
@@ -86,7 +81,7 @@ the clause:
self._gl_context = gl_context.GLContext(width, height) # type: ignore
self._gl_context.make_current()
self._mjr_context = _render.MjrContext(
model, _enums.mjtFontScale.mjFONTSCALE_150.value, depth_mapping, depth_precision
model, _enums.mjtFontScale.mjFONTSCALE_150.value
)
_render.mjr_setBuffer(
_enums.mjtFramebuffer.mjFB_OFFSCREEN.value, self._mjr_context
@@ -188,20 +183,16 @@ the clause:
D = -(np.float32(2)*zfar*znear)/(zfar - znear)
# In reverse Z mode the perspective matrix is transformed by the following
if self._depth_mapping == _enums.mjtDepthMapping.mjDB_ONETOZERO:
C = np.float32(-0.5)*C - np.float32(0.5)
D = np.float32(-0.5)*D
C = np.float32(-0.5)*C - np.float32(0.5)
D = np.float32(-0.5)*D
# We need 64 bits to convert Z from ndc to metric depth without noticeable losses in precision
out_64 = out.astype(np.float64)
# Convert depth from window coordinates to normalized device coordinates
# In reversed Z mode the mapping is identity
# https://registry.khronos.org/OpenGL-Refpages/gl4/html/glDepthRange.xhtml
if self._depth_mapping == _enums.mjtDepthMapping.mjDB_NEGONETOONE:
out_64 = 2.0*out_64 - 1.0
# Undo OpenGL projection
# Note: We do not need to take action to convert from window coordinates to
# normalized device coordinates because in reversed Z mode the mapping
# is identity
out_64 = D / (out_64 + C)
# Cast result back to float32 for backwards compatibility
-1
View File
@@ -27,7 +27,6 @@ void PlatformUIAdapter::FreeMjrContext() {
bool PlatformUIAdapter::RefreshMjrContext(const mjModel* m, int fontscale) {
if (m != last_model_ || fontscale != last_fontscale_) {
// con_.depthMapping = mjDB_ONETOZERO;
mjr_makeContext(m, &con_, fontscale);
last_model_ = m;
last_fontscale_ = fontscale;
+7 -21
View File
@@ -1062,11 +1062,7 @@ 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_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
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_TEXTURE_COMPARE_FUNC, GL_GEQUAL);
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
@@ -1125,17 +1121,16 @@ static void makeOff(mjrContext* con) {
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, con->offColor);
// create depth and stencil buffer
GLenum depth_buffer_format = con->depthPrecision == mjDB_FLOAT32 ? GL_DEPTH32F_STENCIL8 : GL_DEPTH24_STENCIL8;
glGenRenderbuffers(1, &con->offDepthStencil);
if (!con->offDepthStencil) {
mju_error("Could not allocate offscreen depth and stencil buffer");
}
glBindRenderbuffer(GL_RENDERBUFFER, con->offDepthStencil);
if (con->offSamples) {
glRenderbufferStorageMultisample(GL_RENDERBUFFER, con->offSamples, depth_buffer_format,
glRenderbufferStorageMultisample(GL_RENDERBUFFER, con->offSamples, GL_DEPTH32F_STENCIL8,
con->offWidth, con->offHeight);
} else {
glRenderbufferStorage(GL_RENDERBUFFER, depth_buffer_format, con->offWidth, con->offHeight);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH32F_STENCIL8, con->offWidth, con->offHeight);
}
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, con->offDepthStencil);
@@ -1174,7 +1169,7 @@ static void makeOff(mjrContext* con) {
mju_error("Could not allocate offscreen depth and stencil buffer_r");
}
glBindRenderbuffer(GL_RENDERBUFFER, con->offDepthStencil_r);
glRenderbufferStorage(GL_RENDERBUFFER, depth_buffer_format, con->offWidth, con->offHeight);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH32F_STENCIL8, con->offWidth, con->offHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, con->offDepthStencil_r);
@@ -1546,15 +1541,7 @@ void mjr_makeContext_offSize(const mjModel* m, mjrContext* con, int fontscale,
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// 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);
con->depthMapping = oldDepthMapping;
con->depthPrecision = oldDepthPrecision;
// no model: offscreen and font only
if (!m) {
@@ -1847,13 +1834,12 @@ MJAPI void mjr_resizeOffscreen(int width, int height, mjrContext* con) {
}
GLenum depth_buffer_format = con->depthPrecision == mjDB_FLOAT32 ? GL_DEPTH32F_STENCIL8 : GL_DEPTH24_STENCIL8;
glBindRenderbuffer(GL_RENDERBUFFER, con->offDepthStencil);
if (con->offSamples) {
glRenderbufferStorageMultisample(GL_RENDERBUFFER, con->offSamples, depth_buffer_format,
glRenderbufferStorageMultisample(GL_RENDERBUFFER, con->offSamples, GL_DEPTH32F_STENCIL8,
con->offWidth, con->offHeight);
} else {
glRenderbufferStorage(GL_RENDERBUFFER, depth_buffer_format, con->offWidth, con->offHeight);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH32F_STENCIL8, con->offWidth, con->offHeight);
}
if (con->offSamples) {
@@ -1861,6 +1847,6 @@ MJAPI void mjr_resizeOffscreen(int width, int height, mjrContext* con) {
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, con->offWidth, con->offHeight);
glBindRenderbuffer(GL_RENDERBUFFER, con->offDepthStencil_r);
glRenderbufferStorage(GL_RENDERBUFFER, depth_buffer_format, con->offWidth, con->offHeight);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH32F_STENCIL8, con->offWidth, con->offHeight);
}
}
+10 -38
View File
@@ -498,11 +498,7 @@ static void initGL3(const mjvScene* scn, const mjrContext* con) {
// common options
glDisable(GL_BLEND);
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);
}
glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
if (scn->flags[mjRND_CULL_FACE]) {
@@ -511,19 +507,11 @@ static void initGL3(const mjvScene* scn, const mjrContext* con) {
glDisable(GL_CULL_FACE);
}
glShadeModel(GL_SMOOTH);
if (con->depthMapping == mjDB_ONETOZERO) {
glDepthFunc(GL_GEQUAL);
} else {
glDepthFunc(GL_LEQUAL);
}
glDepthFunc(GL_GEQUAL);
glDepthRange(0, 1);
glAlphaFunc(GL_GEQUAL, 0.99f);
glClearColor(0, 0, 0, 0);
if (con->depthMapping == mjDB_ONETOZERO) {
glClearDepth(0);
} else {
glClearDepth(1);
}
glClearDepth(0);
glClearStencil(0);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
@@ -613,11 +601,9 @@ static void setView(int view, mjrRect viewport, const mjvScene* scn, const mjrCo
// set projection
glMatrixMode(GL_PROJECTION);
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);
}
// reverse Z rendering mapping (znear, zfar) -> (1, 0)
glTranslatef(0,0,0.5);
glScalef(1,1,-0.5);
glFrustum(cam.frustum_center - halfwidth,
cam.frustum_center + halfwidth,
cam.frustum_bottom,
@@ -690,24 +676,12 @@ void mjr_render(mjrRect viewport, mjvScene* scn, const mjrContext* con) {
float temp[4], headpos[3], forward[3], skyboxdst;
float camProject[16], camView[16], lightProject[16], lightView[16];
double clipplane[4];
float biasMatrixOneToZero[16] = {
float biasMatrix[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.0f, 0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 0.5f, 0.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];
mjvGeom *thisgeom, tempgeom;
@@ -1056,11 +1030,9 @@ void mjr_render(mjrRect viewport, mjvScene* scn, const mjrContext* con) {
// set projection: from light viewpoint
glMatrixMode(GL_PROJECTION);
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);
}
// reverse Z rendering mapping (znear, zfar) -> (1, 0)
glTranslatef(0,0,0.5);
glScalef(1,1,-0.5);
if (thislight->directional) {
glOrtho(-con->shadowClip, con->shadowClip,
-con->shadowClip, con->shadowClip,
-8
View File
@@ -389,14 +389,6 @@ public enum mjtFramebuffer : int{
mjFB_WINDOW = 0,
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{
mjFONTSCALE_50 = 50,
mjFONTSCALE_100 = 100,