Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'intern/cycles/subd')
-rw-r--r--intern/cycles/subd/subd_mesh.cpp247
-rw-r--r--intern/cycles/subd/subd_mesh.h16
2 files changed, 260 insertions, 3 deletions
diff --git a/intern/cycles/subd/subd_mesh.cpp b/intern/cycles/subd/subd_mesh.cpp
index 29e487cd5d9..0db20656f39 100644
--- a/intern/cycles/subd/subd_mesh.cpp
+++ b/intern/cycles/subd/subd_mesh.cpp
@@ -35,6 +35,251 @@
#include "util_debug.h"
#include "util_foreach.h"
+#ifdef WITH_OPENSUBDIV
+
+#include <osd/vertex.h>
+#include <osd/mesh.h>
+#include <osd/cpuComputeController.h>
+#include <osd/cpuVertexBuffer.h>
+#include <osd/cpuEvalLimitController.h>
+#include <osd/evalLimitContext.h>
+
+CCL_NAMESPACE_BEGIN
+
+/* typedefs */
+typedef OpenSubdiv::OsdVertex OsdVertex;
+typedef OpenSubdiv::FarMesh<OsdVertex> OsdFarMesh;
+typedef OpenSubdiv::FarMeshFactory<OsdVertex> OsdFarMeshFactory;
+typedef OpenSubdiv::HbrCatmarkSubdivision<OsdVertex> OsdHbrCatmarkSubdivision;
+typedef OpenSubdiv::HbrFace<OsdVertex> OsdHbrFace;
+typedef OpenSubdiv::HbrHalfedge<OsdVertex> OsdHbrHalfEdge;
+typedef OpenSubdiv::HbrMesh<OsdVertex> OsdHbrMesh;
+typedef OpenSubdiv::HbrVertex<OsdVertex> OsdHbrVertex;
+typedef OpenSubdiv::OsdCpuComputeContext OsdCpuComputeContext;
+typedef OpenSubdiv::OsdCpuComputeController OsdCpuComputeController;
+typedef OpenSubdiv::OsdCpuEvalLimitContext OsdCpuEvalLimitContext;
+typedef OpenSubdiv::OsdCpuEvalLimitController OsdCpuEvalLimitController;
+typedef OpenSubdiv::OsdCpuVertexBuffer OsdCpuVertexBuffer;
+typedef OpenSubdiv::OsdEvalCoords OsdEvalCoords;
+typedef OpenSubdiv::OsdVertexBufferDescriptor OsdVertexBufferDescriptor;
+
+/* OpenSubdiv Patch */
+
+class OpenSubdPatch : public Patch {
+public:
+ int face_id;
+
+ OpenSubdPatch(OsdFarMesh *farmesh, OsdCpuVertexBuffer *vbuf_base)
+ {
+ face_id = 0;
+
+ /* create buffers for evaluation */
+ vbuf_P = OsdCpuVertexBuffer::Create(3, 1);
+ vbuf_dPdu = OsdCpuVertexBuffer::Create(3, 1);
+ vbuf_dPdv = OsdCpuVertexBuffer::Create(3, 1);
+
+ P = vbuf_P->BindCpuBuffer();
+ dPdu = vbuf_dPdu->BindCpuBuffer();
+ dPdv = vbuf_dPdv->BindCpuBuffer();
+
+ /* setup evaluation context */
+ OsdVertexBufferDescriptor in_desc(0, 3, 3), out_desc(0, 3, 3); /* offset, length, stride */
+
+ evalctx = OsdCpuEvalLimitContext::Create(farmesh, false);
+ evalctx->GetVertexData().Bind(in_desc, vbuf_base, out_desc, vbuf_P, vbuf_dPdu, vbuf_dPdv);
+ }
+
+ ~OpenSubdPatch()
+ {
+ evalctx->GetVertexData().Unbind();
+
+ delete evalctx;
+ delete vbuf_P;
+ delete vbuf_dPdu;
+ delete vbuf_dPdv;
+ }
+
+ void eval(float3 *P_, float3 *dPdu_, float3 *dPdv_, float u, float v)
+ {
+ OsdEvalCoords coords;
+ coords.u = u;
+ coords.v = v;
+ coords.face = face_id;
+
+ evalctrl.EvalLimitSample<OsdCpuVertexBuffer,OsdCpuVertexBuffer>(coords, evalctx, 0);
+
+ *P_ = make_float3(P[0], P[1], P[2]);
+ if (dPdu_) *dPdu_ = make_float3(dPdv[0], dPdv[1], dPdv[2]);
+ if (dPdv_) *dPdv_ = make_float3(dPdu[0], dPdu[1], dPdu[2]);
+
+ /* optimize: skip evaluating derivatives when not needed */
+ /* todo: swapped derivatives, different winding convention? */
+ }
+
+ BoundBox bound()
+ {
+ /* not implemented */
+ BoundBox bbox = BoundBox::empty;
+ return bbox;
+ }
+
+ int ptex_face_id()
+ {
+ return face_id;
+ }
+
+protected:
+ OsdCpuEvalLimitController evalctrl;
+ OsdCpuEvalLimitContext *evalctx;
+ OsdCpuVertexBuffer *vbuf_P;
+ OsdCpuVertexBuffer *vbuf_dPdu;
+ OsdCpuVertexBuffer *vbuf_dPdv;
+ float *P;
+ float *dPdu;
+ float *dPdv;
+};
+
+/* OpenSubdiv Mesh */
+
+OpenSubdMesh::OpenSubdMesh()
+{
+ /* create osd mesh */
+ static OsdHbrCatmarkSubdivision catmark;
+ OsdHbrMesh *hbrmesh = new OsdHbrMesh(&catmark);
+
+ /* initialize class */
+ num_verts = 0;
+ num_ptex_faces = 0;
+ _hbrmesh = (void*)hbrmesh;
+}
+
+OpenSubdMesh::~OpenSubdMesh()
+{
+ OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh;
+
+ if(hbrmesh)
+ delete hbrmesh;
+}
+
+void OpenSubdMesh::add_vert(const float3& co)
+{
+ OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh;
+
+ OsdVertex v;
+ positions.push_back(co.x);
+ positions.push_back(co.y);
+ positions.push_back(co.z);
+ hbrmesh->NewVertex(num_verts++, v);
+}
+
+void OpenSubdMesh::add_face(int v0, int v1, int v2)
+{
+ int index[3] = {v0, v1, v2};
+ return add_face(index, 3);
+}
+
+void OpenSubdMesh::add_face(int v0, int v1, int v2, int v3)
+{
+ int index[4] = {v0, v1, v2, v3};
+ add_face(index, 4);
+}
+
+void OpenSubdMesh::add_face(int *index, int num)
+{
+ OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh;
+
+#ifndef NDEBUG
+ /* sanity checks */
+ for(int j = 0; j < num; j++) {
+ OsdHbrVertex *origin = hbrmesh->GetVertex(index[j]);
+ OsdHbrVertex *destination = hbrmesh->GetVertex(index[(j+1)%num]);
+ OsdHbrHalfEdge *opposite = destination->GetEdge(origin);
+
+ if(origin==NULL || destination==NULL)
+ assert("An edge was specified that connected a nonexistent vertex\n");
+
+ if(origin == destination)
+ assert("An edge was specified that connected a vertex to itself\n");
+
+ if(opposite && opposite->GetOpposite())
+ assert("A non-manifold edge incident to more than 2 faces was found\n");
+
+ if(origin->GetEdge(destination))
+ assert("An edge connecting two vertices was specified more than once."
+ "It's likely that an incident face was flipped\n");
+ }
+#endif
+
+ OsdHbrFace *face = hbrmesh->NewFace(num, index, 0);
+
+ /* this is required for limit eval patch table? */
+ face->SetPtexIndex(num_ptex_faces);
+
+ if(num == 4)
+ num_ptex_faces++;
+ else
+ num_ptex_faces += num;
+}
+
+bool OpenSubdMesh::finish()
+{
+ OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh;
+
+ /* finish hbr mesh construction */
+ hbrmesh->SetInterpolateBoundaryMethod(OsdHbrMesh::k_InterpolateBoundaryEdgeOnly);
+ hbrmesh->Finish();
+
+ return true;
+}
+
+void OpenSubdMesh::tessellate(DiagSplit *split)
+{
+ if (num_ptex_faces == 0)
+ return;
+
+ const int level = 3;
+ const bool requirefvar = false;
+
+ /* convert HRB to FAR mesh */
+ OsdHbrMesh *hbrmesh = (OsdHbrMesh*)_hbrmesh;
+
+ OsdFarMeshFactory meshFactory(hbrmesh, level, true);
+ OsdFarMesh *farmesh = meshFactory.Create(requirefvar);
+ int num_hbr_verts = hbrmesh->GetNumVertices();
+
+ delete hbrmesh;
+ hbrmesh = NULL;
+ _hbrmesh = NULL;
+
+ /* refine HBR mesh with vertex coordinates */
+ OsdCpuComputeController *compute_controller = new OsdCpuComputeController();
+ OsdCpuComputeContext *compute_context = OsdCpuComputeContext::Create(farmesh);
+
+ OsdCpuVertexBuffer *vbuf_base = OsdCpuVertexBuffer::Create(3, num_hbr_verts);
+ vbuf_base->UpdateData(&positions[0], 0, num_verts);
+
+ compute_controller->Refine(compute_context, farmesh->GetKernelBatches(), vbuf_base);
+ compute_controller->Synchronize();
+
+ /* split & dice patches */
+ OpenSubdPatch patch(farmesh, vbuf_base);
+
+ for(int f = 0; f < num_ptex_faces; f++) {
+ patch.face_id = f;
+ split->split_quad(&patch);
+ }
+
+ /* clean up */
+ delete farmesh;
+ delete compute_controller;
+ delete compute_context;
+ delete vbuf_base;
+}
+
+CCL_NAMESPACE_END
+
+#else /* WITH_OPENSUBDIV */
+
CCL_NAMESPACE_BEGIN
/* Subd Vertex */
@@ -169,3 +414,5 @@ void SubdMesh::tessellate(DiagSplit *split)
CCL_NAMESPACE_END
+#endif /* WITH_OPENSUBDIV */
+
diff --git a/intern/cycles/subd/subd_mesh.h b/intern/cycles/subd/subd_mesh.h
index 96557692f05..f6aefc20318 100644
--- a/intern/cycles/subd/subd_mesh.h
+++ b/intern/cycles/subd/subd_mesh.h
@@ -35,8 +35,10 @@
CCL_NAMESPACE_BEGIN
+#ifndef WITH_OPENSUBDIV
class SubdVert;
class SubdFace;
+#endif
class DiagSplit;
class Mesh;
@@ -46,9 +48,6 @@ class Mesh;
class SubdMesh
{
public:
- vector<SubdVert*> verts;
- vector<SubdFace*> faces;
-
SubdMesh();
~SubdMesh();
@@ -60,6 +59,17 @@ public:
bool finish();
void tessellate(DiagSplit *split);
+
+protected:
+#ifdef WITH_OPENSUBDIV
+ void *_hbrmesh;
+ vector<float> positions;
+ int num_verts, num_ptex_faces;
+#else
+ vector<SubdVert*> verts;
+ vector<SubdFace*> faces;
+#endif
+
};
CCL_NAMESPACE_END