RM_billboard, etc.

This commit is contained in:
David Rose 2002-12-06 01:21:04 +00:00
parent 0be100989d
commit a39fe8b02f
12 changed files with 579 additions and 147 deletions

View File

@ -16,7 +16,7 @@
parametricCurveDrawer.h curveFitter.I curveFitter.h \
hermiteCurve.h nurbsCurve.h \
nurbsCurveDrawer.I nurbsCurveDrawer.h \
nurbsCurveEvaluator.h \
nurbsCurveEvaluator.I nurbsCurveEvaluator.h \
nurbsCurveInterface.I nurbsCurveInterface.h \
nurbsCurveResult.I nurbsCurveResult.h \
nurbsMatrixVector.I nurbsMatrixVector.h \
@ -50,7 +50,7 @@
hermiteCurve.h \
nurbsCurve.h \
nurbsCurveDrawer.I nurbsCurveDrawer.h \
nurbsCurveEvaluator.h \
nurbsCurveEvaluator.I nurbsCurveEvaluator.h \
nurbsCurveInterface.I nurbsCurveInterface.h \
nurbsCurveResult.I nurbsCurveResult.h \
nurbsMatrixVector.I nurbsMatrixVector.h \

View File

@ -0,0 +1,140 @@
// Filename: nurbsCurveEvaluator.I
// Created by: drose (05Dec02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveEvaluator::set_order
// Access: Published
// Description: Sets the order of the curve. This resets the knot
// vector to the default knot vector for the number of
// vertices.
//
// The order must be 1, 2, 3, or 4, and the value is one
// more than the degree of the curve.
////////////////////////////////////////////////////////////////////
INLINE void NurbsCurveEvaluator::
set_order(int order) {
_order = order;
_knots_dirty = true;
_basis_dirty = true;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveEvaluator::get_order
// Access: Published
// Description: Returns the order of the curve as set by a previous
// call to set_order().
////////////////////////////////////////////////////////////////////
INLINE int NurbsCurveEvaluator::
get_order() const {
return _order;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveEvaluator::get_num_vertices
// Access: Published
// Description: Returns the number of control vertices in the curve.
// This is the number passed to the last call to
// reset().
////////////////////////////////////////////////////////////////////
INLINE int NurbsCurveEvaluator::
get_num_vertices() const {
return (int)_vertices.size();
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveEvaluator::set_vertex
// Access: Published
// Description: Sets the nth control vertex of the curve.
////////////////////////////////////////////////////////////////////
INLINE void NurbsCurveEvaluator::
set_vertex(int i, const LVecBase4f &vertex) {
nassertv(i >= 0 && i < (int)_vertices.size());
_vertices[i].set_vertex(vertex);
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveEvaluator::set_vertex
// Access: Published
// Description: Sets the nth control vertex of the curve.
////////////////////////////////////////////////////////////////////
INLINE void NurbsCurveEvaluator::
set_vertex(int i, const LVecBase3f &vertex, float weight) {
nassertv(i >= 0 && i < (int)_vertices.size());
_vertices[i].set_vertex(LVecBase4f(vertex[0] * weight, vertex[1] * weight, vertex[2] * weight, weight));
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveEvaluator::get_vertex
// Access: Published
// Description: Returns the nth control vertex of the curve, relative
// to its indicated coordinate space.
////////////////////////////////////////////////////////////////////
INLINE const LVecBase4f &NurbsCurveEvaluator::
get_vertex(int i) const {
nassertr(i >= 0 && i < (int)_vertices.size(), LVecBase4f::zero());
return _vertices[i].get_vertex();
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveEvaluator::set_vertex_space
// Access: Published
// Description: Sets the coordinate space of the nth control vertex.
// If this is not specified, or is set to an empty
// NodePath, the nth control vertex is deemed to be in
// the coordinate space passed to evaluate().
//
// This specifies the space as a fixed NodePath, which
// is always the same NodePath. Also see setting the
// space as a path string, which can specify a different
// NodePath for different instances of the curve.
////////////////////////////////////////////////////////////////////
INLINE void NurbsCurveEvaluator::
set_vertex_space(int i, const NodePath &space) {
nassertv(i >= 0 && i < (int)_vertices.size());
_vertices[i].set_space(space);
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveEvaluator::set_vertex_space
// Access: Published
// Description: Sets the coordinate space of the nth control vertex.
// If this is not specified, or is set to an empty
// string, the nth control vertex is deemed to be in
// the coordinate space passed to evaluate().
//
// This specifies the space as a string, which describes
// the path to find the node relative to the rel_to
// NodePath when the curve is evaluated.
////////////////////////////////////////////////////////////////////
INLINE void NurbsCurveEvaluator::
set_vertex_space(int i, const string &space) {
nassertv(i >= 0 && i < (int)_vertices.size());
_vertices[i].set_space(space);
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveEvaluator::get_num_knots
// Access: Published
// Description: Returns the number of knot values in the curve. This
// is based on the number of vertices and the order.
////////////////////////////////////////////////////////////////////
INLINE int NurbsCurveEvaluator::
get_num_knots() const {
return (int)_vertices.size() + _order;
}

View File

@ -39,34 +39,6 @@ NurbsCurveEvaluator::
~NurbsCurveEvaluator() {
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveEvaluator::set_order
// Access: Published
// Description: Sets the order of the curve. This resets the knot
// vector to the default knot vector for the number of
// vertices.
//
// The order must be 1, 2, 3, or 4, and the value is one
// more than the degree of the curve.
////////////////////////////////////////////////////////////////////
void NurbsCurveEvaluator::
set_order(int order) {
_order = order;
_knots_dirty = true;
_basis_dirty = true;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveEvaluator::get_order
// Access: Published
// Description: Returns the order of the curve as set by a previous
// call to set_order().
////////////////////////////////////////////////////////////////////
int NurbsCurveEvaluator::
get_order() const {
return _order;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveEvaluator::reset
// Access: Published
@ -88,90 +60,19 @@ reset(int num_vertices) {
_basis_dirty = true;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveEvaluator::get_num_vertices
// Access: Published
// Description: Returns the number of control vertices in the curve.
// This is the number passed to the last call to
// reset().
////////////////////////////////////////////////////////////////////
int NurbsCurveEvaluator::
get_num_vertices() const {
return (int)_vertices.size();
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveEvaluator::set_vertex
// Access: Published
// Description: Sets the nth control vertex of the curve.
////////////////////////////////////////////////////////////////////
void NurbsCurveEvaluator::
set_vertex(int i, const LVecBase4f &vertex) {
nassertv(i >= 0 && i < (int)_vertices.size());
_vertices[i].set_vertex(vertex);
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveEvaluator::set_vertex
// Access: Published
// Description: Sets the nth control vertex of the curve.
////////////////////////////////////////////////////////////////////
void NurbsCurveEvaluator::
set_vertex(int i, const LVecBase3f &vertex, float weight) {
nassertv(i >= 0 && i < (int)_vertices.size());
_vertices[i].set_vertex(LVecBase4f(vertex[0] * weight, vertex[1] * weight, vertex[2] * weight, weight));
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveEvaluator::get_vertex
// Access: Published
// Description: Returns the nth control vertex of the curve, relative
// to its indicated coordinate space.
////////////////////////////////////////////////////////////////////
const LVecBase4f &NurbsCurveEvaluator::
get_vertex(int i) const {
nassertr(i >= 0 && i < (int)_vertices.size(), LVecBase4f::zero());
return _vertices[i].get_vertex();
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveEvaluator::set_vertex_space
// Access: Published
// Description: Sets the coordinate space of the nth control vertex.
// If this is not specified, or is set to an empty
// NodePath, the nth control vertex is deemed to be in
// the coordinate space passed to evaluate().
////////////////////////////////////////////////////////////////////
void NurbsCurveEvaluator::
set_vertex_space(int i, const NodePath &space) {
nassertv(i >= 0 && i < (int)_vertices.size());
_vertices[i].set_space(space);
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveEvaluator::get_vertex_space
// Access: Published
// Description: Returns the coordinate space of the nth control
// vertex of the curve, expressed as a NodePath.
////////////////////////////////////////////////////////////////////
const NodePath &NurbsCurveEvaluator::
get_vertex_space(int i) const {
NodePath NurbsCurveEvaluator::
get_vertex_space(int i, const NodePath &rel_to) const {
#ifndef NDEBUG
static NodePath empty_node_path;
nassertr(i >= 0 && i < (int)_vertices.size(), empty_node_path);
#endif
return _vertices[i].get_space();
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveEvaluator::get_num_knots
// Access: Published
// Description: Returns the number of knot values in the curve. This
// is based on the number of vertices and the order.
////////////////////////////////////////////////////////////////////
int NurbsCurveEvaluator::
get_num_knots() const {
return (int)_vertices.size() + _order;
return _vertices[i].get_space(rel_to);
}
////////////////////////////////////////////////////////////////////
@ -242,7 +143,7 @@ get_vertices(pvector<LVecBase4f> &verts, const NodePath &rel_to) const {
verts.reserve(verts.size() + num_vertices);
int vi;
for (vi = 0; vi < num_vertices; vi++) {
const NodePath &space = _vertices[vi].get_space();
NodePath space = _vertices[vi].get_space(rel_to);
const LVecBase4f &vertex = _vertices[vi].get_vertex();
if (space.is_empty()) {
verts.push_back(vertex);
@ -267,7 +168,7 @@ get_vertices(pvector<LPoint3f> &verts, const NodePath &rel_to) const {
verts.reserve(verts.size() + num_vertices);
int vi;
for (vi = 0; vi < num_vertices; vi++) {
const NodePath &space = _vertices[vi].get_space();
const NodePath &space = _vertices[vi].get_space(rel_to);
LVecBase4f vertex = _vertices[vi].get_vertex();
if (!space.is_empty()) {
const LMatrix4f &mat = space.get_mat(rel_to);

View File

@ -50,20 +50,21 @@ PUBLISHED:
NurbsCurveEvaluator();
~NurbsCurveEvaluator();
void set_order(int order);
int get_order() const;
INLINE void set_order(int order);
INLINE int get_order() const;
void reset(int num_vertices);
int get_num_vertices() const;
void set_vertex(int i, const LVecBase4f &vertex);
void set_vertex(int i, const LVecBase3f &vertex, float weight = 1.0);
const LVecBase4f &get_vertex(int i) const;
INLINE int get_num_vertices() const;
INLINE void set_vertex(int i, const LVecBase4f &vertex);
INLINE void set_vertex(int i, const LVecBase3f &vertex, float weight = 1.0);
INLINE const LVecBase4f &get_vertex(int i) const;
void set_vertex_space(int i, const NodePath &space);
const NodePath &get_vertex_space(int i) const;
INLINE void set_vertex_space(int i, const NodePath &space);
INLINE void set_vertex_space(int i, const string &space);
NodePath get_vertex_space(int i, const NodePath &rel_to) const;
int get_num_knots() const;
INLINE int get_num_knots() const;
void set_knot(int i, float knot);
float get_knot(int i) const;
@ -90,5 +91,7 @@ private:
NurbsMatrixVector _basis;
};
#include "nurbsCurveEvaluator.I"
#endif

View File

@ -65,6 +65,25 @@ eval_point(float t, LVecBase3f &point) {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveResult::eval_tangent
// Access: Published
// Description: Computes the tangent to the curve at the indicated
// point in parametric time. This tangent vector will
// not necessarily be normalized, and could be zero.
// See also eval_point().
////////////////////////////////////////////////////////////////////
INLINE bool NurbsCurveResult::
eval_tangent(float t, LVecBase3f &tangent) {
int segment = find_segment(t);
if (segment == -1) {
return false;
}
eval_segment_tangent(segment, _prod.scale_t(segment, t), tangent);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveResult::get_num_segments
// Access: Public
@ -77,3 +96,16 @@ INLINE int NurbsCurveResult::
get_num_segments() const {
return _prod.get_num_segments();
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveResult::get_segment_t
// Access: Public
// Description: Accepts a t value in the range [0, 1], and assumed to
// be relative to the indicated segment (as in
// eval_segment_point()), and returns the corresponding
// t value in the entire curve (as in eval_point()).
////////////////////////////////////////////////////////////////////
INLINE float NurbsCurveResult::
get_segment_t(int segment, float t) const {
return t * (_prod.get_to(segment) - _prod.get_from(segment)) + _prod.get_from(segment);
}

View File

@ -82,6 +82,24 @@ eval_segment_point(int segment, float t, LVecBase3f &point) const {
point.set(r[0] / r[3], r[1] / r[3], r[2] / r[3]);
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveResult::eval_segment_tangent
// Access: Published
// Description: As eval_segment_point, but computes the tangent to
// the curve at the indicated point. The tangent vector
// will not necessarily be normalized, and could be
// zero, particularly at the endpoints.
////////////////////////////////////////////////////////////////////
void NurbsCurveResult::
eval_segment_tangent(int segment, float t, LVecBase3f &tangent) const {
const LMatrix4f &mat = _prod.get_matrix(segment);
float t2 = t*t;
LVecBase4f tvec(t2, t, 1.0f, 0.0f);
LVecBase4f r = tvec * mat;
tangent.set(r[0], r[1], r[2]);
}
////////////////////////////////////////////////////////////////////
// Function: NurbsCurveResult::find_segment
// Access: Private

View File

@ -49,9 +49,12 @@ PUBLISHED:
INLINE float get_end_t() const;
INLINE bool eval_point(float t, LVecBase3f &point);
INLINE bool eval_tangent(float t, LVecBase3f &tangent);
INLINE int get_num_segments() const;
void eval_segment_point(int segment, float t, LVecBase3f &point) const;
void eval_segment_tangent(int segment, float t, LVecBase3f &tangent) const;
INLINE float get_segment_t(int segment, float t) const;
private:
int find_segment(float t);

View File

@ -34,7 +34,8 @@ NurbsVertex() {
INLINE NurbsVertex::
NurbsVertex(const NurbsVertex &copy) :
_vertex(copy._vertex),
_space(copy._space)
_space(copy._space),
_space_path(copy._space_path)
{
}
@ -47,6 +48,7 @@ INLINE void NurbsVertex::
operator = (const NurbsVertex &copy) {
_vertex = copy._vertex;
_space = copy._space;
_space_path = copy._space_path;
}
////////////////////////////////////////////////////////////////////
@ -81,11 +83,24 @@ get_vertex() const {
////////////////////////////////////////////////////////////////////
// Function: NurbsVertex::set_space
// Access: Public
// Description:
// Description: Sets the space of this vertex as a fixed NodePath.
////////////////////////////////////////////////////////////////////
INLINE void NurbsVertex::
set_space(const NodePath &space) {
_space = space;
_space_path = string();
}
////////////////////////////////////////////////////////////////////
// Function: NurbsVertex::set_space
// Access: Public
// Description: Sets the space of this vertex as a relative path from
// the rel_to node.
////////////////////////////////////////////////////////////////////
INLINE void NurbsVertex::
set_space(const string &space) {
_space = NodePath();
_space_path = space;
}
////////////////////////////////////////////////////////////////////
@ -93,7 +108,11 @@ set_space(const NodePath &space) {
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE const NodePath &NurbsVertex::
get_space() const {
INLINE NodePath NurbsVertex::
get_space(const NodePath &rel_to) const {
if (_space_path.empty()) {
return _space;
} else {
return rel_to.find(_space_path);
}
}

View File

@ -48,11 +48,13 @@ public:
INLINE const LVecBase4f &get_vertex() const;
INLINE void set_space(const NodePath &space);
INLINE const NodePath &get_space() const;
INLINE void set_space(const string &space);
INLINE NodePath get_space(const NodePath &rel_to) const;
private:
LVecBase4f _vertex;
NodePath _space;
string _space_path;
};
#include "nurbsVertex.I"

View File

@ -25,7 +25,11 @@
INLINE RopeNode::CData::
CData() {
_curve = new NurbsCurveEvaluator;
_render_mode = RopeNode::RM_thread;
_uv_mode = RopeNode::UV_none;
_uv_scale.set(1.0f, 1.0f);
_num_segs = 10;
_thickness = 1.0f;
}
////////////////////////////////////////////////////////////////////
@ -35,7 +39,12 @@ CData() {
////////////////////////////////////////////////////////////////////
INLINE RopeNode::CData::
CData(const RopeNode::CData &copy) :
_curve(copy._curve)
_curve(copy._curve),
_render_mode(copy._render_mode),
_uv_mode(copy._uv_mode),
_uv_scale(copy._uv_scale),
_num_segs(copy._num_segs),
_thickness(copy._thickness)
{
}
@ -62,6 +71,79 @@ get_curve() const {
return cdata->_curve;
}
////////////////////////////////////////////////////////////////////
// Function: set_render_mode
// Access: Public
// Description: Specifies the method used to render the rope. The
// simplest is RM_thread, which just draws a one-pixel
// line segment.
////////////////////////////////////////////////////////////////////
INLINE void RopeNode::
set_render_mode(RopeNode::RenderMode render_mode) {
CDWriter cdata(_cycler);
cdata->_render_mode = render_mode;
}
////////////////////////////////////////////////////////////////////
// Function: get_render_mode
// Access: Public
// Description: Returns the method used to render the rope. See
// set_render_mode().
////////////////////////////////////////////////////////////////////
INLINE RopeNode::RenderMode RopeNode::
get_render_mode() const {
CDReader cdata(_cycler);
return cdata->_render_mode;
}
////////////////////////////////////////////////////////////////////
// Function: set_uv_mode
// Access: Public
// Description: Specifies the algorithm to use to generate UV's for
// the rope.
////////////////////////////////////////////////////////////////////
INLINE void RopeNode::
set_uv_mode(RopeNode::UVMode uv_mode) {
CDWriter cdata(_cycler);
cdata->_uv_mode = uv_mode;
}
////////////////////////////////////////////////////////////////////
// Function: get_uv_mode
// Access: Public
// Description: Returns the algorithm to use to generate UV's for the
// rope.
////////////////////////////////////////////////////////////////////
INLINE RopeNode::UVMode RopeNode::
get_uv_mode() const {
CDReader cdata(_cycler);
return cdata->_uv_mode;
}
////////////////////////////////////////////////////////////////////
// Function: set_uv_scale
// Access: Public
// Description: Specifies an additional scaling factor to apply to
// generated UV's for the rope.
////////////////////////////////////////////////////////////////////
INLINE void RopeNode::
set_uv_scale(const LVecBase2f &uv_scale) {
CDWriter cdata(_cycler);
cdata->_uv_scale = uv_scale;
}
////////////////////////////////////////////////////////////////////
// Function: get_uv_scale
// Access: Public
// Description: Returns the scaling factor to apply to generated UV's
// for the rope.
////////////////////////////////////////////////////////////////////
INLINE const LVecBase2f &RopeNode::
get_uv_scale() const {
CDReader cdata(_cycler);
return cdata->_uv_scale;
}
////////////////////////////////////////////////////////////////////
// Function: set_num_segs
// Access: Public
@ -87,3 +169,29 @@ get_num_segs() const {
CDReader cdata(_cycler);
return cdata->_num_segs;
}
////////////////////////////////////////////////////////////////////
// Function: set_thickness
// Access: Public
// Description: Specifies the thickness of the rope, in pixels or in
// spatial units, depending on the render mode. See
// set_render_mode().
////////////////////////////////////////////////////////////////////
INLINE void RopeNode::
set_thickness(float thickness) {
nassertv(thickness >= 0);
CDWriter cdata(_cycler);
cdata->_thickness = thickness;
}
////////////////////////////////////////////////////////////////////
// Function: get_thickness
// Access: Public
// Description: Returns the thickness of the rope. See
// set_thickness().
////////////////////////////////////////////////////////////////////
INLINE float RopeNode::
get_thickness() const {
CDReader cdata(_cycler);
return cdata->_thickness;
}

View File

@ -22,6 +22,7 @@
#include "cullableObject.h"
#include "cullHandler.h"
#include "geomLinestrip.h"
#include "geomTristrip.h"
#include "bamWriter.h"
#include "bamReader.h"
#include "datagram.h"
@ -149,35 +150,21 @@ has_cull_callback() const {
////////////////////////////////////////////////////////////////////
bool RopeNode::
cull_callback(CullTraverser *trav, CullTraverserData &data) {
// Create a new linestrip on-the-fly to render the rope.
int num_verts = get_num_segs() + 1;
if (num_verts >= 2) {
PTA_Vertexf verts;
PTA_int lengths;
// Create some geometry on-the-fly to render the rope.
if (get_num_segs() > 0) {
NurbsCurveEvaluator *curve = get_curve();
PT(NurbsCurveResult) result = curve->evaluate(data._node_path.get_node_path());
int num_segments = result->get_num_segments();
if (num_segments > 0) {
for (int segment = 0; segment < num_segments; segment++) {
for (int i = 0; i < num_verts; i++) {
float t = (float)i / (float)(num_verts - 1);
LPoint3f point;
result->eval_segment_point(segment, t, point);
verts.push_back(point);
}
lengths.push_back(num_verts);
}
if (result->get_num_segments() > 0) {
switch (get_render_mode()) {
case RM_thread:
render_thread(trav, data, result);
break;
PT(Geom) geom = new GeomLinestrip;
geom->set_num_prims(num_segments);
geom->set_coords(verts);
geom->set_lengths(lengths);
CullableObject *object = new CullableObject(geom, data._state,
data._render_transform);
trav->get_cull_handler()->record_object(object);
case RM_billboard:
render_billboard(trav, data, result);
break;
}
}
}
@ -245,6 +232,192 @@ recompute_internal_bound() {
return reset_bound(NodePath(this));
}
////////////////////////////////////////////////////////////////////
// Function: RopeNode::render_thread
// Access: Private
// Description: Draws the rope in RM_thread mode. This uses a
// GeomLinestrip to draw the rope in the simplest
// possible method, generally resulting in a
// one-pixel-wide curve.
//
// In this mode, the thickness parameter represents a
// thickness in pixels, and is passed to the linestrip.
// However, you should be aware the DirectX does not
// support line thickness.
////////////////////////////////////////////////////////////////////
void RopeNode::
render_thread(CullTraverser *trav, CullTraverserData &data,
NurbsCurveResult *result) {
PTA_Vertexf verts;
PTA_TexCoordf uvs;
PTA_int lengths;
int num_verts = get_num_segs() + 1;
int num_segments = result->get_num_segments();
for (int segment = 0; segment < num_segments; segment++) {
for (int i = 0; i < num_verts; i++) {
float t = (float)i / (float)(num_verts - 1);
LPoint3f point;
result->eval_segment_point(segment, t, point);
verts.push_back(point);
uvs.push_back(TexCoordf(result->get_segment_t(segment, t), 0.0f));
}
lengths.push_back(num_verts);
}
PT(Geom) geom = new GeomLinestrip;
geom->set_num_prims(num_segments);
geom->set_coords(verts);
geom->set_lengths(lengths);
CullableObject *object = new CullableObject(geom, data._state,
data._render_transform);
trav->get_cull_handler()->record_object(object);
}
////////////////////////////////////////////////////////////////////
// Function: RopeNode::render_billboard
// Access: Private
// Description: Draws the rope in RM_billboard mode. This draws a
// series of triangle strips oriented to be
// perpendicular to the camera plane.
//
// In this mode, thickness is in spatial units, and
// determines the with of the triangle strips.
////////////////////////////////////////////////////////////////////
void RopeNode::
render_billboard(CullTraverser *trav, CullTraverserData &data,
NurbsCurveResult *result) {
const TransformState *net_transform = data._net_transform;
const TransformState *camera_transform = trav->get_camera_transform();
CPT(TransformState) rel_transform =
net_transform->invert_compose(camera_transform);
LVector3f camera_vec = LVector3f::forward() * rel_transform->get_mat();
float thickness = get_thickness();
float radius = thickness * 0.5f;
UVMode uv_mode = get_uv_mode();
LVecBase2f uv_scale = get_uv_scale();
// We can't just build one tristrip per segment. Instead, we should
// build one continuous tristrip for all connected segments, so we
// can stitch them together properly at the seams.
int num_verts = get_num_segs() + 1;
int num_segments = result->get_num_segments();
vector_Vertexf center_verts;
vector_int center_lengths;
vector_float center_t;
LPoint3f point;
int cur_length = 0;
for (int segment = 0; segment < num_segments; segment++) {
LPoint3f first_point;
result->eval_segment_point(segment, 0.0f, first_point);
if (cur_length == 0 || point != first_point) {
// If the first point of this segment is different from the last
// point of the previous segment, end the tristrip and store the
// point.
if (cur_length != 0) {
center_lengths.push_back(cur_length);
}
center_verts.push_back(first_point);
center_t.push_back(result->get_segment_t(segment, 0.0f));
cur_length = 1;
}
// Store all the remaining points in this segment.
for (int i = 1; i < num_verts; i++) {
float t = (float)i / (float)(num_verts - 1);
result->eval_segment_point(segment, t, point);
center_verts.push_back(point);
center_t.push_back(result->get_segment_t(segment, t));
cur_length++;
}
}
if (cur_length != 0) {
center_lengths.push_back(cur_length);
}
// Now we have stored one or more sequences of vertices down the
// center strips. Go back and convert them into actual tristrips.
PTA_Vertexf verts;
PTA_TexCoordf uvs;
PTA_int lengths;
int vi = 0;
int num_prims = 0;
float dist = 0.0f;
for (int i = 0; i < (int)center_lengths.size(); i++) {
int length = center_lengths[i];
for (int j = 0; j < length; j++) {
const Vertexf &point = center_verts[vi + j];
float t = center_t[vi + j];
LVector3f tangent;
// Rather than evaluating the curve for the tangent, we derive
// it from the neighboring points. This gives us better
// behavior at the endpoints, where the tangent might go to
// zero.
if (j == 0) {
tangent = center_verts[vi + j + 1] - point;
} else if (j == length - 1) {
tangent = point - center_verts[vi + j - 1];
} else {
tangent = center_verts[vi + j + 1] - center_verts[vi + j - 1];
}
LVector3f cross = normalize(tangent.cross(camera_vec));
cross *= radius;
verts.push_back(point + cross);
verts.push_back(point - cross);
switch (uv_mode) {
case UV_none:
break;
case UV_parametric:
uvs.push_back(TexCoordf(t * uv_scale[0], uv_scale[1]));
uvs.push_back(TexCoordf(t * uv_scale[0], 0.0f));
break;
case UV_distance:
if (j != 0) {
LVector3f vec = point - center_verts[vi + j - 1];
dist += vec.length();
}
uvs.push_back(TexCoordf(dist * uv_scale[0], thickness * uv_scale[1]));
uvs.push_back(TexCoordf(dist * uv_scale[0], 0.0f));
break;
case UV_distance2:
if (j != 0) {
LVector3f vec = point - center_verts[vi + j - 1];
dist += vec.length_squared();
}
uvs.push_back(TexCoordf(dist * uv_scale[0], thickness * uv_scale[1]));
uvs.push_back(TexCoordf(dist * uv_scale[0], 0.0f));
break;
}
}
vi += length;
lengths.push_back(length * 2);
num_prims++;
}
PT(Geom) geom = new GeomTristrip;
geom->set_num_prims(num_prims);
geom->set_coords(verts);
if (uv_mode != UV_none) {
geom->set_texcoords(uvs, G_PER_VERTEX);
}
geom->set_lengths(lengths);
CullableObject *object = new CullableObject(geom, data._state,
data._render_transform);
trav->get_cull_handler()->record_object(object);
}
////////////////////////////////////////////////////////////////////
// Function: RopeNode::register_with_read_factory
// Access: Public, Static

View File

@ -53,17 +53,46 @@ public:
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data);
PUBLISHED:
enum RenderMode {
RM_thread,
RM_billboard
};
enum UVMode {
UV_none,
UV_parametric,
UV_distance,
UV_distance2,
};
INLINE void set_curve(NurbsCurveEvaluator *curve);
INLINE NurbsCurveEvaluator *get_curve() const;
INLINE void set_render_mode(RenderMode render_mode);
INLINE RenderMode get_render_mode() const;
INLINE void set_uv_mode(UVMode uv_mode);
INLINE UVMode get_uv_mode() const;
INLINE void set_uv_scale(const LVecBase2f &uv_scale);
INLINE const LVecBase2f &get_uv_scale() const;
INLINE void set_num_segs(int num_segs);
INLINE int get_num_segs() const;
INLINE void set_thickness(float thickness);
INLINE float get_thickness() const;
BoundingVolume *reset_bound(const NodePath &rel_to);
protected:
virtual BoundingVolume *recompute_internal_bound();
private:
void render_thread(CullTraverser *trav, CullTraverserData &data,
NurbsCurveResult *result);
void render_billboard(CullTraverser *trav, CullTraverserData &data,
NurbsCurveResult *result);
private:
// This is the data that must be cycled between pipeline stages.
class EXPCL_PANDA CData : public CycleData {
@ -75,7 +104,11 @@ private:
virtual void fillin(DatagramIterator &scan, BamReader *manager);
PT(NurbsCurveEvaluator) _curve;
RenderMode _render_mode;
UVMode _uv_mode;
LVecBase2f _uv_scale;
int _num_segs;
float _thickness;
};
PipelineCycler<CData> _cycler;