mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-27 15:25:54 -04:00
display: Support specifying depth range on DisplayRegion
See https://discourse.panda3d.org/t/depthoffsetattrib-z-range-composition-order/27943/4
This commit is contained in:
parent
3d4dd50358
commit
280175f267
@ -156,6 +156,28 @@ set_dimensions(const LVecBase4 &dimensions) {
|
||||
set_dimensions(0, dimensions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the range of the depth buffer this DisplayRegion writes to.
|
||||
* The parameters range from 0 to 1. It is legal for the near value to be
|
||||
* larger than the far value.
|
||||
*/
|
||||
INLINE void DisplayRegion::
|
||||
set_depth_range(PN_stdfloat near, PN_stdfloat far) {
|
||||
CDWriter cdata(_cycler, true);
|
||||
cdata->_depth_range.set(near, far);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INLINE void DisplayRegion::
|
||||
get_depth_range(PN_stdfloat &near, PN_stdfloat &far) const {
|
||||
CDReader cdata(_cycler);
|
||||
const LVecBase2 &range = cdata->_depth_range;
|
||||
near = range[0];
|
||||
far = range[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the GraphicsOutput that this DisplayRegion is ultimately associated
|
||||
* with, or NULL if no window is associated.
|
||||
@ -693,6 +715,16 @@ get_top(int i) const {
|
||||
return _cdata->_regions[i]._dimensions[3];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INLINE void DisplayRegionPipelineReader::
|
||||
get_depth_range(PN_stdfloat &near, PN_stdfloat &far) const {
|
||||
const LVecBase2 &range = _cdata->_depth_range;
|
||||
near = range[0];
|
||||
far = range[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the GraphicsOutput that this DisplayRegion is ultimately associated
|
||||
* with, or NULL if no window is associated.
|
||||
|
@ -738,7 +738,8 @@ CData() :
|
||||
_stereo_channel(Lens::SC_mono),
|
||||
_tex_view_offset(0),
|
||||
_target_tex_page(-1),
|
||||
_scissor_enabled(true)
|
||||
_scissor_enabled(true),
|
||||
_depth_range(0, 1)
|
||||
{
|
||||
_regions.push_back(Region());
|
||||
}
|
||||
@ -757,7 +758,8 @@ CData(const DisplayRegion::CData ©) :
|
||||
_stereo_channel(copy._stereo_channel),
|
||||
_tex_view_offset(copy._tex_view_offset),
|
||||
_target_tex_page(copy._target_tex_page),
|
||||
_scissor_enabled(copy._scissor_enabled)
|
||||
_scissor_enabled(copy._scissor_enabled),
|
||||
_depth_range(copy._depth_range)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -82,6 +82,9 @@ PUBLISHED:
|
||||
virtual void set_dimensions(int i, const LVecBase4 &dimensions);
|
||||
MAKE_PROPERTY(dimensions, get_dimensions, set_dimensions);
|
||||
|
||||
INLINE void set_depth_range(PN_stdfloat near, PN_stdfloat far);
|
||||
INLINE void get_depth_range(PN_stdfloat &near, PN_stdfloat &far) const;
|
||||
|
||||
INLINE GraphicsOutput *get_window() const;
|
||||
GraphicsPipe *get_pipe() const;
|
||||
virtual bool is_stereo() const;
|
||||
@ -233,6 +236,7 @@ private:
|
||||
}
|
||||
|
||||
Regions _regions;
|
||||
LVecBase2 _depth_range; // near, far
|
||||
|
||||
int _lens_index; // index into which lens of a camera is associated with this display region. 0 is default
|
||||
|
||||
@ -333,6 +337,8 @@ public:
|
||||
INLINE PN_stdfloat get_bottom(int i = 0) const;
|
||||
INLINE PN_stdfloat get_top(int i = 0) const;
|
||||
|
||||
INLINE void get_depth_range(PN_stdfloat &near, PN_stdfloat &far) const;
|
||||
|
||||
INLINE GraphicsOutput *get_window() const;
|
||||
GraphicsPipe *get_pipe() const;
|
||||
|
||||
|
@ -528,6 +528,7 @@ CLP(GraphicsStateGuardian)(GraphicsEngine *engine, GraphicsPipe *pipe) :
|
||||
|
||||
_scissor_enabled = false;
|
||||
_scissor_attrib_active = false;
|
||||
_has_attrib_depth_range = false;
|
||||
|
||||
_white_texture = 0;
|
||||
|
||||
@ -3337,6 +3338,7 @@ reset() {
|
||||
_glDepthRangedNV(-1.0, 1.0);
|
||||
_use_depth_zero_to_one = true;
|
||||
_use_remapped_depth_range = true;
|
||||
_has_attrib_depth_range = false;
|
||||
|
||||
if (GLCAT.is_debug()) {
|
||||
GLCAT.debug()
|
||||
@ -3352,6 +3354,17 @@ reset() {
|
||||
}
|
||||
#endif
|
||||
|
||||
if (_has_attrib_depth_range) {
|
||||
#ifdef OPENGLES
|
||||
glDepthRangef(0.0f, 1.0f);
|
||||
#else
|
||||
glDepthRange(0.0, 1.0);
|
||||
#endif
|
||||
_depth_range_near = 0;
|
||||
_depth_range_far = 1;
|
||||
_has_attrib_depth_range = false;
|
||||
}
|
||||
|
||||
// Set up all the enableddisabled flags to GL's known initial values:
|
||||
// everything off.
|
||||
_multisample_mode = 0;
|
||||
@ -3926,6 +3939,33 @@ prepare_display_region(DisplayRegionPipelineReader *dr) {
|
||||
}
|
||||
}
|
||||
|
||||
PN_stdfloat near;
|
||||
PN_stdfloat far;
|
||||
dr->get_depth_range(near, far);
|
||||
#ifdef GSG_VERBOSE
|
||||
if (GLCAT.is_spam()) {
|
||||
GLCAT.spam()
|
||||
<< "glDepthRange(" << near << ", " << far << ")" << endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef OPENGLES
|
||||
// OpenGL ES uses a single-precision call.
|
||||
glDepthRangef((GLclampf)near, (GLclampf)far);
|
||||
#else
|
||||
// Mainline OpenGL uses a double-precision call.
|
||||
if (!_use_remapped_depth_range) {
|
||||
glDepthRange((GLclampd)near, (GLclampd)far);
|
||||
} else {
|
||||
// If we have a remapped depth range, we should adjust the values to range
|
||||
// from -1 to 1. We need to use an NV extension to pass unclamped values.
|
||||
_glDepthRangedNV(near * 2.0 - 1.0, far * 2.0 - 1.0);
|
||||
}
|
||||
#endif // OPENGLES
|
||||
_has_attrib_depth_range = false;
|
||||
_depth_range_near = near;
|
||||
_depth_range_far = far;
|
||||
|
||||
report_my_gl_errors();
|
||||
}
|
||||
|
||||
@ -8151,24 +8191,35 @@ do_issue_depth_offset() {
|
||||
|
||||
PN_stdfloat min_value = target_depth_offset->get_min_value();
|
||||
PN_stdfloat max_value = target_depth_offset->get_max_value();
|
||||
if (min_value != (PN_stdfloat)0.0 ||
|
||||
max_value != (PN_stdfloat)1.0 ||
|
||||
_has_attrib_depth_range) {
|
||||
min_value = _depth_range_far * min_value + _depth_range_near * (1 - min_value);
|
||||
max_value = _depth_range_far * max_value + _depth_range_near * (1 - max_value);
|
||||
|
||||
#ifdef GSG_VERBOSE
|
||||
GLCAT.spam()
|
||||
<< "glDepthRange(" << min_value << ", " << max_value << ")" << endl;
|
||||
if (GLCAT.is_spam()) {
|
||||
GLCAT.spam()
|
||||
<< "glDepthRange(" << min_value << ", " << max_value << ")" << endl;
|
||||
}
|
||||
#endif
|
||||
#ifdef OPENGLES
|
||||
// OpenGL ES uses a single-precision call.
|
||||
glDepthRangef((GLclampf)min_value, (GLclampf)max_value);
|
||||
// OpenGL ES uses a single-precision call.
|
||||
glDepthRangef((GLclampf)min_value, (GLclampf)max_value);
|
||||
#else
|
||||
// Mainline OpenGL uses a double-precision call.
|
||||
if (!_use_remapped_depth_range) {
|
||||
glDepthRange((GLclampd)min_value, (GLclampd)max_value);
|
||||
} else {
|
||||
// If we have a remapped depth range, we should adjust the values to range
|
||||
// from -1 to 1. We need to use an NV extension to pass unclamped values.
|
||||
_glDepthRangedNV(min_value * 2.0 - 1.0, max_value * 2.0 - 1.0);
|
||||
}
|
||||
// Mainline OpenGL uses a double-precision call.
|
||||
if (!_use_remapped_depth_range) {
|
||||
glDepthRange((GLclampd)min_value, (GLclampd)max_value);
|
||||
} else {
|
||||
// If we have a remapped depth range, we should adjust the values to range
|
||||
// from -1 to 1. We need to use an NV extension to pass unclamped values.
|
||||
_glDepthRangedNV(min_value * 2.0 - 1.0, max_value * 2.0 - 1.0);
|
||||
}
|
||||
#endif // OPENGLES
|
||||
|
||||
_has_attrib_depth_range = true;
|
||||
}
|
||||
|
||||
report_my_gl_errors();
|
||||
}
|
||||
|
||||
|
@ -675,6 +675,9 @@ protected:
|
||||
bool _scissor_enabled;
|
||||
bool _scissor_attrib_active;
|
||||
epvector<LVecBase4i> _scissor_array;
|
||||
PN_stdfloat _depth_range_near;
|
||||
PN_stdfloat _depth_range_far;
|
||||
bool _has_attrib_depth_range;
|
||||
|
||||
#ifndef OPENGLES_1
|
||||
BitMask32 _enabled_vertex_attrib_arrays;
|
||||
|
@ -56,7 +56,7 @@ def depth_region(request, graphics_pipe):
|
||||
engine.remove_window(buffer)
|
||||
|
||||
|
||||
def render_depth_pixel(region, distance, near, far, clear=None, write=True):
|
||||
def render_depth_pixel(region, distance, near, far, clear=None, write=True, state=None):
|
||||
"""Renders a fragment at the specified distance using the specified render
|
||||
settings, and returns the resulting depth value."""
|
||||
|
||||
@ -65,6 +65,9 @@ def render_depth_pixel(region, distance, near, far, clear=None, write=True):
|
||||
scene.set_attrib(core.DepthTestAttrib.make(core.RenderAttrib.M_always))
|
||||
scene.set_depth_write(write)
|
||||
|
||||
if state:
|
||||
scene.set_state(scene.get_state().compose(state))
|
||||
|
||||
camera = scene.attach_new_node(core.Camera("camera"))
|
||||
camera.node().get_lens(0).set_near_far(near, far)
|
||||
camera.node().set_cull_bounds(core.OmniBoundingVolume())
|
||||
@ -151,3 +154,28 @@ def test_inverted_depth_clipping(depth_region):
|
||||
|
||||
# Just far enough; read a value close to 0.0.
|
||||
assert 0.01 > render_depth_pixel(depth_region, 9.999, near=10, far=1, clear=0.5)
|
||||
|
||||
|
||||
def test_depth_range(depth_region):
|
||||
try:
|
||||
depth_region.set_depth_range(0.25, 0.75)
|
||||
z = render_depth_pixel(depth_region, 1.00001, near=1, far=10)
|
||||
assert z == pytest.approx(0.25, rel=0.01)
|
||||
|
||||
z = render_depth_pixel(depth_region, 10, near=1, far=10)
|
||||
assert z == pytest.approx(0.75, rel=0.01)
|
||||
|
||||
# Combines with DepthOffsetAttrib range.
|
||||
state = core.RenderState.make(core.DepthOffsetAttrib.make(0, 0.25, 0.75))
|
||||
z = render_depth_pixel(depth_region, 1.00001, near=1, far=10, state=state)
|
||||
assert z == pytest.approx(0.375, rel=0.01)
|
||||
|
||||
# Reverse the depth range.
|
||||
depth_region.set_depth_range(0.75, 0.25)
|
||||
z = render_depth_pixel(depth_region, 1.00001, near=1, far=10)
|
||||
assert z == pytest.approx(0.75, rel=0.01)
|
||||
|
||||
z = render_depth_pixel(depth_region, 10, near=1, far=10)
|
||||
assert z == pytest.approx(0.25, rel=0.01)
|
||||
finally:
|
||||
depth_region.set_depth_range(0, 1)
|
||||
|
Loading…
x
Reference in New Issue
Block a user