Merge remote-tracking branch 'origin/dev' into rc/v3_4_0

This commit is contained in:
David G Yu 2019-06-24 20:19:28 -07:00
commit 1b556809c3
84 changed files with 3084 additions and 2453 deletions

View File

@ -87,6 +87,8 @@ if (DOCUTILS_FOUND AND PYTHONINTERP_FOUND)
intro.rst intro.rst
license.rst license.rst
mod_notes.rst mod_notes.rst
mtlviewer.rst
mtlptexviewer.rst
osd_overview.rst osd_overview.rst
osd_shader_interface.rst osd_shader_interface.rst
porting.rst porting.rst

View File

@ -38,20 +38,26 @@ of the software.
:widths: 50 50 :widths: 50 50
* - | `glViewer <glviewer.html>`_ * - | `glViewer <glviewer.html>`_
| `glFVarViewer <glfvarviewer.html>`_
| `glEvalLimit <glevallimit.html>`_ | `glEvalLimit <glevallimit.html>`_
| `glPaintTest <glpainttest.html>`_
| `glPtexViewer <glptexviewer.html>`_
- | `glFVarViewer <glfvarviewer.html>`_
| `glStencilViewer <glstencilviewer.html>`_ | `glStencilViewer <glstencilviewer.html>`_
- | `glPtexViewer <glptexviewer.html>`_
| `glPaintTest <glpainttest.html>`_
| `glShareTopology <glsharetopology.html>`_ | `glShareTopology <glsharetopology.html>`_
.. list-table:: **DirectX examples** .. list-table:: **DirectX examples**
:class: quickref :class: quickref
:widths: 50 50
* - | `dxViewer <dxviewer.html>`_ * - | `dxViewer <dxviewer.html>`_
- | `dxPtexViewer <dxptexviewer.html>`_ - | `dxPtexViewer <dxptexviewer.html>`_
.. list-table:: **Metal examples**
:class: quickref
:widths: 50 50
* - | `mtlViewer <mtlviewer.html>`_
- | `mtlPtexViewer <mtlptexviewer.html>`_
---- ----
Common Command Line Options Common Command Line Options

View File

@ -35,7 +35,7 @@ SYNOPSIS
.. parsed-literal:: .. parsed-literal::
:class: codefhead :class: codefhead
**dxPtexViewer** [**-f**] [**-l** *isolation level*] [**-c** *animation loops*] [**-y**] **dxPtexViewer** [**-f**] [**-yup**] [**-u**] [**-a**] [**-l** *isolation level*] [**-c** *animation loops*]
[**-e** *environment map*] [**-d** *HDR diffuse map*] [**-s** *HDR specular map*] [**-e** *environment map*] [**-d** *HDR diffuse map*] [**-s** *HDR specular map*]
[**--disp** *displacement scale*] [**--disp** *displacement scale*]
*ptex color file* *ptex color file*
@ -51,7 +51,11 @@ DESCRIPTION
with color, displacement, occlusion and specular ptex maps. Multiple controls with color, displacement, occlusion and specular ptex maps. Multiple controls
are available to experiment with the algorithms. are available to experiment with the algorithms.
.. include:: under_development.rst .. image:: images/dxptexviewer.png
:width: 400px
:align: center
:target: images/dxptexviewer.png
OPTIONS OPTIONS
@ -98,7 +102,7 @@ for the subset of common options supported here.
the data contained in all the ptex files !) the data contained in all the ptex files !)
Keyboard Controls KEYBOARD CONTROLS
================= =================
.. code:: c++ .. code:: c++

View File

@ -35,8 +35,8 @@ SYNOPSIS
.. parsed-literal:: .. parsed-literal::
:class: codefhead :class: codefhead
**dxViewer** [**-u**] [**-a**] [**-l** *refinement level*] [**-c** *animation loops*] **dxViewer** [**-f**] [**-yup**] [**-u**] [**-a**] [**-l** *refinement level*] [**-c** *animation loops*]
*objfile(s)* [**-anim**] [**-catmark**] [**-loop**] [**-bilinear**] *objfile(s)* [**-catmark**] [**-loop**] [**-bilinear**]
DESCRIPTION DESCRIPTION
=========== ===========
@ -50,12 +50,6 @@ shapes. Multiple controls are available to experiment with the algorithms.
:align: center :align: center
:target: images/dxviewer.png :target: images/dxviewer.png
.. container:: notebox
* **Note:**
dxViewer requires Microsoft's DirectX D3D11 SDK
OPTIONS OPTIONS
======= =======

View File

@ -294,42 +294,21 @@ to refine primvar data.
Far::PatchTable Far::PatchTable
================ ================
The patch table is a serialized topology representation. This container is PatchTable is the collection of patches derived from the refined faces of a particular mesh topology.
generated using *Far::PatchTableFactory* from an instance
*Far::TopologyRefiner* after a refinement has been applied. The
FarPatchTableFactory traverses the data-structures of the TopologyRefiner and
serializes the sub-faces into collections of bi-linear and bi-cubic patches as
dictated by the refinement mode (uniform or adaptive). The patches are then
sorted into arrays based on their types.
.. container:: notebox This collection is created using *Far::PatchTableFactory* from an instance
of *Far::TopologyRefiner* after refinement has been applied.
**Release Notes (3.0.0)**
The organization and API of Far::PatchTable is likely to change
in the 3.1 release to accommodate additional functionality including:
smooth face-varying interpolation on patches, and dynamic feature
adaptive isolation (DFAS), and patch evaluation of Loop subdivision
surfaces.
Patch Arrays Patch Arrays
************ ************
The patch table is a collection of control vertex indices. Meshes are decomposed The PatchTable is organized into patch arrays. All patches in each array have
into a collection of patches, which can be of different types. Each type the same type except for face-varying patch arrays which may have a mix of regular and irregular patch types.
has different requirements for the internal organization of its
control-vertices. A PatchArray contains a sequence of multiple patches that
share a common set of attributes.
While all patches in a PatchArray will have the same type, each patch in the The *PatchDescriptor* provides the fundamental description of a patch, including the number of control points per patch as well as the basis for patch evaluation.
array is associated with a distinct *PatchParam* which specifies additional
information about the individual patch.
Each PatchArray contains a patch *Descriptor* that provides the fundamental Each patch in the array is associated with a *PatchParam* which
description of the patches in the array. specifies additional information about the individual patch.
The PatchArray *ArrayRange* provides the indices necessary to track the records
of individual patches in the table.
.. image:: images/far_patchtables.png .. image:: images/far_patchtables.png
:align: center :align: center
@ -350,19 +329,21 @@ PatchTable:
+---------------------+------+---------------------------------------------+ +---------------------+------+---------------------------------------------+
| LINES | 2 | Lines : useful for cage drawing | | LINES | 2 | Lines : useful for cage drawing |
+---------------------+------+---------------------------------------------+ +---------------------+------+---------------------------------------------+
| QUADS | 4 | Bi-linear quads-only patches | | QUADS | 4 | Bi-linear quadrilaterals |
+---------------------+------+---------------------------------------------+ +---------------------+------+---------------------------------------------+
| TRIANGLES | 3 | Bi-linear triangles-only mesh | | TRIANGLES | 3 | Linear triangles |
+---------------------+------+---------------------------------------------+ +---------------------+------+---------------------------------------------+
| LOOP | n/a | Loop patch (currently unsupported) | | LOOP | 12 | Quartic triangular Box-spline patches |
+---------------------+------+---------------------------------------------+ +---------------------+------+---------------------------------------------+
| REGULAR | 16 | B-spline Basis patches | | REGULAR | 16 | Bi-cubic B-spline patches |
+---------------------+------+---------------------------------------------+ +---------------------+------+---------------------------------------------+
| GREGORY | 4 | Legacy Gregory patches | | GREGORY | 4 | Legacy Gregory patches |
+---------------------+------+---------------------------------------------+ +---------------------+------+---------------------------------------------+
| GREGORY_BOUNDARY | 4 | Legacy Gregory Boundary patches | | GREGORY_BOUNDARY | 4 | Legacy Gregory Boundary patches |
+---------------------+------+---------------------------------------------+ +---------------------+------+---------------------------------------------+
| GREGORY_BASIS | 20 | Gregory Basis patches | | GREGORY_BASIS | 20 | Bi-cubic quadrilateral Gregory patches |
+---------------------+------+---------------------------------------------+
| GREGORY_TRIANGLE | 18 | Quartic triangular Gregory patches |
+---------------------+------+---------------------------------------------+ +---------------------+------+---------------------------------------------+
@ -372,6 +353,10 @@ table as well as the method used to evaluate values.
Patch Parameterization Patch Parameterization
********************** **********************
Here we describe the encoding of the patch parameterization for
quadrilateral patches. The encoding for triangular patches is similar,
please see the API documentation of Far::PatchParam for details.
Each patch represents a specific portion of the parametric space of the Each patch represents a specific portion of the parametric space of the
coarse topological face identified by the PatchParam FaceId. As topological coarse topological face identified by the PatchParam FaceId. As topological
refinement progresses through successive levels, each resulting patch refinement progresses through successive levels, each resulting patch
@ -435,11 +420,9 @@ sharpness parameter.
.. container:: notebox .. container:: notebox
**Release Notes (3.0.0)** **Release Notes (3.x)**
Currently, the crease sharpness parameter is encoded as a separate Evaluation
PatchArray within the PatchTable. This parameter may be combined
with the other PatchParam values in future releases. Also, evaluation
of single-crease patches is currently only implemented for OSD patch of single-crease patches is currently only implemented for OSD patch
drawing, but we expect to implement support in all of the evaluation drawing, but we expect to implement support in all of the evaluation
code paths for future releases. code paths for future releases.
@ -453,15 +436,6 @@ adaptively to the points of the coarse mesh. However, the final patches
generated from irregular faces, e.g. patches incident on an extraordinary generated from irregular faces, e.g. patches incident on an extraordinary
vertex might have a representation which requires additional local points. vertex might have a representation which requires additional local points.
.. container:: notebox
**Release Notes (3.0.0)**
Currently, representations which require local points also require
the use of a StencilTable to compute the values of local points.
This requirement, as well as the rest of the API related to local
points may change in future releases.
Legacy Gregory Patches Legacy Gregory Patches
********************** **********************
@ -472,15 +446,6 @@ Legacy Gregory patches are used, the PatchTable must also have an alternative
representation of the mesh topology encoded as a vertex valence table representation of the mesh topology encoded as a vertex valence table
and a quad offsets table. and a quad offsets table.
.. container:: notebox
**Release Notes (3.0.0)**
The encoding and support for Legacy Gregory patches may change
in future releases. The current encoding of the vertex valence
and quad offsets tables may be prohibitively expensive for some
use cases.
Far::StencilTable Far::StencilTable
================== ==================

Binary file not shown.

Before

Width:  |  Height:  |  Size: 240 KiB

After

Width:  |  Height:  |  Size: 7.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 232 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 232 KiB

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 232 KiB

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

BIN
documentation/images/dxviewer.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 KiB

After

Width:  |  Height:  |  Size: 580 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 359 KiB

After

Width:  |  Height:  |  Size: 424 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 343 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 KiB

After

Width:  |  Height:  |  Size: 270 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 KiB

After

Width:  |  Height:  |  Size: 556 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 KiB

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 194 KiB

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 964 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

After

Width:  |  Height:  |  Size: 353 KiB

View File

@ -0,0 +1,61 @@
..
Copyright 2019 Pixar
Licensed under the Apache License, Version 2.0 (the "Apache License")
with the following modification; you may not use this file except in
compliance with the Apache License and the following modification to it:
Section 6. Trademarks. is deleted and replaced with:
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor
and its affiliates, except as required to comply with Section 4(c) of
the License and to reproduce the content of the NOTICE file.
You may obtain a copy of the Apache License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the Apache License with the above modification is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the Apache License for the specific
language governing permissions and limitations under the Apache License.
mtlPtexViewer
-------------
.. contents::
:local:
:backlinks: none
SYNOPSIS
========
.. parsed-literal::
:class: codefhead
**open** **mtlPtexViewer.app** **--args** [**-yup**] [**-u**] [**-a**] [**-l** *isolation level*]
*ptex color file*
*ptex displacement file*
DESCRIPTION
===========
``mtlPtexViewer`` is a stand-alone application demonstrating shading with color and displacement ptex maps. Multiple controls are available to experiment with the algorithms.
.. image:: images/mtlptexviewer.png
:width: 400px
:align: center
:target: images/mtlptexviewer.png
KEYBOARD CONTROLS
=================
.. code:: c++
q : quit
f : fit frame
+/- : increase / decrease tessellation rate
.. include:: examples_see_also.rst

View File

@ -0,0 +1,75 @@
..
Copyright 2019 Pixar
Licensed under the Apache License, Version 2.0 (the "Apache License")
with the following modification; you may not use this file except in
compliance with the Apache License and the following modification to it:
Section 6. Trademarks. is deleted and replaced with:
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor
and its affiliates, except as required to comply with Section 4(c) of
the License and to reproduce the content of the NOTICE file.
You may obtain a copy of the Apache License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the Apache License with the above modification is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the Apache License for the specific
language governing permissions and limitations under the Apache License.
mtlViewer
---------
.. contents::
:local:
:backlinks: none
SYNOPSIS
========
.. parsed-literal::
:class: codefhead
**open** **mtlViewer.app** **--args** [**-yup**] [**-u**] [**-a**] [**-l** *refinement level*]
*objfile(s)* [**-catmark**] [**-loop**] [**-bilinear**]
DESCRIPTION
===========
``mtlViewer`` is a stand-alone application that showcases the application of
uniform and feature adaptive subdivision schemes to a collection of geometric
shapes. Multiple controls are available to experiment with the algorithms.
+----------------------------------------------------+
| .. image:: images/mtlviewer.png |
| :width: 400px |
| :align: center |
| :target: images/mtlviewer.png |
| |
| mtlViewer running on macOS |
+----------------------------------------------------+
+----------------------------------------------------+
| .. image:: images/mtlviewer_ios.png |
| :width: 400px |
| :align: center |
| :target: images/mtlviewer_ios.png |
| |
| mtlViewer running on iOS |
+----------------------------------------------------+
KEYBOARD CONTROLS
=================
.. code:: c++
q : quit
f : fit frame
+/- : increase / decrease tessellation rate
.. include:: examples_see_also.rst

View File

@ -42,8 +42,8 @@ The main roles of **Osd** are:
Compute limit surfaces by limit stencils on CPU/GPU backends Compute limit surfaces by limit stencils on CPU/GPU backends
- **Limit Evaluation with PatchTable** - **Limit Evaluation with PatchTable**
Compute limit surfaces by patch evaluation on CPU/GPU backends Compute limit surfaces by patch evaluation on CPU/GPU backends
- **OpenGL/DX11 Drawing with hardware tessellation** - **OpenGL/DX11/Metal Drawing with hardware tessellation**
Provide GLSL/HLSL tessellation functions for patch table Provide GLSL/HLSL/Metal tessellation functions for patch table
- **Interleaved/Batched buffer configuration** - **Interleaved/Batched buffer configuration**
Provide consistent buffer descriptor to deal with arbitrary buffer layout. Provide consistent buffer descriptor to deal with arbitrary buffer layout.
- **Cross-Platform Implementation** - **Cross-Platform Implementation**
@ -98,7 +98,8 @@ as a stencil tables as long as Evaluator::EvalStencils() can access the necessar
+-----------------------------+-----------------------+-------------------------+ +-----------------------------+-----------------------+-------------------------+
| DX11 ComputeShader (GPU) | D3D11ComputeEvaluator | D3D11StencilTable | | DX11 ComputeShader (GPU) | D3D11ComputeEvaluator | D3D11StencilTable |
+-----------------------------+-----------------------+-------------------------+ +-----------------------------+-----------------------+-------------------------+
| Metal (GPU) | MTLComputeEvaluator | MTLStencilTable |
+-----------------------------+-----------------------+-------------------------+
Limit Stencil Evaluation Limit Stencil Evaluation
======================== ========================
@ -141,17 +142,18 @@ Once all control vertices and local points are resolved by the stencil evaluatio
| DX11 ComputeShader (GPU) | | D3D11ComputeEvaluator | D3D11PatchTable | | DX11 ComputeShader (GPU) | | D3D11ComputeEvaluator | D3D11PatchTable |
| | | (*)not yet supported | | | | | (*)not yet supported | |
+-----------------------------+-------------------------+-------------------------+ +-----------------------------+-------------------------+-------------------------+
| Metal ComputeShader (GPU) | | MTLComputeEvaluator | MTLPatchTable |
+-----------------------------+-------------------------+-------------------------+
.. container:: notebox .. container:: notebox
**Release Notes (3.0.0)** **Release Notes (3.x)**
* GPU limit evaluation backends (Evaluator::EvalPatches()) only support * Osd evaluation backends (Evaluator::EvalPatches()) do not support
BSpline patches. Clients need to specify BSpline approximation for endcap evaluation of single-crease or Legacy Gregory patch types.
when creating a patch table. See `end capping <far_overview.html#endcap>`__.
OpenGL/DX11 Drawing with Hardware Tessellation OpenGL/DX11/Metal Drawing with Hardware Tessellation
============================================== ====================================================
One of the most interesting use cases of the **Osd** layer is realtime drawing One of the most interesting use cases of the **Osd** layer is realtime drawing
of subdivision surfaces using hardware tessellation. This is somewhat similar to of subdivision surfaces using hardware tessellation. This is somewhat similar to
@ -265,6 +267,8 @@ The methods that need to be implemented for the Evaluators are:
+-----------------------+------------------------+------------------+ +-----------------------+------------------------+------------------+
| D3D11ComputeEvaluator | D3D11 UAV | BindD3D11UAV() | | D3D11ComputeEvaluator | D3D11 UAV | BindD3D11UAV() |
+-----------------------+------------------------+------------------+ +-----------------------+------------------------+------------------+
| MTLComputeEvaluator | MTLBuffer | BindMTLBuffer() |
+-----------------------+------------------------+------------------+
The buffers can use these methods as a trigger of interop. **Osd** provides a default The buffers can use these methods as a trigger of interop. **Osd** provides a default
implementation of interop buffer for most of the backend combinations. implementation of interop buffer for most of the backend combinations.

View File

@ -50,8 +50,8 @@ The following is a minimal example of GLSL code explaining how client shader cod
uses OpenSubdiv shader functions to tessellate patches of a patch table. uses OpenSubdiv shader functions to tessellate patches of a patch table.
Tessellation Control Shader Example (for BSpline patches) Tessellation Control Shader Example (for B-Spline patches)
********************************************************* **********************************************************
.. code:: glsl .. code:: glsl
@ -88,8 +88,8 @@ Tessellation Control Shader Example (for BSpline patches)
Tessellation Evaluation Shader Example (for BSpline patches) Tessellation Evaluation Shader Example (for B-Spline patches)
************************************************************ *************************************************************
.. code:: glsl .. code:: glsl
@ -160,7 +160,8 @@ are stored in a OsdPerPatchVertexGreogryBasis struct.
.. code:: glsl .. code:: glsl
void OsdComputePerPatchVertexGregoryBasis( void
OsdComputePerPatchVertexGregoryBasis(
ivec3 patchParam, int ID, vec3 cv, out OsdPerPatchVertexGregoryBasis result) ivec3 patchParam, int ID, vec3 cv, out OsdPerPatchVertexGregoryBasis result)
The tessellation evaluation shader takes an array of OsdPerPatchVertexGregoryBasis struct, The tessellation evaluation shader takes an array of OsdPerPatchVertexGregoryBasis struct,
@ -174,6 +175,54 @@ and then evaluates the patch using the OsdEvalPatchGregory() function.
out vec3 N, out vec3 dNu, out vec3 dNv) out vec3 N, out vec3 dNu, out vec3 dNv)
Box-spline Triangle Patch
*************************
While regular triangle patches are expressed as triangular box-spline patches in Far::PatchTable,
the **Osd** shader converts them into triangular Bezier patches for consistency.
This conversion is performed in the tessellation control stage. The boundary edge evaluation is resolved during this conversion.
OsdComputePerPatchVertexBoxSplineTriangle() can be used for this process.
The resulting Bezier control vertices are stored in OsdPerPatchVertexBezier struct.
.. code:: glsl
void
OsdComputePerPatchVertexBoxSplineTriangle(
ivec3 patchParam, int ID, vec3 cv[12], out OsdPerPatchVertexBezier result);
The tessellation evaluation shader takes an array of OsdPerPatchVertexBezier struct,
and then evaluates the patch using the OsdEvalPatchBezierTriangle() function.
.. code:: glsl
void OsdEvalPatchBezierTriangle(ivec3 patchParam, vec2 UV,
OsdPerPatchVertexBezier cv[15],
out vec3 P, out vec3 dPu, out vec3 dPv,
out vec3 N, out vec3 dNu, out vec3 dNv)
Gregory Triangle Patch
**********************
OsdComputePerPatchVertexGregoryBasis() can be used for the quartic triangular Gregory patches (although no basis conversion involved for the Gregory triangle patches) and the resulting vertices are stored in a OsdPerPatchVertexGreogryBasis struct.
.. code:: glsl
void
OsdComputePerPatchVertexGregoryBasis(
ivec3 patchParam, int ID, vec3 cv, out OsdPerPatchVertexGregoryBasis result)
The tessellation evaluation shader takes an array of OsdPerPatchVertexGregoryBasis struct,
and then evaluates the patch using the OsdEvalPatchGregoryTriangle() function.
.. code:: glsl
void
OsdEvalPatchGregoryTriangle(ivec3 patchParam, vec2 UV, vec3 cv[18],
out vec3 P, out vec3 dPu, out vec3 dPv,
out vec3 N, out vec3 dNu, out vec3 dNv)
Legacy Gregory Patch (2.x compatibility) Legacy Gregory Patch (2.x compatibility)
**************************************** ****************************************
@ -190,12 +239,6 @@ Tessellation levels
**Osd** provides both uniform and screen-space adaptive tessellation level computation. **Osd** provides both uniform and screen-space adaptive tessellation level computation.
Uniform tessellation
OsdGetTessLevelsUniform()
Screen-space adaptive tessellation
OsdGetTessLevelsAdaptiveLimitPoints()
Because of the nature of `feature adaptive subdivision <far_overview.html>`__, Because of the nature of `feature adaptive subdivision <far_overview.html>`__,
we need to pay extra attention for a patch's outer tessellation level for the screen-space we need to pay extra attention for a patch's outer tessellation level for the screen-space
adaptive case so that cracks don't appear. adaptive case so that cracks don't appear.
@ -212,31 +255,63 @@ as separate levels for the two segments of the edge split at the middle.
.. image:: images/osd_shader_transition.png .. image:: images/osd_shader_transition.png
Then the tessellation evaluation shader takes gl_TessCoord and those two values, and remaps Tessellation levels at each tessellated vertex
gl_TessCoord using OsdGetTessParameterization() to ensure the parameters are consistent **********************************************
The tessellation evaluation shader takes gl_TessCoord and those two values, and remaps
gl_TessCoord using OsdGetTessParameterization() or OsdGetTessLevelParameterizationTriangle() to ensure the parameters are consistent
across adjacent patches. across adjacent patches.
.. code:: glsl
vec2 OsdGetTessParameterization(vec2 uv, vec4 tessOuterLo, vec4 tessOuterHi);
.. code:: glsl
vec2 OsdGetTessParameterizationTriangle(vec3 uvw, vec4 tessOuterLo, vec4 tessOuterHi);
.. image:: images/osd_shader_param_remap.png .. image:: images/osd_shader_param_remap.png
.. code:: glsl Tessellation levels computed at each patch
******************************************
vec2 OsdGetTessParameterization(vec2 uv, vec4 tessOuterLo, vec4 tessOuterHi) These tessellation levels can be computed the corresponding method in the tesselation control shader. Note that these functions potentially requires all bezier control
These tessellation levels can be computed by OsdGetTessLevelsAdaptiveLimitPoints()
in the tessellation control shader. Note that this function requires all 16 bezier control
points, you need to call barrier() to ensure the conversion is done for all invocations. points, you need to call barrier() to ensure the conversion is done for all invocations.
See osd/glslPatchBSpline.glsl for more details. See osd/glslPatchBSpline.glsl for more details.
Uniform
~~~~~~~
.. code:: glsl .. code:: glsl
void OsdGetTessLevelsAdaptiveLimitPoints(OsdPerPatchVertexBezier cpBezier[16], void
ivec3 patchParam, OsdGetTessLevelsUniform(ivec3 patchParam,
out vec4 tessLevelOuter, out vec2 tessLevelInner, out vec4 tessLevelOuter, out vec2 tessLevelInner,
out vec4 tessOuterLo, out vec4 tessOuterHi) out vec4 tessOuterLo, out vec4 tessOuterHi)
.. container:: notebox .. code:: glsl
**Release Notes (3.0.0)** void
OsdGetTessLevelsUniformTriangle(ivec3 patchParam,
out vec4 tessLevelOuter, out vec2 tessLevelInner,
out vec4 tessOuterLo, out vec4 tessOuterHi)
* Currently OsdGetTessParameterization doesn't support fraction spacing.
It will be fixed in a future release. Screenspace
~~~~~~~~~~~
.. code:: glsl
void OsdEvalPatchBezierTessLevels(
OsdPerPatchVertexBezier cpBezier[16],
ivec3 patchParam,
out vec4 tessLevelOuter, out vec2 tessLevelInner,
out vec4 tessOuterLo, out vec4 tessOuterHi);
.. code:: glsl
void OsdEvalPatchBezierTriangleTessLevels(
vec3 cv[15],
ivec3 patchParam,
out vec4 tessLevelOuter, out vec2 tessLevelInner,
out vec4 tessOuterLo, out vec4 tessOuterHi);

View File

@ -22,8 +22,8 @@
language governing permissions and limitations under the Apache License. language governing permissions and limitations under the Apache License.
Overview of Release 3.4 (draft) Overview of Release 3.4
=============================== =======================
.. contents:: .. contents::
:local: :local:
@ -34,9 +34,8 @@ New Features
Triangular Patches for Loop Subdivision Triangular Patches for Loop Subdivision
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for the drawing and evaluation of Loop subdivision meshes with
Added support for drawing and evaluation of Loop subdivision meshes with triangular patches was added. This includes the full set of Far and Osd interfaces
triangular patches. This includes the full set of Far and Osd interfaces
for both evaluation and drawing. for both evaluation and drawing.
+-----------------------------------+-----------------------------------+ +-----------------------------------+-----------------------------------+
@ -56,11 +55,18 @@ including creases, face-varying patches, non-manifold topology, etc.
| :target: images/loop_rel_3.png| :target: images/loop_rel_4.png | | :target: images/loop_rel_3.png| :target: images/loop_rel_4.png |
+----------------------------------+----------------------------------------------------------------+ +----------------------------------+----------------------------------------------------------------+
Quartic triangular patches are used to exactly match the limit surface of The long standing requirement that Loop meshes be purely triangular remains, as
Loop subdivision where the mesh is regular and approximated where irregular. Loop subdivision is not defined for non-triangular faces. And as is the case with
As is the case with use of the Catmark scheme, application of Loop subdivision the use of the Catmark scheme, application of Loop subdivision to dense, poorly
to dense, poorly modeled meshes may lead to unexpectedly poor performance or modeled meshes may lead to unexpectedly poor performance and/or surface quality.
surface quality.
The patch representation used for Loop subdivision is intended to exactly match the
underlying limit surface where regular, and so uses quartic triangular Box-splines.
This is in contrast to approaches that use simpler patches to approximate the Loop
limit surface everywhere. As with Catmark, Gregory patches are used to approximate
irregular areas. Though other choices are available that compromise surface
quality in favor of improved performance, they may be less effective with Loop than
they are with Catmark.
Major Improvements to Introductory Documentation Major Improvements to Introductory Documentation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -119,27 +125,6 @@ API Additions
See associated `Doxygen <doxy_html/index.html>`__ for full details. See associated `Doxygen <doxy_html/index.html>`__ for full details.
Osd::MeshBits
~~~~~~~~~~~~~
- enumeration MeshEndCapBilinearBasis
Osd::PatchArray
~~~~~~~~~~~~~~~
- GetDescriptorRegular()
- GetDescriptorIrregular()
- GetPatchTyperRegular()
- GetPatchTyperIrregular()
- GetStride()
Osd extensions common to all shaders
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- TBD
Far construction and refinement of topology
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- overloaded TopologyRefinerFactory::Create()
- extensions to TopologyRefiner::RefineAdaptive()
Far extensions for triangular patches Far extensions for triangular patches
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- enum PatchDescriptor::Type::GREGORY_TRIANGLE - enum PatchDescriptor::Type::GREGORY_TRIANGLE
@ -147,6 +132,11 @@ Far extensions for triangular patches
- PatchParam::UnnormalizeTriangle() - PatchParam::UnnormalizeTriangle()
- PatchParam::IsTriangleRotated() - PatchParam::IsTriangleRotated()
Construction and refinement of topology
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- overloaded TopologyRefinerFactory::Create()
- extensions to TopologyRefiner::RefineAdaptive()
Construction and interface of Far::PatchTable Construction and interface of Far::PatchTable
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- overloaded PatchTableFactory::Create() - overloaded PatchTableFactory::Create()
@ -190,6 +180,51 @@ Far member functions converted to templates for double precision
- PatchTable::GetLocalPointFaceVaryingStencilTable() - PatchTable::GetLocalPointFaceVaryingStencilTable()
- PatchMap::FindPatch() - PatchMap::FindPatch()
Osd::MeshBits
~~~~~~~~~~~~~
- enumeration MeshEndCapBilinearBasis
Osd::PatchArray
~~~~~~~~~~~~~~~
- GetDescriptorRegular()
- GetDescriptorIrregular()
- GetPatchTyperRegular()
- GetPatchTyperIrregular()
- GetStride()
Osd extensions for patch evaluation common to all shaders
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- struct OsdPatchArray and OsdPatchArrayInit()
- struct OsdPatchCoord and OsdPatchCoordInit()
- struct OsdPatchParam and OsdPatchParamInit()
- OsdPatchParamGetFaceId()
- OsdPatchParamGetU()
- OsdPatchParamGetV()
- OsdPatchParamGetTransition()
- OsdPatchParamGetBoundary()
- OsdPatchParamGetNonQuadRoot()
- OsdPatchParamGetDepth()
- OsdPatchParamGetParamFraction()
- OsdPatchParamIsRegular()
- OsdPatchParamIsTriangleRotated()
- OsdPatchParamNormalize()
- OsdPatchParamUnnormalize()
- OsdPatchParamNormalize(Triangle)
- OsdPatchParamUnnormalizeTriangle()
- OsdEvaluatePatchBasisNormalized()
- OsdEvaluatePatchBasis()
Osd extensions for patch tessellation common to all shaders
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- OsdInterpolatePatchCoordTriangle()
- OsdComputePerPatchVertexBoxSplineTriangle
- OsdEvalPatchBezierTriangle()
- OsdEvalPatchGregoryTriangle()
- OsdGetTessLevelsUniformTriangle()
- OsdEvalPatchBezierTessLevels()
- OsdEvalPatchBezierTriangleTessLevels()
- OsdGetTessParameterizationTriangle()
Other Changes Other Changes
------------- -------------

View File

@ -31,6 +31,9 @@
---- ----
Release 3.4
~~~~~~~~~~~
Release 3.4.0 - Jun 2019 Release 3.4.0 - Jun 2019
======================== ========================
@ -63,6 +66,9 @@ code and configuration improvements. For more information on the following, ple
- Fixed Far::StencilTable append when base StencilTable empty (GitHub #982) - Fixed Far::StencilTable append when base StencilTable empty (GitHub #982)
- Patches around non-manifold vertices now free of cracks (GitHub #1013) - Patches around non-manifold vertices now free of cracks (GitHub #1013)
Release 3.3
~~~~~~~~~~~
Release 3.3.3 - Jul 2018 Release 3.3.3 - Jul 2018
======================== ========================
@ -116,6 +122,9 @@ Release 3.3.0 is significant release adding an Osd implementation for Apple's Me
- Fixed several instances of local variable shadowing that could cause build warnings - Fixed several instances of local variable shadowing that could cause build warnings
- Updated continuous-integration build scripts and added testing on macOS - Updated continuous-integration build scripts and added testing on macOS
Release 3.2
~~~~~~~~~~~
Release 3.2.0 - Feb 2017 Release 3.2.0 - Feb 2017
======================== ========================
@ -134,6 +143,9 @@ Release 3.2.0 is a minor release containing API additions and bug fixes
**Bug Fixes** **Bug Fixes**
- Fixed a double delete of GL program in Osd::GLComputeEvaluator - Fixed a double delete of GL program in Osd::GLComputeEvaluator
Release 3.1
~~~~~~~~~~~
Release 3.1.1 - Jan 2017 Release 3.1.1 - Jan 2017
======================== ========================
@ -179,6 +191,9 @@ code and configuration improvements. For more information on the following, ple
- Fixed bug with refinement using Chaikin creasing - Fixed bug with refinement using Chaikin creasing
- Fixed bugs with HUD sliders in the example viewers - Fixed bugs with HUD sliders in the example viewers
Release 3.0
~~~~~~~~~~~
Release 3.0.5 - Mar 2016 Release 3.0.5 - Mar 2016
======================== ========================
@ -315,7 +330,8 @@ Release 3.0.0 RC1
supported. supported.
- The Osd layer was largely refactored. - The Osd layer was largely refactored.
Previous 2.x Release Notes Previous 2.x Release Notes
========================== ~~~~~~~~~~~~~~~~~~~~~~~~~~
`Previous releases <release_notes_2x.html>`_ `Previous releases <release_notes_2x.html>`_

View File

@ -139,8 +139,18 @@ the surface they define compared to the similar Bezier patch. The two patches i
that example actually represent exactly the same piece of surface -- each with a set that example actually represent exactly the same piece of surface -- each with a set
of control points having different effects on it. In mathematical terms, each control of control points having different effects on it. In mathematical terms, each control
point has a "basis function" associated with it that affects the surface in a particular point has a "basis function" associated with it that affects the surface in a particular
way when only that point is moved. It is these basis functions that often give rise way when only that point is moved:
to the names of the different patches.
+--------------------------------------+--------------------------------------+
| .. image:: images/basis_bspline.jpg | .. image:: images/basis_bezier.jpg |
| :align: center | :align: center |
| :width: 80% | :width: 80% |
| :target: images/basis_bspline.jpg | :target: images/basis_bezier.jpg |
| | |
| Bicubic B-Spline basis function | Bicubic Bezier basis funciton |
+--------------------------------------+--------------------------------------+
It is these basis functions that often give rise to the names of the different patches.
There are pros and cons to these different properties of the control points of patches, There are pros and cons to these different properties of the control points of patches,
which become more apparent as we assemble patches into piecewise surfaces. which become more apparent as we assemble patches into piecewise surfaces.
@ -635,8 +645,7 @@ involving topology (computing the weights) and combining the data separately.
| :width: 95% | :width: 95% | :width: 95% | | :width: 95% | :width: 95% | :width: 95% |
| :target: images/data_pose_1.jpg | :target: images/data_pose_2.jpg | :target: images/data_pose_3.jpg | | :target: images/data_pose_1.jpg | :target: images/data_pose_2.jpg | :target: images/data_pose_3.jpg |
+---------------------------------------+---------------------------------------+---------------------------------------+ +---------------------------------------+---------------------------------------+---------------------------------------+
| Three shapes resulting from three sets of positions for the a mesh of complex but fixed topology. | | Three shapes resulting from three sets of positions for a mesh of fixed topology. |
| (currently stand-in images until we have an animated character approved for publication) |
+---------------------------------------+---------------------------------------+---------------------------------------+ +---------------------------------------+---------------------------------------+---------------------------------------+
When the topology is fixed, enormous savings are possible by pre-computing information When the topology is fixed, enormous savings are possible by pre-computing information

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

File diff suppressed because it is too large Load Diff

View File

@ -31,16 +31,16 @@
#define FONT_TEXTURE_ROWS 8 #define FONT_TEXTURE_ROWS 8
#define FONT_CHAR_WIDTH (FONT_TEXTURE_WIDTH/FONT_TEXTURE_COLUMNS) #define FONT_CHAR_WIDTH (FONT_TEXTURE_WIDTH/FONT_TEXTURE_COLUMNS)
#define FONT_CHAR_HEIGHT (FONT_TEXTURE_HEIGHT/FONT_TEXTURE_ROWS) #define FONT_CHAR_HEIGHT (FONT_TEXTURE_HEIGHT/FONT_TEXTURE_ROWS)
#define FONT_CHECK_BOX_OFF 0x3 #define FONT_CHECK_BOX_OFF 0x2
#define FONT_CHECK_BOX_ON 0x4 #define FONT_CHECK_BOX_ON 0x3
#define FONT_RADIO_BUTTON_OFF 0x6 #define FONT_RADIO_BUTTON_OFF 0x4
#define FONT_RADIO_BUTTON_ON 0x7 #define FONT_RADIO_BUTTON_ON 0x5
#define FONT_SLIDER_LEFT 0x10 #define FONT_SLIDER_LEFT 0x10
#define FONT_SLIDER_MIDDLE 0x11 #define FONT_SLIDER_MIDDLE 0x11
#define FONT_SLIDER_RIGHT 0x12 #define FONT_SLIDER_RIGHT 0x12
#define FONT_SLIDER_CURSOR 0x7c #define FONT_SLIDER_CURSOR 0x13
#define FONT_ARROW_RIGHT 0x15 #define FONT_ARROW_RIGHT 0x14
#define FONT_ARROW_DOWN 0x17 #define FONT_ARROW_DOWN 0x15
extern unsigned char font_image[]; extern unsigned char font_image[];

View File

@ -556,10 +556,15 @@ Hud::Rebuild(int width, int height, int framebufferWidth, int framebufferHeight)
} }
} }
drawString(_staticVboSource, _windowWidth-80, _windowHeight-48, .5, .5, .5, // draw the character cells corresponding to the logo
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"); drawString(_staticVboSource, _windowWidth-128, _windowHeight-44, .5, .5, .5,
drawString(_staticVboSource, _windowWidth-80, _windowHeight-32, .5, .5, .5, "\x06\x07\x08\x09");
"\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"); drawString(_staticVboSource, _windowWidth-128, _windowHeight-28, .5, .5, .5,
"\x16\x17\x18\x19");
drawString(_staticVboSource, _windowWidth-92, _windowHeight-36, .5, .5, .5,
"\x0a\x0b\x0c\x0d");
drawString(_staticVboSource, _windowWidth-58, _windowHeight-36, .5, .5, .5,
"\x1a\x1b\x1c\x1d\x1e\x1f");
} }
bool bool

View File

@ -46,7 +46,17 @@ const char* MTLPtexMipmapTexture::GetShaderSource() {
MTLPtexMipmapTexture * MTLPtexMipmapTexture::Create(Osd::MTLContext *deviceContext, PtexTexture *reader, int maxLevels) { MTLPtexMipmapTexture * MTLPtexMipmapTexture::Create(Osd::MTLContext *deviceContext, PtexTexture *reader, int maxLevels) {
const auto maxNumPages = 2048; const auto maxNumPages = 2048;
PtexMipmapTextureLoader loader(reader, maxNumPages, maxLevels); size_t targetMemory = 0;
// Read the ptex data and pack the texels
bool padAlpha = reader->numChannels()==3;
PtexMipmapTextureLoader loader(reader,
maxNumPages,
maxLevels,
targetMemory,
true/*seemlessMipmap*/,
padAlpha);
const auto numFaces = loader.GetNumFaces(); const auto numFaces = loader.GetNumFaces();
const auto layoutBuffer = [deviceContext->device newBufferWithBytes:loader.GetLayoutBuffer() length:numFaces * 6 * sizeof(short) options:Osd::MTLDefaultStorageMode]; const auto layoutBuffer = [deviceContext->device newBufferWithBytes:loader.GetLayoutBuffer() length:numFaces * 6 * sizeof(short) options:Osd::MTLDefaultStorageMode];
@ -54,7 +64,7 @@ MTLPtexMipmapTexture * MTLPtexMipmapTexture::Create(Osd::MTLContext *deviceConte
const auto textureDescriptor = [MTLTextureDescriptor new]; const auto textureDescriptor = [MTLTextureDescriptor new];
int bpp = 0; int bpp = 0;
textureDescriptor.pixelFormat = [&]() { textureDescriptor.pixelFormat = [&]() {
const auto numChannels = reader->numChannels(); const auto numChannels = reader->numChannels() + padAlpha;
switch(reader->dataType()) { switch(reader->dataType()) {
case Ptex::dt_uint16: case Ptex::dt_uint16:
bpp = sizeof(short) * numChannels; bpp = sizeof(short) * numChannels;

View File

@ -1960,7 +1960,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmd
const char *diffuseEnvironmentMap = NULL, *specularEnvironmentMap = NULL; const char *diffuseEnvironmentMap = NULL, *specularEnvironmentMap = NULL;
const char *colorFilename = NULL, *displacementFilename = NULL, const char *colorFilename = NULL, *displacementFilename = NULL,
*occlusionFilename = NULL, *specularFilename = NULL; *occlusionFilename = NULL, *specularFilename = NULL;
int memLimit; int memLimit = 0;
for (int i = 0; i < (int)argv.size(); ++i) { for (int i = 0; i < (int)argv.size(); ++i) {
if (strstr(argv[i].c_str(), ".obj")) if (strstr(argv[i].c_str(), ".obj"))

View File

@ -465,13 +465,7 @@ getAdaptivePatchColor(int3 patchParam, float sharpness)
}; };
int patchType = 0; int patchType = 0;
#if defined OSD_PATCH_ENABLE_SINGLE_CREASE
if (sharpness > 0) {
pattern = 1;
}
#endif
int pattern = countbits(OsdGetPatchTransitionMask(patchParam));
int edgeCount = countbits(OsdGetPatchBoundaryMask(patchParam)); int edgeCount = countbits(OsdGetPatchBoundaryMask(patchParam));
if (edgeCount == 1) { if (edgeCount == 1) {
patchType = 2; // BOUNDARY patchType = 2; // BOUNDARY
@ -480,9 +474,11 @@ getAdaptivePatchColor(int3 patchParam, float sharpness)
patchType = 3; // CORNER patchType = 3; // CORNER
} }
// XXX: it looks like edgeCount != 0 for some gregory boundary patches. #if defined OSD_PATCH_ENABLE_SINGLE_CREASE
// there might be a bug somewhere... if (sharpness > 0) {
#if defined OSD_PATCH_GREGORY patchType = 1;
}
#elif defined OSD_PATCH_GREGORY
patchType = 4; patchType = 4;
#elif defined OSD_PATCH_GREGORY_BOUNDARY #elif defined OSD_PATCH_GREGORY_BOUNDARY
patchType = 5; patchType = 5;
@ -490,6 +486,8 @@ getAdaptivePatchColor(int3 patchParam, float sharpness)
patchType = 6; patchType = 6;
#endif #endif
int pattern = countbits(OsdGetPatchTransitionMask(patchParam));
return patchColors[6*patchType + pattern]; return patchColors[6*patchType + pattern];
} }

View File

@ -135,15 +135,15 @@ int g_freeze = 0,
g_displayStyle = kDisplayStyleWireOnShaded, g_displayStyle = kDisplayStyleWireOnShaded,
g_adaptive = 1, g_adaptive = 1,
g_endCap = kEndCapGregoryBasis, g_endCap = kEndCapGregoryBasis,
g_smoothCornerPatch = 0, g_smoothCornerPatch = 1,
g_singleCreasePatch = 1, g_singleCreasePatch = 1,
g_infSharpPatch = 0, g_infSharpPatch = 1,
g_drawNormals = 0, g_drawNormals = 0,
g_mbutton[3] = {0, 0, 0}; g_mbutton[3] = {0, 0, 0};
int g_screenSpaceTess = 1, int g_screenSpaceTess = 0,
g_fractionalSpacing = 1, g_fractionalSpacing = 0,
g_patchCull = 1, g_patchCull = 0,
g_displayPatchCounts = 0; g_displayPatchCounts = 0;
float g_rotate[2] = {0, 0}, float g_rotate[2] = {0, 0},

View File

@ -72,6 +72,7 @@ static void initShapes() {
g_defaultShapes.push_back(ShapeDesc("catmark_car", catmark_car, kCatmark)); g_defaultShapes.push_back(ShapeDesc("catmark_car", catmark_car, kCatmark));
g_defaultShapes.push_back(ShapeDesc("loop_toroidal_tet", loop_toroidal_tet, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_toroidal_tet", loop_toroidal_tet, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_tetrahedron", loop_tetrahedron, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_cube", loop_cube, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_cube", loop_cube, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_cubes_semisharp", loop_cubes_semisharp, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_cubes_semisharp", loop_cubes_semisharp, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_cubes_infsharp", loop_cubes_infsharp, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_cubes_infsharp", loop_cubes_infsharp, kLoop));

View File

@ -416,11 +416,7 @@ getAdaptivePatchColor(int3 patchParam, float2 vSegments)
if (vSegments.y > 0) { if (vSegments.y > 0) {
patchType = 1; patchType = 1;
} }
#endif #elif defined OSD_PATCH_GREGORY
// XXX: it looks like edgeCount != 0 for gregory_boundary.
// there might be a bug somewhere.
#if defined OSD_PATCH_GREGORY
patchType = 4; patchType = 4;
#elif defined OSD_PATCH_GREGORY_BOUNDARY #elif defined OSD_PATCH_GREGORY_BOUNDARY
patchType = 5; patchType = 5;

View File

@ -139,9 +139,9 @@ int g_currentShape = 0,
g_level = 2, g_level = 2,
g_kernel = kCPU, g_kernel = kCPU,
g_endCap = kEndCapGregoryBasis, g_endCap = kEndCapGregoryBasis,
g_smoothCornerPatch = 0, g_smoothCornerPatch = 1,
g_singleCreasePatch = 0, g_singleCreasePatch = 0,
g_infSharpPatch = 0, g_infSharpPatch = 1,
g_numElements = 3; g_numElements = 3;
int g_running = 1, int g_running = 1,

View File

@ -28,62 +28,67 @@
static std::vector<ShapeDesc> g_defaultShapes; static std::vector<ShapeDesc> g_defaultShapes;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
static void initShapes() { static void initShapes() {
g_defaultShapes.push_back(ShapeDesc("catmark_toroidal_tet", catmark_toroidal_tet, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_cube", catmark_cube, kCatmark)); g_defaultShapes.push_back(ShapeDesc("catmark_cube", catmark_cube, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_cube_corner0", catmark_cube_corner0, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_cubes_semisharp", catmark_cubes_semisharp, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_cube_corner1", catmark_cube_corner1, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_cubes_infsharp", catmark_cubes_infsharp, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_cube_corner2", catmark_cube_corner2, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_pyramid", catmark_pyramid, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_cube_corner3", catmark_cube_corner3, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_pyramid_creases0", catmark_pyramid_creases0, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_cube_corner4", catmark_cube_corner4, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_pyramid_creases1", catmark_pyramid_creases1, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_cube_creases0", catmark_cube_creases0, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_torus", catmark_torus, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_cube_creases1", catmark_cube_creases1, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_torus_creases0", catmark_torus_creases0, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_cube_creases2", catmark_cube_creases2, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_torus_creases1", catmark_torus_creases1, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_dart_edgecorner", catmark_dart_edgecorner, kCatmark ) );
g_defaultShapes.push_back( ShapeDesc("catmark_dart_edgeonly", catmark_dart_edgeonly, kCatmark ) );
g_defaultShapes.push_back(ShapeDesc("catmark_edgecorner", catmark_edgecorner, kCatmark)); g_defaultShapes.push_back(ShapeDesc("catmark_edgecorner", catmark_edgecorner, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_edgeonly", catmark_edgeonly, kCatmark)); g_defaultShapes.push_back(ShapeDesc("catmark_edgeonly", catmark_edgeonly, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_quadstrips", catmark_quadstrips, kCatmark)); g_defaultShapes.push_back(ShapeDesc("catmark_quadstrips", catmark_quadstrips, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_xord_interior", catmark_xord_interior, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_xord_boundary", catmark_xord_boundary, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_val2_interior", catmark_val2_interior, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_nonquads", catmark_nonquads, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_single_crease", catmark_single_crease, kCatmark)); g_defaultShapes.push_back(ShapeDesc("catmark_single_crease", catmark_single_crease, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_inf_crease0", catmark_inf_crease0, kCatmark)); g_defaultShapes.push_back(ShapeDesc("catmark_inf_crease0", catmark_inf_crease0, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_fan", catmark_fan, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_inf_crease1", catmark_inf_crease1, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test1", catmark_gregory_test1, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_nonman_verts", catmark_nonman_verts, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test2", catmark_gregory_test2, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_nonman_edges", catmark_nonman_edges, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test3", catmark_gregory_test3, kCatmark ) );
g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test4", catmark_gregory_test4, kCatmark ) );
g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test5", catmark_gregory_test5, kCatmark ) );
g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test6", catmark_gregory_test6, kCatmark ) );
g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test7", catmark_gregory_test7, kCatmark ) );
g_defaultShapes.push_back(ShapeDesc("catmark_hole_test1", catmark_hole_test1, kCatmark)); g_defaultShapes.push_back(ShapeDesc("catmark_hole_test1", catmark_hole_test1, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_hole_test2", catmark_hole_test2, kCatmark)); g_defaultShapes.push_back(ShapeDesc("catmark_hole_test2", catmark_hole_test2, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_pyramid_creases0", catmark_pyramid_creases0, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_hole_test3", catmark_hole_test3, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_pyramid_creases1", catmark_pyramid_creases1, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_hole_test4", catmark_hole_test4, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_pyramid", catmark_pyramid, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_chaikin0", catmark_chaikin0, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_tent_creases0", catmark_tent_creases0, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_chaikin1", catmark_chaikin1, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_tent_creases1", catmark_tent_creases1 , kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_chaikin2", catmark_chaikin2, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_tent", catmark_tent, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_smoothtris0", catmark_smoothtris0, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_torus", catmark_torus, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_smoothtris1", catmark_smoothtris1, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_torus_creases0", catmark_torus_creases0, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_pole8", catmark_pole8, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_bishop", catmark_bishop, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_pole64", catmark_pole64, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_car", catmark_car, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_nonman_quadpole64",catmark_nonman_quadpole64,kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_nonman_edge100", catmark_nonman_edge100, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_helmet", catmark_helmet, kCatmark)); g_defaultShapes.push_back(ShapeDesc("catmark_helmet", catmark_helmet, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_bishop", catmark_bishop, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_pawn", catmark_pawn, kCatmark)); g_defaultShapes.push_back(ShapeDesc("catmark_pawn", catmark_pawn, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_rook", catmark_rook, kCatmark)); g_defaultShapes.push_back(ShapeDesc("catmark_rook", catmark_rook, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_car", catmark_car, kCatmark));
g_defaultShapes.push_back(ShapeDesc("loop_toroidal_tet", loop_toroidal_tet, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_tetrahedron", loop_tetrahedron, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_cube", loop_cube, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_cube", loop_cube, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_cubes_semisharp", loop_cubes_semisharp, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_cubes_semisharp", loop_cubes_semisharp, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_cubes_infsharp", loop_cubes_infsharp, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_cubes_infsharp", loop_cubes_infsharp, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_cube_asymmetric", loop_cube_asymmetric, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_cube_asymmetric", loop_cube_asymmetric, kLoop));
g_defaultShapes.push_back( ShapeDesc("loop_triangle_edgecorner", loop_triangle_edgecorner, kLoop ) );
g_defaultShapes.push_back( ShapeDesc("loop_triangle_edgeonly", loop_triangle_edgeonly, kLoop ) );
g_defaultShapes.push_back( ShapeDesc("loop_xord_interior", loop_xord_interior, kLoop ) );
g_defaultShapes.push_back( ShapeDesc("loop_xord_boundary", loop_xord_boundary, kLoop ) );
g_defaultShapes.push_back(ShapeDesc("loop_icosahedron", loop_icosahedron, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_icosahedron", loop_icosahedron, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_icos_semisharp", loop_icos_semisharp, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_icos_semisharp", loop_icos_semisharp, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_icos_infsharp", loop_icos_infsharp, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_icos_infsharp", loop_icos_infsharp, kLoop));
g_defaultShapes.push_back( ShapeDesc("loop_pole8", loop_pole8, kLoop ) ); g_defaultShapes.push_back(ShapeDesc("loop_triangle_edgecorner", loop_triangle_edgecorner, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_triangle_edgeonly", loop_triangle_edgeonly, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_saddle_edgeonly", loop_saddle_edgeonly, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_xord_interior", loop_xord_interior, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_xord_boundary", loop_xord_boundary, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_nonman_verts", loop_nonman_verts, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_nonman_edges", loop_nonman_edges, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_pole64", loop_pole64, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_pole64", loop_pole64, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_nonman_edge100", loop_nonman_edge100, kLoop));
g_defaultShapes.push_back(ShapeDesc("bilinear_cube", bilinear_cube, kBilinear)); g_defaultShapes.push_back(ShapeDesc("bilinear_cube", bilinear_cube, kBilinear));
g_defaultShapes.push_back(ShapeDesc("bilinear_nonplanar", bilinear_nonplanar, kBilinear)); g_defaultShapes.push_back(ShapeDesc("bilinear_nonplanar", bilinear_nonplanar, kBilinear));

View File

@ -82,9 +82,9 @@ int g_freeze = 0,
g_uvCullBackface = 0, g_uvCullBackface = 0,
g_displayStyle = kWireShaded, g_displayStyle = kWireShaded,
g_adaptive = 1, g_adaptive = 1,
g_smoothCornerPatch = 0, g_smoothCornerPatch = 1,
g_singleCreasePatch = 0, g_singleCreasePatch = 1,
g_infSharpPatch = 0, g_infSharpPatch = 1,
g_mbutton[3] = {0, 0, 0}, g_mbutton[3] = {0, 0, 0},
g_mouseUvView = 0, g_mouseUvView = 0,
g_running = 1; g_running = 1;
@ -236,7 +236,7 @@ struct FVarData
glBindTexture(GL_TEXTURE_BUFFER, textureBuffer); glBindTexture(GL_TEXTURE_BUFFER, textureBuffer);
glTexBuffer(GL_TEXTURE_BUFFER, GL_R32F, buffer); glTexBuffer(GL_TEXTURE_BUFFER, GL_R32F, buffer);
glBindTexture(GL_TEXTURE_BUFFER, 0); glBindTexture(GL_TEXTURE_BUFFER, 0);
glBindTexture(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
glDeleteBuffers(1, &buffer); glDeleteBuffers(1, &buffer);
@ -251,7 +251,7 @@ struct FVarData
glBindTexture(GL_TEXTURE_BUFFER, textureParamBuffer); glBindTexture(GL_TEXTURE_BUFFER, textureParamBuffer);
glTexBuffer(GL_TEXTURE_BUFFER, GL_RG32I, buffer); glTexBuffer(GL_TEXTURE_BUFFER, GL_RG32I, buffer);
glBindTexture(GL_TEXTURE_BUFFER, 0); glBindTexture(GL_TEXTURE_BUFFER, 0);
glBindTexture(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
glDeleteBuffers(1, &buffer); glDeleteBuffers(1, &buffer);
} }
@ -545,13 +545,11 @@ GetEffect(bool uvDraw = false) {
struct EffectDesc { struct EffectDesc {
EffectDesc(OpenSubdiv::Far::PatchDescriptor desc, EffectDesc(OpenSubdiv::Far::PatchDescriptor desc,
OpenSubdiv::Far::PatchDescriptor fvarDesc, Effect effect) : desc(desc),
Effect effect) : desc(desc), fvarDesc(fvarDesc),
effect(effect), effect(effect),
maxValence(0), numElements(0) { } maxValence(0), numElements(0) { }
OpenSubdiv::Far::PatchDescriptor desc; OpenSubdiv::Far::PatchDescriptor desc;
OpenSubdiv::Far::PatchDescriptor fvarDesc;
Effect effect; Effect effect;
int maxValence; int maxValence;
int numElements; int numElements;
@ -559,10 +557,9 @@ struct EffectDesc {
bool operator < (const EffectDesc &e) const { bool operator < (const EffectDesc &e) const {
return return
(desc < e.desc || ((desc == e.desc && (desc < e.desc || ((desc == e.desc &&
(fvarDesc < e.fvarDesc || ((fvarDesc == e.fvarDesc &&
(maxValence < e.maxValence || ((maxValence == e.maxValence) && (maxValence < e.maxValence || ((maxValence == e.maxValence) &&
(numElements < e.numElements || ((numElements == e.numElements) && (numElements < e.numElements || ((numElements == e.numElements) &&
(effect < e.effect))))))))))); (effect < e.effect))))))));
} }
}; };
@ -589,11 +586,6 @@ public:
if (type == Far::PatchDescriptor::QUADS) { if (type == Far::PatchDescriptor::QUADS) {
ss << "#define PRIM_QUAD\n"; ss << "#define PRIM_QUAD\n";
} else if (type == Far::PatchDescriptor::TRIANGLES ||
type == Far::PatchDescriptor::LOOP ||
type == Far::PatchDescriptor::GREGORY_TRIANGLE) {
ss << "#define PRIM_TRI\n";
ss << "#define LOOP\n";
} else { } else {
ss << "#define PRIM_TRI\n"; ss << "#define PRIM_TRI\n";
} }
@ -626,14 +618,6 @@ public:
ss << "#define SHADING_FACEVARYING_UNIFORM_SUBDIVISION\n"; ss << "#define SHADING_FACEVARYING_UNIFORM_SUBDIVISION\n";
} }
if (effectDesc.desc.IsAdaptive()) {
if (effectDesc.fvarDesc.GetType() == Far::PatchDescriptor::REGULAR) {
ss << "#define SHADING_FACEVARYING_SMOOTH_BSPLINE_BASIS\n";
} else if (effectDesc.fvarDesc.GetType() == Far::PatchDescriptor::GREGORY_BASIS) {
ss << "#define SHADING_FACEVARYING_SMOOTH_GREGORY_BASIS\n";
}
}
// include osd PatchCommon // include osd PatchCommon
ss << "#define OSD_PATCH_BASIS_GLSL\n"; ss << "#define OSD_PATCH_BASIS_GLSL\n";
ss << Osd::GLSLPatchShaderSource::GetPatchBasisShaderSource(); ss << Osd::GLSLPatchShaderSource::GetPatchBasisShaderSource();
@ -699,7 +683,7 @@ public:
glUniformBlockBinding(program, uboIndex, g_tessellationBinding); glUniformBlockBinding(program, uboIndex, g_tessellationBinding);
g_fvarArrayDataBinding = 2; g_fvarArrayDataBinding = 2;
uboIndex = glGetUniformBlockIndex(program, "FVarArrayData"); uboIndex = glGetUniformBlockIndex(program, "OsdFVarArrayData");
if (uboIndex != GL_INVALID_INDEX) if (uboIndex != GL_INVALID_INDEX)
glUniformBlockBinding(program, uboIndex, g_fvarArrayDataBinding); glUniformBlockBinding(program, uboIndex, g_fvarArrayDataBinding);
@ -802,10 +786,9 @@ bindTextures() {
static GLenum static GLenum
bindProgram(Effect effect, bindProgram(Effect effect,
OpenSubdiv::Osd::PatchArray const & patch, OpenSubdiv::Osd::PatchArray const & patch) {
OpenSubdiv::Far::PatchDescriptor const & fvarDesc) {
EffectDesc effectDesc(patch.GetDescriptor(), fvarDesc, effect); EffectDesc effectDesc(patch.GetDescriptor(), effect);
typedef OpenSubdiv::Far::PatchDescriptor Descriptor; typedef OpenSubdiv::Far::PatchDescriptor Descriptor;
@ -884,9 +867,6 @@ display() {
glBindVertexArray(g_vao); glBindVertexArray(g_vao);
OpenSubdiv::Far::PatchDescriptor fvarDesc =
g_mesh->GetFarPatchTable()->GetFVarPatchDescriptor(0);
OpenSubdiv::Osd::PatchArrayVector const & patches = OpenSubdiv::Osd::PatchArrayVector const & patches =
g_mesh->GetPatchTable()->GetPatchArrays(); g_mesh->GetPatchTable()->GetPatchArrays();
@ -900,7 +880,7 @@ display() {
for (int i = 0; i < (int)patches.size(); ++i) { for (int i = 0; i < (int)patches.size(); ++i) {
OpenSubdiv::Osd::PatchArray const & patch = patches[i]; OpenSubdiv::Osd::PatchArray const & patch = patches[i];
GLenum primType = bindProgram(GetEffect(), patch, fvarDesc); GLenum primType = bindProgram(GetEffect(), patch);
glDrawElements( glDrawElements(
primType, primType,
@ -934,7 +914,7 @@ display() {
for (int i = 0; i < (int)patches.size(); ++i) { for (int i = 0; i < (int)patches.size(); ++i) {
OpenSubdiv::Osd::PatchArray const & patch = patches[i]; OpenSubdiv::Osd::PatchArray const & patch = patches[i];
GLenum primType = bindProgram(GetEffect(/*uvDraw=*/ true), patch, fvarDesc); GLenum primType = bindProgram(GetEffect(/*uvDraw=*/ true), patch);
glDrawElements( glDrawElements(
primType, primType,
@ -1189,7 +1169,7 @@ initHUD() {
10, 60, callbackControlEdges, 0, 'h'); 10, 60, callbackControlEdges, 0, 'h');
g_hud.AddCheckBox("Control vertices (J)", g_controlMeshDisplay.GetVerticesDisplay(), g_hud.AddCheckBox("Control vertices (J)", g_controlMeshDisplay.GetVerticesDisplay(),
10, 80, callbackControlVertices, 0, 'j'); 10, 80, callbackControlVertices, 0, 'j');
g_hud.AddCheckBox("UV Backface Culling (B)", g_uvCullBackface, g_hud.AddCheckBox("UV Backface Culling (B)", g_uvCullBackface != 0,
10, 100, callbackUVCullBackface, 0, 'b'); 10, 100, callbackUVCullBackface, 0, 'b');
int shading_pulldown = g_hud.AddPullDown("Display Style (W)", int shading_pulldown = g_hud.AddPullDown("Display Style (W)",

View File

@ -60,6 +60,7 @@ static void initShapes() {
g_defaultShapes.push_back(ShapeDesc("catmark_hole_test2", catmark_hole_test2, kCatmark)); g_defaultShapes.push_back(ShapeDesc("catmark_hole_test2", catmark_hole_test2, kCatmark));
g_defaultShapes.push_back(ShapeDesc("loop_toroidal_tet", loop_toroidal_tet, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_toroidal_tet", loop_toroidal_tet, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_tetrahedron", loop_tetrahedron, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_cube", loop_cube, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_cube", loop_cube, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_cubes_semisharp", loop_cubes_semisharp, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_cubes_semisharp", loop_cubes_semisharp, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_cubes_infsharp", loop_cubes_infsharp, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_cubes_infsharp", loop_cubes_infsharp, kLoop));

View File

@ -167,7 +167,7 @@ out block {
} outpt; } outpt;
uniform isamplerBuffer OsdFVarParamBuffer; uniform isamplerBuffer OsdFVarParamBuffer;
layout(std140) uniform FVarArrayData { layout(std140) uniform OsdFVarArrayData {
OsdPatchArray fvarPatchArray[2]; OsdPatchArray fvarPatchArray[2];
}; };
@ -211,25 +211,22 @@ void emit(int index, vec3 normal)
outpt.v.normal = normal; outpt.v.normal = normal;
#endif #endif
#ifdef LOOP // ----- scheme : LOOP #ifdef SHADING_FACEVARYING_UNIFORM_SUBDIVISION
// interpolate fvar data at refined tri or quad vertex locations
#ifdef PRIM_TRI
vec2 trist[3] = vec2[](vec2(0,0), vec2(1,0), vec2(0,1)); vec2 trist[3] = vec2[](vec2(0,0), vec2(1,0), vec2(0,1));
#ifdef SHADING_FACEVARYING_UNIFORM_SUBDIVISION
vec2 st = trist[index]; vec2 st = trist[index];
#else
vec2 st = inpt[index].v.tessCoord;
#endif #endif
vec2 uv = interpolateFaceVarying(st, /*fvarOffset*/0); #ifdef PRIM_QUAD
#else // ----- scheme : CATMARK / BILINEAR
#ifdef SHADING_FACEVARYING_UNIFORM_SUBDIVISION
vec2 quadst[4] = vec2[](vec2(0,0), vec2(1,0), vec2(1,1), vec2(0,1)); vec2 quadst[4] = vec2[](vec2(0,0), vec2(1,0), vec2(1,1), vec2(0,1));
vec2 st = quadst[index]; vec2 st = quadst[index];
#endif
#else #else
// interpolate fvar data at tessellated vertex locations
vec2 st = inpt[index].v.tessCoord; vec2 st = inpt[index].v.tessCoord;
#endif #endif
vec2 uv = interpolateFaceVarying(st, /*fvarOffset*/0); vec2 uv = interpolateFaceVarying(st, /*fvarOffset*/0);
#endif // ------ scheme
outpt.color = vec3(uv.s, uv.t, 0); outpt.color = vec3(uv.s, uv.t, 0);

View File

@ -117,11 +117,6 @@ public:
} else if (type == Far::PatchDescriptor::GREGORY_TRIANGLE) { } else if (type == Far::PatchDescriptor::GREGORY_TRIANGLE) {
ss << "#define OSD_PATCH_GREGORY_TRIANGLE\n"; ss << "#define OSD_PATCH_GREGORY_TRIANGLE\n";
} }
if (type == Far::PatchDescriptor::TRIANGLES ||
type == Far::PatchDescriptor::LOOP ||
type == Far::PatchDescriptor::GREGORY_TRIANGLE) {
ss << "#define LOOP\n";
}
if (desc.IsAdaptive()) { if (desc.IsAdaptive()) {
ss << "#define SMOOTH_NORMALS\n"; ss << "#define SMOOTH_NORMALS\n";
@ -658,12 +653,12 @@ int main(int argc, char ** argv) {
} }
ofs << "</tr>\n"; ofs << "</tr>\n";
for (size_t i = 0; i < g_shapes.size(); ++i) { for (size_t i = 0; i < g_defaultShapes.size(); ++i) {
ofs << "<tr>\n"; ofs << "<tr>\n";
ofs << "<td>" << g_shapes[i].name << "</td>\n"; ofs << "<td>" << g_defaultShapes[i].name << "</td>\n";
for (size_t k = 0; k < kernels.size(); ++k) { for (size_t k = 0; k < kernels.size(); ++k) {
ofs << "<td>"; ofs << "<td>";
ofs << "<img src='" << prefix << "_" << kernels[k] << "_" << g_shapes[i].name << ".png'>"; ofs << "<img src='" << prefix << "_" << kernels[k] << "_" << g_defaultShapes[i].name << ".png'>";
ofs << "</td>"; ofs << "</td>";
} }
ofs << "</tr>\n"; ofs << "</tr>\n";
@ -698,9 +693,9 @@ int main(int argc, char ** argv) {
} }
} }
#endif #endif
for (size_t i = 0; i < g_shapes.size(); ++i) { for (size_t i = 0; i < g_defaultShapes.size(); ++i) {
// run test // run test
runTest(g_shapes[i], kernel, isolationLevel, adaptive, &shaderCache); runTest(g_defaultShapes[i], kernel, isolationLevel, adaptive, &shaderCache);
if (writeToFile) { if (writeToFile) {
// read back pixels // read back pixels
@ -708,7 +703,7 @@ int main(int argc, char ** argv) {
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, &data[0]); glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, &data[0]);
// write image // write image
std::string filename = prefix + "_" + kernel + "_" + g_shapes[i].name + ".png"; std::string filename = prefix + "_" + kernel + "_" + g_defaultShapes[i].name + ".png";
// flip vertical // flip vertical
stbi_write_png(filename.c_str(), width, height, 3, &data[width*3*(height-1)], -width*3); stbi_write_png(filename.c_str(), width, height, 3, &data[width*3*(height-1)], -width*3);
} }

View File

@ -26,83 +26,73 @@
#include "../../regression/shapes/all.h" #include "../../regression/shapes/all.h"
static std::vector<ShapeDesc> g_shapes; static std::vector<ShapeDesc> g_defaultShapes;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
static void initShapes() { static void initShapes() {
g_defaultShapes.push_back(ShapeDesc("catmark_toroidal_tet", catmark_toroidal_tet, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_cube", catmark_cube, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_cubes_semisharp", catmark_cubes_semisharp, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_cubes_infsharp", catmark_cubes_infsharp, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_pyramid", catmark_pyramid, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_pyramid_creases0", catmark_pyramid_creases0, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_pyramid_creases1", catmark_pyramid_creases1, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_torus", catmark_torus, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_torus_creases0", catmark_torus_creases0, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_torus_creases1", catmark_torus_creases1, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_edgecorner", catmark_edgecorner, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_edgeonly", catmark_edgeonly, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_quadstrips", catmark_quadstrips, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_xord_interior", catmark_xord_interior, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_xord_boundary", catmark_xord_boundary, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_val2_interior", catmark_val2_interior, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_nonquads", catmark_nonquads, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_single_crease", catmark_single_crease, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_inf_crease0", catmark_inf_crease0, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_inf_crease1", catmark_inf_crease1, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_nonman_verts", catmark_nonman_verts, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_nonman_edges", catmark_nonman_edges, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_hole_test1", catmark_hole_test1, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_hole_test2", catmark_hole_test2, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_hole_test3", catmark_hole_test3, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_hole_test4", catmark_hole_test4, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_chaikin0", catmark_chaikin0, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_chaikin1", catmark_chaikin1, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_chaikin2", catmark_chaikin2, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_smoothtris0", catmark_smoothtris0, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_smoothtris1", catmark_smoothtris1, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_pole8", catmark_pole8, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_pole64", catmark_pole64, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_nonman_quadpole64",catmark_nonman_quadpole64,kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_nonman_edge100", catmark_nonman_edge100, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_helmet", catmark_helmet, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_bishop", catmark_bishop, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_pawn", catmark_pawn, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_rook", catmark_rook, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_car", catmark_car, kCatmark));
g_shapes.push_back( ShapeDesc("catmark_cube", catmark_cube, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("loop_toroidal_tet", loop_toroidal_tet, kLoop));
g_shapes.push_back( ShapeDesc("catmark_cube_corner0", catmark_cube_corner0, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("loop_tetrahedron", loop_tetrahedron, kLoop));
g_shapes.push_back( ShapeDesc("catmark_cube_corner1", catmark_cube_corner1, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("loop_cube", loop_cube, kLoop));
g_shapes.push_back( ShapeDesc("catmark_cube_corner2", catmark_cube_corner2, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("loop_cubes_semisharp", loop_cubes_semisharp, kLoop));
g_shapes.push_back( ShapeDesc("catmark_cube_corner3", catmark_cube_corner3, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("loop_cubes_infsharp", loop_cubes_infsharp, kLoop));
g_shapes.push_back( ShapeDesc("catmark_cube_corner4", catmark_cube_corner4, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("loop_cube_asymmetric", loop_cube_asymmetric, kLoop));
g_shapes.push_back( ShapeDesc("catmark_cube_creases0", catmark_cube_creases0, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("loop_icosahedron", loop_icosahedron, kLoop));
g_shapes.push_back( ShapeDesc("catmark_cube_creases1", catmark_cube_creases1, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("loop_icos_semisharp", loop_icos_semisharp, kLoop));
g_shapes.push_back( ShapeDesc("catmark_cube_creases2", catmark_cube_creases2, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("loop_icos_infsharp", loop_icos_infsharp, kLoop));
g_shapes.push_back( ShapeDesc("catmark_dart_edgecorner", catmark_dart_edgecorner, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("loop_triangle_edgecorner", loop_triangle_edgecorner, kLoop));
g_shapes.push_back( ShapeDesc("catmark_dart_edgeonly", catmark_dart_edgeonly, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("loop_triangle_edgeonly", loop_triangle_edgeonly, kLoop));
g_shapes.push_back( ShapeDesc("catmark_edgecorner", catmark_edgecorner, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("loop_saddle_edgeonly", loop_saddle_edgeonly, kLoop));
g_shapes.push_back( ShapeDesc("catmark_edgeonly", catmark_edgeonly, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("loop_xord_interior", loop_xord_interior, kLoop));
g_shapes.push_back( ShapeDesc("catmark_quadstrips", catmark_quadstrips, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("loop_xord_boundary", loop_xord_boundary, kLoop));
g_shapes.push_back( ShapeDesc("catmark_chaikin0", catmark_chaikin0, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("loop_nonman_verts", loop_nonman_verts, kLoop));
g_shapes.push_back( ShapeDesc("catmark_chaikin1", catmark_chaikin1, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("loop_nonman_edges", loop_nonman_edges, kLoop));
g_shapes.push_back( ShapeDesc("catmark_chaikin2", catmark_chaikin2, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("loop_pole64", loop_pole64, kLoop));
g_shapes.push_back( ShapeDesc("catmark_fan", catmark_fan, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("loop_nonman_edge100", loop_nonman_edge100, kLoop));
g_shapes.push_back( ShapeDesc("catmark_fvar_bound0", catmark_fvar_bound0, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_fvar_bound1", catmark_fvar_bound1, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_fvar_bound2", catmark_fvar_bound2, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_gregory_test0", catmark_gregory_test0, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_gregory_test1", catmark_gregory_test1, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_gregory_test2", catmark_gregory_test2, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_gregory_test3", catmark_gregory_test3, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_gregory_test4", catmark_gregory_test4, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_gregory_test5", catmark_gregory_test5, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_gregory_test6", catmark_gregory_test6, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_gregory_test7", catmark_gregory_test7, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_hole_test1", catmark_hole_test1, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_hole_test2", catmark_hole_test2, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_hole_test3", catmark_hole_test3, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_hole_test4", catmark_hole_test4, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_pyramid_creases0", catmark_pyramid_creases0, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_pyramid_creases1", catmark_pyramid_creases1, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_pyramid", catmark_pyramid, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_tent_creases0", catmark_tent_creases0, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_tent_creases1", catmark_tent_creases1 , kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_tent", catmark_tent, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_torus", catmark_torus, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_torus_creases0", catmark_torus_creases0, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_smoothtris0", catmark_smoothtris0, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_smoothtris1", catmark_smoothtris1, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_bishop", catmark_bishop, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_car", catmark_car, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_helmet", catmark_helmet, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_pawn", catmark_pawn, kCatmark ) );
g_shapes.push_back( ShapeDesc("catmark_rook", catmark_rook, kCatmark ) );
g_shapes.push_back( ShapeDesc("loop_cube", loop_cube, kLoop ) ); g_defaultShapes.push_back(ShapeDesc("bilinear_cube", bilinear_cube, kBilinear));
g_shapes.push_back( ShapeDesc("loop_cubes_semisharp", loop_cubes_semisharp, kLoop ) ); g_defaultShapes.push_back(ShapeDesc("bilinear_nonplanar", bilinear_nonplanar, kBilinear));
g_shapes.push_back( ShapeDesc("loop_cubes_infsharp", loop_cubes_infsharp, kLoop ) ); g_defaultShapes.push_back(ShapeDesc("bilinear_nonquads0", bilinear_nonquads0, kBilinear));
g_shapes.push_back( ShapeDesc("loop_cube_asymmetric", loop_cube_asymmetric, kLoop ) ); g_defaultShapes.push_back(ShapeDesc("bilinear_nonquads1", bilinear_nonquads1, kBilinear));
g_shapes.push_back( ShapeDesc("loop_triangle_edgecorner", loop_triangle_edgecorner, kLoop ) );
g_shapes.push_back( ShapeDesc("loop_triangle_edgeonly", loop_triangle_edgeonly, kLoop ) );
g_shapes.push_back( ShapeDesc("loop_xord_interior", loop_xord_interior, kLoop ) );
g_shapes.push_back( ShapeDesc("loop_xord_boundary", loop_xord_boundary, kLoop ) );
g_shapes.push_back( ShapeDesc("loop_icosahedron", loop_icosahedron, kLoop ) );
g_shapes.push_back( ShapeDesc("loop_icos_semisharp", loop_icos_semisharp, kLoop ) );
g_shapes.push_back( ShapeDesc("loop_icos_infsharp", loop_icos_infsharp, kLoop ) );
g_shapes.push_back( ShapeDesc("loop_fvar_bound0", loop_fvar_bound0, kLoop ) );
g_shapes.push_back( ShapeDesc("loop_fvar_bound1", loop_fvar_bound1, kLoop ) );
g_shapes.push_back( ShapeDesc("loop_fvar_bound2", loop_fvar_bound2, kLoop ) );
g_shapes.push_back( ShapeDesc("loop_fvar_bound3", loop_fvar_bound3, kLoop ) );
g_shapes.push_back( ShapeDesc("loop_chaikin0", loop_chaikin0, kLoop ) );
g_shapes.push_back( ShapeDesc("loop_chaikin1", loop_chaikin1, kLoop ) );
g_shapes.push_back( ShapeDesc("loop_pole8", loop_pole8, kLoop ) );
g_shapes.push_back( ShapeDesc("loop_pole64", loop_pole64, kLoop ) );
g_shapes.push_back( ShapeDesc("bilinear_cube", bilinear_cube, kBilinear ) );
g_shapes.push_back( ShapeDesc("bilinear_nonplanar", bilinear_nonplanar, kBilinear ) );
g_shapes.push_back( ShapeDesc("bilinear_nonquads0", bilinear_nonquads0, kBilinear ) );
g_shapes.push_back( ShapeDesc("bilinear_nonquads1", bilinear_nonquads1, kBilinear ) );
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -44,6 +44,13 @@
mix(mix(inpt[a].color, inpt[b].color, UV.x), \ mix(mix(inpt[a].color, inpt[b].color, UV.x), \
mix(inpt[c].color, inpt[d].color, UV.x), UV.y) mix(inpt[c].color, inpt[d].color, UV.x), UV.y)
#undef OSD_USER_VARYING_PER_EVAL_POINT_TRIANGLE
#define OSD_USER_VARYING_PER_EVAL_POINT_TRIANGLE(UV, a, b, c) \
outpt.color = \
inpt[a].color * (1.0f - UV.x - UV.y) + \
inpt[b].color * UV.x + \
inpt[c].color * UV.y;
//-------------------------------------------------------------- //--------------------------------------------------------------
// Uniforms / Uniform Blocks // Uniforms / Uniform Blocks
//-------------------------------------------------------------- //--------------------------------------------------------------
@ -358,7 +365,7 @@ getAdaptivePatchColor(ivec3 patchParam)
patchType = 3; // CORNER (not correct for patches that are not isolated) patchType = 3; // CORNER (not correct for patches that are not isolated)
} }
#if defined(OSD_PATCH_ENABLE_SINGLE_CREASE) && !defined(LOOP) #if defined OSD_PATCH_ENABLE_SINGLE_CREASE
// check this after boundary/corner since single crease patch also has edgeCount. // check this after boundary/corner since single crease patch also has edgeCount.
if (inpt.vSegments.y > 0) { if (inpt.vSegments.y > 0) {
patchType = 1; patchType = 1;

View File

@ -109,7 +109,7 @@ int g_running = 1,
g_displayDisplacement = 0, g_displayDisplacement = 0,
g_mbutton[3] = {0, 0, 0}; g_mbutton[3] = {0, 0, 0};
int g_brushSize = 500; int g_brushSize = 100;
int g_frame = 0; int g_frame = 0;
GLuint g_ptexPages = 0, GLuint g_ptexPages = 0,
@ -704,15 +704,15 @@ display() {
averageFps += g_fpsTimeSamples[i]/(float)NUM_FPS_TIME_SAMPLES; averageFps += g_fpsTimeSamples[i]/(float)NUM_FPS_TIME_SAMPLES;
} }
g_hud.DrawString(10, -180, "Tess level (+/-): %d", g_tessLevel); g_hud.DrawString(10, -100, "Tess level (+/-): %d", g_tessLevel);
if (numPrimsGenerated > 1000000) { if (numPrimsGenerated > 1000000) {
g_hud.DrawString(10, -160, "Primitives : %3.1f million", (float)numPrimsGenerated/1000000.0); g_hud.DrawString(10, -80, "Primitives : %3.1f million", (float)numPrimsGenerated/1000000.0);
} else if (numPrimsGenerated > 1000) { } else if (numPrimsGenerated > 1000) {
g_hud.DrawString(10, -160, "Primitives : %3.1f thousand", (float)numPrimsGenerated/1000.0); g_hud.DrawString(10, -80, "Primitives : %3.1f thousand", (float)numPrimsGenerated/1000.0);
} else { } else {
g_hud.DrawString(10, -160, "Primitives : %d", numPrimsGenerated); g_hud.DrawString(10, -80, "Primitives : %d", numPrimsGenerated);
} }
g_hud.DrawString(10, -140, "Vertices : %d", g_mesh->GetNumVertices()); g_hud.DrawString(10, -60, "Vertices : %d", g_mesh->GetNumVertices());
g_hud.DrawString(10, -20, "FPS : %3.1f", averageFps); g_hud.DrawString(10, -20, "FPS : %3.1f", averageFps);
} }
@ -961,6 +961,12 @@ callbackModel(int m) {
createOsdMesh(); createOsdMesh();
} }
static void
callbackBrushSize(float value, int /* data */) {
g_brushSize = (int)value;
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
static void static void
initHUD() { initHUD() {
@ -982,6 +988,9 @@ initHUD() {
g_hud.AddPullDownButton(shading_pulldown, "Shaded", 1, g_wire==1); g_hud.AddPullDownButton(shading_pulldown, "Shaded", 1, g_wire==1);
g_hud.AddPullDownButton(shading_pulldown, "Wire+Shaded", 2, g_wire==2); g_hud.AddPullDownButton(shading_pulldown, "Wire+Shaded", 2, g_wire==2);
g_hud.AddSlider("Brush size", 10, 500, g_brushSize,
350, -60, 40, true, callbackBrushSize, 0);
for (int i = 1; i < 11; ++i) { for (int i = 1; i < 11; ++i) {
char level[16]; char level[16];
sprintf(level, "Lv. %d", i); sprintf(level, "Lv. %d", i);

View File

@ -704,11 +704,6 @@ public:
} else if (type == Far::PatchDescriptor::GREGORY_TRIANGLE) { } else if (type == Far::PatchDescriptor::GREGORY_TRIANGLE) {
ss << "#define OSD_PATCH_GREGORY_TRIANGLE\n"; ss << "#define OSD_PATCH_GREGORY_TRIANGLE\n";
} }
if (type == Far::PatchDescriptor::TRIANGLES ||
type == Far::PatchDescriptor::LOOP ||
type == Far::PatchDescriptor::GREGORY_TRIANGLE) {
ss << "#define LOOP\n";
}
// include osd PatchCommon // include osd PatchCommon
ss << Osd::GLSLPatchShaderSource::GetCommonShaderSource(); ss << Osd::GLSLPatchShaderSource::GetCommonShaderSource();

View File

@ -475,7 +475,7 @@ GetOverrideColor(ivec3 patchParam)
patchType = 3; // CORNER (not correct for patches that are not isolated) patchType = 3; // CORNER (not correct for patches that are not isolated)
} }
#if defined(OSD_PATCH_ENABLE_SINGLE_CREASE) && !defined(LOOP) #if defined OSD_PATCH_ENABLE_SINGLE_CREASE
// check this after boundary/corner since single crease patch also has edgeCount. // check this after boundary/corner since single crease patch also has edgeCount.
if (inpt.vSegments.y > 0) { if (inpt.vSegments.y > 0) {
patchType = 1; patchType = 1;

View File

@ -378,11 +378,6 @@ public:
} else if (type == Far::PatchDescriptor::GREGORY_TRIANGLE) { } else if (type == Far::PatchDescriptor::GREGORY_TRIANGLE) {
ss << "#define OSD_PATCH_GREGORY_TRIANGLE\n"; ss << "#define OSD_PATCH_GREGORY_TRIANGLE\n";
} }
if (type == Far::PatchDescriptor::TRIANGLES ||
type == Far::PatchDescriptor::LOOP ||
type == Far::PatchDescriptor::GREGORY_TRIANGLE) {
ss << "#define LOOP\n";
}
// for legacy gregory // for legacy gregory
ss << "#define OSD_MAX_VALENCE " << effectDesc.maxValence << "\n"; ss << "#define OSD_MAX_VALENCE " << effectDesc.maxValence << "\n";

View File

@ -424,7 +424,7 @@ getAdaptivePatchColor(ivec3 patchParam)
patchType = 3; // CORNER (not correct for patches that are not isolated) patchType = 3; // CORNER (not correct for patches that are not isolated)
} }
#if defined(OSD_PATCH_ENABLE_SINGLE_CREASE) && !defined(LOOP) #if defined OSD_PATCH_ENABLE_SINGLE_CREASE
// check this after boundary/corner since single crease patch also has edgeCount. // check this after boundary/corner since single crease patch also has edgeCount.
if (inpt.vSegments.y > 0) { if (inpt.vSegments.y > 0) {
patchType = 1; patchType = 1;

View File

@ -121,7 +121,7 @@ int g_running = 1,
g_repeatCount=0; g_repeatCount=0;
bool g_adaptive=true, bool g_adaptive=true,
g_infSharpPatch=false; g_infSharpPatch=true;
float g_rotate[2] = {0, 0}, float g_rotate[2] = {0, 0},
g_dolly = 5, g_dolly = 5,

View File

@ -30,56 +30,65 @@ static std::vector<ShapeDesc> g_defaultShapes;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
static void initShapes() { static void initShapes() {
g_defaultShapes.push_back(ShapeDesc("catmark_toroidal_tet", catmark_toroidal_tet, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_cube", catmark_cube, kCatmark)); g_defaultShapes.push_back(ShapeDesc("catmark_cube", catmark_cube, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_cube_corner0", catmark_cube_corner0, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_cubes_semisharp", catmark_cubes_semisharp, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_cube_corner1", catmark_cube_corner1, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_cubes_infsharp", catmark_cubes_infsharp, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_cube_corner2", catmark_cube_corner2, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_pyramid", catmark_pyramid, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_cube_corner3", catmark_cube_corner3, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_pyramid_creases0", catmark_pyramid_creases0, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_cube_corner4", catmark_cube_corner4, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_pyramid_creases1", catmark_pyramid_creases1, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_cube_creases0", catmark_cube_creases0, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_torus", catmark_torus, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_cube_creases1", catmark_cube_creases1, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_torus_creases0", catmark_torus_creases0, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_dart_edgecorner", catmark_dart_edgecorner, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_torus_creases1", catmark_torus_creases1, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_dart_edgeonly", catmark_dart_edgeonly, kCatmark ) );
g_defaultShapes.push_back(ShapeDesc("catmark_edgecorner", catmark_edgecorner, kCatmark)); g_defaultShapes.push_back(ShapeDesc("catmark_edgecorner", catmark_edgecorner, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_edgeonly", catmark_edgeonly, kCatmark)); g_defaultShapes.push_back(ShapeDesc("catmark_edgeonly", catmark_edgeonly, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_quadstrips", catmark_quadstrips, kCatmark)); g_defaultShapes.push_back(ShapeDesc("catmark_quadstrips", catmark_quadstrips, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_fan", catmark_fan, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_xord_interior", catmark_xord_interior, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test1", catmark_gregory_test1, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_xord_boundary", catmark_xord_boundary, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test2", catmark_gregory_test2, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_val2_interior", catmark_val2_interior, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test3", catmark_gregory_test3, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_nonquads", catmark_nonquads, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test4", catmark_gregory_test4, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_single_crease", catmark_single_crease, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test5", catmark_gregory_test5, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_inf_crease0", catmark_inf_crease0, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test6", catmark_gregory_test6, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_inf_crease1", catmark_inf_crease1, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_gregory_test7", catmark_gregory_test7, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_nonman_verts", catmark_nonman_verts, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_nonman_edges", catmark_nonman_edges, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_hole_test1", catmark_hole_test1, kCatmark)); g_defaultShapes.push_back(ShapeDesc("catmark_hole_test1", catmark_hole_test1, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_hole_test2", catmark_hole_test2, kCatmark)); g_defaultShapes.push_back(ShapeDesc("catmark_hole_test2", catmark_hole_test2, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_pyramid_creases0", catmark_pyramid_creases0, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_hole_test3", catmark_hole_test3, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_pyramid_creases1", catmark_pyramid_creases1, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_hole_test4", catmark_hole_test4, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_pyramid", catmark_pyramid, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_chaikin0", catmark_chaikin0, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_tent_creases0", catmark_tent_creases0, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_chaikin1", catmark_chaikin1, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_tent_creases1", catmark_tent_creases1 , kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_chaikin2", catmark_chaikin2, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_tent", catmark_tent, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_smoothtris0", catmark_smoothtris0, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_torus", catmark_torus, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_smoothtris1", catmark_smoothtris1, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_torus_creases0", catmark_torus_creases0, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_pole8", catmark_pole8, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_bishop", catmark_bishop, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_pole64", catmark_pole64, kCatmark));
g_defaultShapes.push_back( ShapeDesc("catmark_car", catmark_car, kCatmark ) ); g_defaultShapes.push_back(ShapeDesc("catmark_nonman_quadpole64",catmark_nonman_quadpole64,kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_nonman_edge100", catmark_nonman_edge100, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_helmet", catmark_helmet, kCatmark)); g_defaultShapes.push_back(ShapeDesc("catmark_helmet", catmark_helmet, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_bishop", catmark_bishop, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_pawn", catmark_pawn, kCatmark)); g_defaultShapes.push_back(ShapeDesc("catmark_pawn", catmark_pawn, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_rook", catmark_rook, kCatmark)); g_defaultShapes.push_back(ShapeDesc("catmark_rook", catmark_rook, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_car", catmark_car, kCatmark));
g_defaultShapes.push_back(ShapeDesc("loop_toroidal_tet", loop_toroidal_tet, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_tetrahedron", loop_tetrahedron, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_cube", loop_cube, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_cube", loop_cube, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_cubes_semisharp", loop_cubes_semisharp, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_cubes_semisharp", loop_cubes_semisharp, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_cubes_infsharp", loop_cubes_infsharp, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_cubes_infsharp", loop_cubes_infsharp, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_cube_asymmetric", loop_cube_asymmetric, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_cube_asymmetric", loop_cube_asymmetric, kLoop));
g_defaultShapes.push_back( ShapeDesc("loop_triangle_edgecorner", loop_triangle_edgecorner, kLoop ) );
g_defaultShapes.push_back( ShapeDesc("loop_triangle_edgeonly", loop_triangle_edgeonly, kLoop ) );
g_defaultShapes.push_back( ShapeDesc("loop_xord_interior", loop_xord_interior, kLoop ) );
g_defaultShapes.push_back( ShapeDesc("loop_xord_boundary", loop_xord_boundary, kLoop ) );
g_defaultShapes.push_back(ShapeDesc("loop_icosahedron", loop_icosahedron, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_icosahedron", loop_icosahedron, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_icos_semisharp", loop_icos_semisharp, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_icos_semisharp", loop_icos_semisharp, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_icos_infsharp", loop_icos_infsharp, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_icos_infsharp", loop_icos_infsharp, kLoop));
g_defaultShapes.push_back( ShapeDesc("loop_pole8", loop_pole8, kLoop ) ); g_defaultShapes.push_back(ShapeDesc("loop_triangle_edgecorner", loop_triangle_edgecorner, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_triangle_edgeonly", loop_triangle_edgeonly, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_saddle_edgeonly", loop_saddle_edgeonly, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_xord_interior", loop_xord_interior, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_xord_boundary", loop_xord_boundary, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_nonman_verts", loop_nonman_verts, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_nonman_edges", loop_nonman_edges, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_pole64", loop_pole64, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_pole64", loop_pole64, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_nonman_edge100", loop_nonman_edge100, kLoop));
g_defaultShapes.push_back(ShapeDesc("bilinear_cube", bilinear_cube, kBilinear)); g_defaultShapes.push_back(ShapeDesc("bilinear_cube", bilinear_cube, kBilinear));
g_defaultShapes.push_back(ShapeDesc("bilinear_nonplanar", bilinear_nonplanar, kBilinear)); g_defaultShapes.push_back(ShapeDesc("bilinear_nonplanar", bilinear_nonplanar, kBilinear));

View File

@ -184,9 +184,9 @@ int g_freeze = 0,
g_displayStyle = kDisplayStyleWireOnShaded, g_displayStyle = kDisplayStyleWireOnShaded,
g_adaptive = 1, g_adaptive = 1,
g_endCap = kEndCapGregoryBasis, g_endCap = kEndCapGregoryBasis,
g_smoothCornerPatch = 0, g_smoothCornerPatch = 1,
g_singleCreasePatch = 1, g_singleCreasePatch = 1,
g_infSharpPatch = 0, g_infSharpPatch = 1,
g_mbutton[3] = {0, 0, 0}, g_mbutton[3] = {0, 0, 0},
g_running = 1; g_running = 1;
@ -233,7 +233,9 @@ GLuint g_transformUB = 0,
g_tessellationUB = 0, g_tessellationUB = 0,
g_tessellationBinding = 1, g_tessellationBinding = 1,
g_lightingUB = 0, g_lightingUB = 0,
g_lightingBinding = 2; g_lightingBinding = 2,
g_fvarArrayDataUB = 0,
g_fvarArrayDataBinding = 3;
struct Transform { struct Transform {
float ModelViewMatrix[16]; float ModelViewMatrix[16];
@ -251,7 +253,7 @@ GLuint g_vao = 0;
struct FVarData struct FVarData
{ {
FVarData() : FVarData() :
textureBuffer(0) { textureBuffer(0), textureParamBuffer(0) {
} }
~FVarData() { ~FVarData() {
Release(); Release();
@ -260,11 +262,17 @@ struct FVarData
if (textureBuffer) if (textureBuffer)
glDeleteTextures(1, &textureBuffer); glDeleteTextures(1, &textureBuffer);
textureBuffer = 0; textureBuffer = 0;
if (textureParamBuffer)
glDeleteTextures(1, &textureParamBuffer);
textureParamBuffer = 0;
} }
void Create(OpenSubdiv::Far::PatchTable const *patchTable, void Create(OpenSubdiv::Far::PatchTable const *patchTable,
int fvarWidth, std::vector<float> const & fvarSrcData) { int fvarWidth, std::vector<float> const & fvarSrcData) {
using namespace OpenSubdiv;
Release(); Release();
OpenSubdiv::Far::ConstIndexArray indices = patchTable->GetFVarValues(); Far::ConstIndexArray indices = patchTable->GetFVarValues();
// expand fvardata to per-patch array // expand fvardata to per-patch array
std::vector<float> data; std::vector<float> data;
@ -289,8 +297,22 @@ struct FVarData
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
glDeleteBuffers(1, &buffer); glDeleteBuffers(1, &buffer);
Far::ConstPatchParamArray fvarParam = patchTable->GetFVarPatchParams();
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, fvarParam.size()*sizeof(Far::PatchParam),
&fvarParam[0], GL_STATIC_DRAW);
glGenTextures(1, &textureParamBuffer);
glBindTexture(GL_TEXTURE_BUFFER, textureParamBuffer);
glTexBuffer(GL_TEXTURE_BUFFER, GL_RG32I, buffer);
glBindTexture(GL_TEXTURE_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDeleteBuffers(1, &buffer);
} }
GLuint textureBuffer; GLuint textureBuffer, textureParamBuffer;
} g_fvarData; } g_fvarData;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -780,11 +802,6 @@ public:
break; break;
} }
if (type == Far::PatchDescriptor::TRIANGLES ||
type == Far::PatchDescriptor::LOOP ||
type == Far::PatchDescriptor::GREGORY_TRIANGLE) {
ss << "#define LOOP\n";
}
if (type != Far::PatchDescriptor::TRIANGLES && if (type != Far::PatchDescriptor::TRIANGLES &&
type != Far::PatchDescriptor::QUADS) { type != Far::PatchDescriptor::QUADS) {
ss << "#define SMOOTH_NORMALS\n"; ss << "#define SMOOTH_NORMALS\n";
@ -869,6 +886,10 @@ public:
if (uboIndex != GL_INVALID_INDEX) if (uboIndex != GL_INVALID_INDEX)
glUniformBlockBinding(program, uboIndex, g_lightingBinding); glUniformBlockBinding(program, uboIndex, g_lightingBinding);
uboIndex = glGetUniformBlockIndex(program, "OsdFVarArrayData");
if (uboIndex != GL_INVALID_INDEX)
glUniformBlockBinding(program, uboIndex, g_fvarArrayDataBinding);
// assign texture locations // assign texture locations
GLint loc; GLint loc;
glUseProgram(program); glUseProgram(program);
@ -878,16 +899,19 @@ public:
if ((loc = glGetUniformLocation(program, "OsdFVarDataBuffer")) != -1) { if ((loc = glGetUniformLocation(program, "OsdFVarDataBuffer")) != -1) {
glUniform1i(loc, 1); // GL_TEXTURE1 glUniform1i(loc, 1); // GL_TEXTURE1
} }
// for legacy gregory patches if ((loc = glGetUniformLocation(program, "OsdFVarParamBuffer")) != -1) {
if ((loc = glGetUniformLocation(program, "OsdVertexBuffer")) != -1) {
glUniform1i(loc, 2); // GL_TEXTURE2 glUniform1i(loc, 2); // GL_TEXTURE2
} }
if ((loc = glGetUniformLocation(program, "OsdValenceBuffer")) != -1) { // for legacy gregory patches
if ((loc = glGetUniformLocation(program, "OsdVertexBuffer")) != -1) {
glUniform1i(loc, 3); // GL_TEXTURE3 glUniform1i(loc, 3); // GL_TEXTURE3
} }
if ((loc = glGetUniformLocation(program, "OsdQuadOffsetBuffer")) != -1) { if ((loc = glGetUniformLocation(program, "OsdValenceBuffer")) != -1) {
glUniform1i(loc, 4); // GL_TEXTURE4 glUniform1i(loc, 4); // GL_TEXTURE4
} }
if ((loc = glGetUniformLocation(program, "OsdQuadOffsetBuffer")) != -1) {
glUniform1i(loc, 5); // GL_TEXTURE5
}
glUseProgram(0); glUseProgram(0);
return config; return config;
@ -899,6 +923,9 @@ ShaderCache g_shaderCache;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
static void static void
updateUniformBlocks() { updateUniformBlocks() {
using namespace OpenSubdiv;
if (! g_transformUB) { if (! g_transformUB) {
glGenBuffers(1, &g_transformUB); glGenBuffers(1, &g_transformUB);
glBindBuffer(GL_UNIFORM_BUFFER, g_transformUB); glBindBuffer(GL_UNIFORM_BUFFER, g_transformUB);
@ -932,6 +959,29 @@ updateUniformBlocks() {
glBindBufferBase(GL_UNIFORM_BUFFER, g_tessellationBinding, g_tessellationUB); glBindBufferBase(GL_UNIFORM_BUFFER, g_tessellationBinding, g_tessellationUB);
// Update and bind fvar patch array state
if (g_mesh->GetPatchTable()->GetNumFVarChannels() > 0) {
Osd::PatchArrayVector const &fvarPatchArrays =
g_mesh->GetPatchTable()->GetFVarPatchArrays();
// bind patch arrays UBO (std140 struct size padded to vec4 alignment)
int patchArraySize =
sizeof(GLint) * ((sizeof(Osd::PatchArray)/sizeof(GLint) + 3) & ~3);
if (!g_fvarArrayDataUB) {
glGenBuffers(1, &g_fvarArrayDataUB);
}
glBindBuffer(GL_UNIFORM_BUFFER, g_fvarArrayDataUB);
glBufferData(GL_UNIFORM_BUFFER,
fvarPatchArrays.size()*patchArraySize, NULL, GL_STATIC_DRAW);
for (int i=0; i<(int)fvarPatchArrays.size(); ++i) {
glBufferSubData(GL_UNIFORM_BUFFER,
i*patchArraySize, sizeof(Osd::PatchArray), &fvarPatchArrays[i]);
}
glBindBufferBase(GL_UNIFORM_BUFFER,
g_fvarArrayDataBinding, g_fvarArrayDataUB);
}
// Update and bind lighting state // Update and bind lighting state
struct Lighting { struct Lighting {
struct Light { struct Light {
@ -978,17 +1028,20 @@ bindTextures() {
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_BUFFER, glBindTexture(GL_TEXTURE_BUFFER,
g_fvarData.textureBuffer); g_fvarData.textureBuffer);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_BUFFER,
g_fvarData.textureParamBuffer);
} }
// legacy gregory // legacy gregory
if (g_legacyGregoryPatchTable) { if (g_legacyGregoryPatchTable) {
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_BUFFER,
g_legacyGregoryPatchTable->GetVertexTextureBuffer());
glActiveTexture(GL_TEXTURE3); glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_BUFFER, glBindTexture(GL_TEXTURE_BUFFER,
g_legacyGregoryPatchTable->GetVertexValenceTextureBuffer()); g_legacyGregoryPatchTable->GetVertexTextureBuffer());
glActiveTexture(GL_TEXTURE4); glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_BUFFER,
g_legacyGregoryPatchTable->GetVertexValenceTextureBuffer());
glActiveTexture(GL_TEXTURE5);
glBindTexture(GL_TEXTURE_BUFFER, glBindTexture(GL_TEXTURE_BUFFER,
g_legacyGregoryPatchTable->GetQuadOffsetsTextureBuffer()); g_legacyGregoryPatchTable->GetQuadOffsetsTextureBuffer());
} }

View File

@ -72,6 +72,7 @@ static void initShapes() {
g_defaultShapes.push_back(ShapeDesc("catmark_car", catmark_car, kCatmark)); g_defaultShapes.push_back(ShapeDesc("catmark_car", catmark_car, kCatmark));
g_defaultShapes.push_back(ShapeDesc("loop_toroidal_tet", loop_toroidal_tet, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_toroidal_tet", loop_toroidal_tet, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_tetrahedron", loop_tetrahedron, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_cube", loop_cube, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_cube", loop_cube, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_cubes_semisharp", loop_cubes_semisharp, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_cubes_semisharp", loop_cubes_semisharp, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_cubes_infsharp", loop_cubes_infsharp, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_cubes_infsharp", loop_cubes_infsharp, kLoop));

View File

@ -179,23 +179,29 @@ out block {
OSD_USER_VARYING_DECLARE OSD_USER_VARYING_DECLARE
} outpt; } outpt;
uniform isamplerBuffer OsdFVarParamBuffer;
layout(std140) uniform OsdFVarArrayData {
OsdPatchArray fvarPatchArray[2];
};
vec2 vec2
interpolateFaceVarying(vec2 uv, int fvarOffset) interpolateFaceVarying(vec2 uv, int fvarOffset)
{ {
int patchIndex = OsdGetPatchIndex(gl_PrimitiveID); int patchIndex = OsdGetPatchIndex(gl_PrimitiveID);
OsdPatchArray array = fvarPatchArray[0];
ivec3 fvarPatchParam = texelFetch(OsdFVarParamBuffer, patchIndex).xyz;
OsdPatchParam param = OsdPatchParamInit(fvarPatchParam.x,
fvarPatchParam.y,
fvarPatchParam.z);
int patchType = OsdPatchParamIsRegular(param) ? array.regDesc : array.desc;
float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20]; float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20];
#ifdef LOOP
int patchType = OSD_PATCH_DESCRIPTOR_TRIANGLES;
OsdPatchParam param = OsdPatchParamInit(0, 0, 0);
int numPoints = OsdEvaluatePatchBasisNormalized(patchType, param, int numPoints = OsdEvaluatePatchBasisNormalized(patchType, param,
uv.s, uv.t, wP, wDu, wDv, wDuu, wDuv, wDvv); uv.s, uv.t, wP, wDu, wDv, wDuu, wDuv, wDvv);
#else
int patchType = OSD_PATCH_DESCRIPTOR_QUADS;
OsdPatchParam param = OsdPatchParamInit(0, 0, 0);
int numPoints = OsdEvaluatePatchBasisNormalized(patchType, param,
uv.s, uv.t, wP, wDu, wDv, wDuu, wDuv, wDvv);
#endif
int patchArrayStride = numPoints; int patchArrayStride = numPoints;
int primOffset = patchIndex * patchArrayStride; int primOffset = patchIndex * patchArrayStride;
@ -230,27 +236,22 @@ void emit(int index, vec3 normal)
#endif #endif
#ifdef SHADING_FACEVARYING_COLOR #ifdef SHADING_FACEVARYING_COLOR
#ifdef LOOP // ----- scheme : LOOP
#ifdef SHADING_FACEVARYING_UNIFORM_SUBDIVISION #ifdef SHADING_FACEVARYING_UNIFORM_SUBDIVISION
// interpolate fvar data at refined tri or quad vertex locations
#ifdef PRIM_TRI
vec2 trist[3] = vec2[](vec2(0,0), vec2(1,0), vec2(0,1)); vec2 trist[3] = vec2[](vec2(0,0), vec2(1,0), vec2(0,1));
vec2 st = trist[index]; vec2 st = trist[index];
#else
vec2 st = inpt[index].v.tessCoord;
#endif #endif
vec2 uv = interpolateFaceVarying(st, /*fvarOffset=*/0); #ifdef PRIM_QUAD
#else // ----- scheme : CATMARK / BILINEAR
#ifdef SHADING_FACEVARYING_UNIFORM_SUBDIVISION
vec2 quadst[4] = vec2[](vec2(0,0), vec2(1,0), vec2(1,1), vec2(0,1)); vec2 quadst[4] = vec2[](vec2(0,0), vec2(1,0), vec2(1,1), vec2(0,1));
vec2 st = quadst[index]; vec2 st = quadst[index];
#endif
#else #else
// interpolate fvar data at tessellated vertex locations
vec2 st = inpt[index].v.tessCoord; vec2 st = inpt[index].v.tessCoord;
#endif #endif
vec2 uv = interpolateFaceVarying(st, /*fvarOffset=*/0);
#endif // ------ scheme vec2 uv = interpolateFaceVarying(st, /*fvarOffset*/0);
outpt.color = vec3(uv.s, uv.t, 0); outpt.color = vec3(uv.s, uv.t, 0);
#endif #endif
@ -324,8 +325,8 @@ void main()
#endif // PRIM_QUAD #endif // PRIM_QUAD
#ifdef PRIM_TRI #ifdef PRIM_TRI
vec3 A = (inpt[1].v.position - inpt[0].v.position).xyz; vec3 A = (inpt[0].v.position - inpt[1].v.position).xyz;
vec3 B = (inpt[2].v.position - inpt[0].v.position).xyz; vec3 B = (inpt[2].v.position - inpt[1].v.position).xyz;
vec3 n0 = normalize(cross(B, A)); vec3 n0 = normalize(cross(B, A));
#if defined(GEOMETRY_OUT_WIRE) || defined(GEOMETRY_OUT_LINE) #if defined(GEOMETRY_OUT_WIRE) || defined(GEOMETRY_OUT_LINE)
@ -502,7 +503,7 @@ getAdaptivePatchColor(ivec3 patchParam)
patchType = 3; // CORNER (not correct for patches that are not isolated) patchType = 3; // CORNER (not correct for patches that are not isolated)
} }
#if defined(OSD_PATCH_ENABLE_SINGLE_CREASE) && !defined(LOOP) #if defined OSD_PATCH_ENABLE_SINGLE_CREASE
// check this after boundary/corner since single crease patch also has edgeCount. // check this after boundary/corner since single crease patch also has edgeCount.
if (inpt.vSegments.y > 0) { if (inpt.vSegments.y > 0) {
patchType = 1; patchType = 1;

View File

@ -90,13 +90,18 @@ enum {
-(void)keyDown:(NSEvent *)event { -(void)keyDown:(NSEvent *)event {
const auto key = [event.charactersIgnoringModifiers characterAtIndex:0]; const auto key = [event.charactersIgnoringModifiers characterAtIndex:0];
if(key == '=') { if (hud.KeyDown(key)) {
_controller.osdRenderer.tessellationLevel = std::min(_controller.osdRenderer.tessellationLevel + 1, 16.0f); return;
} else if(key == '=') {
_controller.osdRenderer.tessellationLevel = std::min(_controller.osdRenderer.tessellationLevel + 1, 16);
} else if (key == '-') { } else if (key == '-') {
_controller.osdRenderer.tessellationLevel = std::max(_controller.osdRenderer.tessellationLevel - 1, 0.0f); _controller.osdRenderer.tessellationLevel = std::max(_controller.osdRenderer.tessellationLevel - 1, 0);
} else if(!hud.KeyDown(key)) } else if (key == 'f') {
[_controller.osdRenderer fitFrame];
} else {
[super keyDown:event]; [super keyDown:event];
} }
}
-(void)scrollWheel:(NSEvent *)event { -(void)scrollWheel:(NSEvent *)event {
_controller.osdRenderer.camera->dollyDistance += event.deltaY / 100.0; _controller.osdRenderer.camera->dollyDistance += event.deltaY / 100.0;
@ -184,6 +189,9 @@ enum {
case kHUD_CB_FRACTIONAL_SPACING: case kHUD_CB_FRACTIONAL_SPACING:
self.osdRenderer.useFractionalTessellation = checked; self.osdRenderer.useFractionalTessellation = checked;
break; break;
case kHUD_CB_SEAMLESS_MIPMAP:
self.osdRenderer.useSeamlessMipmap = checked;
break;
default: default:
assert("Unknown checkbox ID" && 0); assert("Unknown checkbox ID" && 0);
} }
@ -397,8 +405,6 @@ enum {
auto commandBuffer = [_commandQueue commandBuffer]; auto commandBuffer = [_commandQueue commandBuffer];
_osdRenderer.displacementScale = 3;
double avg = 0; double avg = 0;
for(int i = 0; i < FRAME_HISTORY; i++) for(int i = 0; i < FRAME_HISTORY; i++)
avg += _frameBeginTimestamp[i]; avg += _frameBeginTimestamp[i];
@ -408,7 +414,7 @@ enum {
auto& hud = self.view->hud; auto& hud = self.view->hud;
if(hud.IsVisible()) { if(hud.IsVisible()) {
hud.DrawString(10, -120, "Tess level : %f", _osdRenderer.tessellationLevel); hud.DrawString(10, -120, "Tess level : %d", _osdRenderer.tessellationLevel);
hud.DrawString(10, -20, "FPS = %3.1f", 1.0 / avg); hud.DrawString(10, -20, "FPS = %3.1f", 1.0 / avg);
//Disable Culling & Force Fill mode when drawing the UI //Disable Culling & Force Fill mode when drawing the UI

View File

@ -1,111 +0,0 @@
//
// Copyright 2013 Pixar
//
// Licensed under the Apache License, Version 2.0 (the "Apache License")
// with the following modification; you may not use this file except in
// compliance with the Apache License and the following modification to it:
// Section 6. Trademarks. is deleted and replaced with:
//
// 6. Trademarks. This License does not grant permission to use the trade
// names, trademarks, service marks, or product names of the Licensor
// and its affiliates, except as required to comply with Section 4(c) of
// the License and to reproduce the content of the NOTICE file.
//
// You may obtain a copy of the Apache License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the Apache License with the above modification is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the Apache License for the specific
// language governing permissions and limitations under the Apache License.
//
#include "../../regression/common/shape_utils.h"
#include "../../regression/shapes/all.h"
static std::vector<ShapeDesc> g_defaultShapes;
//------------------------------------------------------------------------------
static void initShapes() {
// g_defaultShapes.push_back(ShapeDesc("temple", Viewer::shapes::temple, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_cube_corner0", catmark_cube_corner0, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_cube_corner1", catmark_cube_corner1, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_cube_corner2", catmark_cube_corner2, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_cube_corner3", catmark_cube_corner3, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_cube_corner4", catmark_cube_corner4, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_cube_creases0", catmark_cube_creases0, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_cube_creases1", catmark_cube_creases1, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_cube_creases2", catmark_cube_creases2, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_cube", catmark_cube, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_dart_edgecorner", catmark_dart_edgecorner, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_dart_edgeonly", catmark_dart_edgeonly, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_edgecorner", catmark_edgecorner, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_edgeonly", catmark_edgeonly, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_chaikin0", catmark_chaikin0, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_chaikin1", catmark_chaikin1, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_chaikin2", catmark_chaikin2, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_fan", catmark_fan, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_flap", catmark_flap, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_flap2", catmark_flap2, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_fvar_bound0", catmark_fvar_bound0, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_fvar_bound1", catmark_fvar_bound1, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_fvar_bound2", catmark_fvar_bound2, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_gregory_test0", catmark_gregory_test0, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_gregory_test1", catmark_gregory_test1, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_gregory_test2", catmark_gregory_test2, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_gregory_test3", catmark_gregory_test3, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_gregory_test4", catmark_gregory_test4, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_gregory_test5", catmark_gregory_test5, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_gregory_test6", catmark_gregory_test6, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_gregory_test7", catmark_gregory_test7, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_hole_test1", catmark_hole_test1, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_hole_test2", catmark_hole_test2, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_hole_test3", catmark_hole_test3, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_hole_test4", catmark_hole_test4, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_lefthanded", catmark_lefthanded, kCatmark, true /*isLeftHanded*/));
g_defaultShapes.push_back(ShapeDesc("catmark_righthanded", catmark_righthanded, kCatmark));
// g_defaultShapes.push_back(ShapeDesc("catmark_pole8", catmark_pole8, kCatmark));
// g_defaultShapes.push_back(ShapeDesc("catmark_pole64", catmark_pole64, kCatmark));
// g_defaultShapes.push_back(ShapeDesc("catmark_nonman_quadpole8", catmark_nonman_quadpole8, kCatmark));
// g_defaultShapes.push_back(ShapeDesc("catmark_nonman_quadpole64", catmark_nonman_quadpole64, kCatmark));
// g_defaultShapes.push_back(ShapeDesc("catmark_nonman_quadpole360", catmark_nonman_quadpole360, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_pyramid_creases0", catmark_pyramid_creases0, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_pyramid_creases1", catmark_pyramid_creases1, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_pyramid", catmark_pyramid, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_tent_creases0", catmark_tent_creases0, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_tent_creases1", catmark_tent_creases1, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_tent", catmark_tent, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_torus", catmark_torus, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_torus_creases0", catmark_torus_creases0, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_single_crease", catmark_single_crease, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_smoothtris0", catmark_smoothtris0, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_smoothtris1", catmark_smoothtris1, kCatmark));
// // g_defaultShapes.push_back( ShapeDesc("catmark_square_hedit0", catmark_square_hedit0, kCatmark ) );
// // g_defaultShapes.push_back( ShapeDesc("catmark_square_hedit1", catmark_square_hedit1, kCatmark ) );
// // g_defaultShapes.push_back( ShapeDesc("catmark_square_hedit2", catmark_square_hedit2, kCatmark ) );
// // g_defaultShapes.push_back( ShapeDesc("catmark_square_hedit3", catmark_square_hedit3, kCatmark ) );
g_defaultShapes.push_back(ShapeDesc("catmark_bishop", catmark_bishop, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_car", catmark_car, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_helmet", catmark_helmet, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_pawn", catmark_pawn, kCatmark));
g_defaultShapes.push_back(ShapeDesc("catmark_rook", catmark_rook, kCatmark));
//
// g_defaultShapes.push_back(ShapeDesc("bilinear_cube", bilinear_cube, kBilinear));
//
// g_defaultShapes.push_back(ShapeDesc("loop_cube_creases0", loop_cube_creases0, kLoop));
// g_defaultShapes.push_back(ShapeDesc("loop_cube_creases1", loop_cube_creases1, kLoop));
// g_defaultShapes.push_back(ShapeDesc("loop_cube", loop_cube, kLoop));
// g_defaultShapes.push_back(ShapeDesc("loop_icosahedron", loop_icosahedron, kLoop));
// g_defaultShapes.push_back(ShapeDesc("loop_saddle_edgecorner", loop_saddle_edgecorner, kLoop));
// g_defaultShapes.push_back(ShapeDesc("loop_saddle_edgeonly", loop_saddle_edgeonly, kLoop));
// g_defaultShapes.push_back(ShapeDesc("loop_triangle_edgecorner", loop_triangle_edgecorner, kLoop));
// g_defaultShapes.push_back(ShapeDesc("loop_triangle_edgeonly", loop_triangle_edgeonly, kLoop));
// g_defaultShapes.push_back(ShapeDesc("loop_chaikin0", loop_chaikin0, kLoop));
// g_defaultShapes.push_back(ShapeDesc("loop_chaikin1", loop_chaikin1, kLoop));
// g_defaultShapes.push_back(ShapeDesc("loop_pole8", loop_pole8, kLoop));
// g_defaultShapes.push_back(ShapeDesc("loop_pole64", loop_pole64, kLoop));
// g_defaultShapes.push_back(ShapeDesc("loop_pole360", loop_pole360, kLoop));
}

View File

@ -63,13 +63,12 @@ typedef struct {
-(id<MTLRenderCommandEncoder>)drawFrame:(id<MTLCommandBuffer>)commandBuffer; -(id<MTLRenderCommandEncoder>)drawFrame:(id<MTLCommandBuffer>)commandBuffer;
-(void)fitFrame;
@property (readonly, nonatomic) id<OSDRendererDelegate> delegate; @property (readonly, nonatomic) id<OSDRendererDelegate> delegate;
@property (nonatomic) unsigned refinementLevel; @property (nonatomic) unsigned refinementLevel;
@property (nonatomic) float tessellationLevel; @property (nonatomic) int tessellationLevel;
@property (readonly, nonatomic) NSArray<NSString*>* loadedModels;
@property (nonatomic) NSString* currentModel;
@property (readonly, nonatomic) Camera* camera; @property (readonly, nonatomic) Camera* camera;
@ -80,7 +79,8 @@ typedef struct {
@property (nonatomic) bool usePatchIndexBuffer; @property (nonatomic) bool usePatchIndexBuffer;
@property (nonatomic) bool usePatchBackfaceCulling; @property (nonatomic) bool usePatchBackfaceCulling;
@property (nonatomic) bool usePatchClipCulling; @property (nonatomic) bool usePatchClipCulling;
@property (nonatomic) bool useSingleCrease; @property (nonatomic) bool useSmoothCornerPatch;
@property (nonatomic) bool useSingleCreasePatch;
@property (nonatomic) bool useInfinitelySharpPatch; @property (nonatomic) bool useInfinitelySharpPatch;
@property (nonatomic) bool useStageIn; @property (nonatomic) bool useStageIn;
@property (nonatomic) bool usePrimitiveBackfaceCulling; @property (nonatomic) bool usePrimitiveBackfaceCulling;
@ -91,6 +91,7 @@ typedef struct {
@property (nonatomic) bool displayControlMeshVertices; @property (nonatomic) bool displayControlMeshVertices;
@property (nonatomic) bool displaySpecular; @property (nonatomic) bool displaySpecular;
@property (nonatomic) bool displayOcclusion; @property (nonatomic) bool displayOcclusion;
@property (nonatomic) bool yup;
@property (nonatomic) float mipmapBias; @property (nonatomic) float mipmapBias;
@property (nonatomic) float displacementScale; @property (nonatomic) float displacementScale;

View File

@ -1,6 +1,6 @@
#line 0 "examples/mtlPtexViewer/mtlPtexViewer.metal" #line 0 "examples/mtlPtexViewer/mtlPtexViewer.metal"
// //
// Copyright 2013 Pixar // Copyright 2013-2019 Pixar
// //
// Licensed under the Apache License, Version 2.0 (the "Apache License") // Licensed under the Apache License, Version 2.0 (the "Apache License")
// with the following modification; you may not use this file except in // with the following modification; you may not use this file except in
@ -26,6 +26,10 @@
#include <metal_stdlib> #include <metal_stdlib>
using namespace metal; using namespace metal;
#if OSD_IS_ADAPTIVE
static_assert(!OSD_ENABLE_SCREENSPACE_TESSELLATION || !USE_PTVS_FACTORS, "USE_PTVS_FACTORS cannot be enabled if OSD_ENABLE_SCREENSPACE_TESSELLATION is enabled");
#endif
struct Config { struct Config {
float displacementScale; float displacementScale;
float mipmapBias; float mipmapBias;
@ -64,11 +68,11 @@ const constant float4 patchColors[] = {
float4(0.0f, 0.8f, 0.75f, 1.0f), // boundary pattern 4 float4(0.0f, 0.8f, 0.75f, 1.0f), // boundary pattern 4
float4(0.0f, 1.0f, 0.0f, 1.0f), // corner float4(0.0f, 1.0f, 0.0f, 1.0f), // corner
float4(0.25f, 0.25f, 0.25f, 1.0f), // corner pattern 0 float4(0.5f, 1.0f, 0.5f, 1.0f), // corner pattern 0
float4(0.25f, 0.25f, 0.25f, 1.0f), // corner pattern 1 float4(0.5f, 1.0f, 0.5f, 1.0f), // corner pattern 1
float4(0.25f, 0.25f, 0.25f, 1.0f), // corner pattern 2 float4(0.5f, 1.0f, 0.5f, 1.0f), // corner pattern 2
float4(0.25f, 0.25f, 0.25f, 1.0f), // corner pattern 3 float4(0.5f, 1.0f, 0.5f, 1.0f), // corner pattern 3
float4(0.25f, 0.25f, 0.25f, 1.0f), // corner pattern 4 float4(0.5f, 1.0f, 0.5f, 1.0f), // corner pattern 4
float4(1.0f, 1.0f, 0.0f, 1.0f), // gregory float4(1.0f, 1.0f, 0.0f, 1.0f), // gregory
float4(1.0f, 1.0f, 0.0f, 1.0f), // gregory float4(1.0f, 1.0f, 0.0f, 1.0f), // gregory
@ -95,33 +99,32 @@ const constant float4 patchColors[] = {
float4 float4
getAdaptivePatchColor(int3 patchParam, float sharpness) getAdaptivePatchColor(int3 patchParam, float sharpness)
{ {
int pattern = popcount(OsdGetPatchTransitionMask(patchParam));
int edgeCount = popcount(OsdGetPatchBoundaryMask(patchParam));
int patchType = 0; int patchType = 0;
#if OSD_PATCH_ENABLE_SINGLE_CREASE
if (sharpness > 0) {
pattern = 1;
}
#endif
int edgeCount = popcount(OsdGetPatchBoundaryMask(patchParam));
if (edgeCount == 1) { if (edgeCount == 1) {
patchType = 2; // BOUNDARY patchType = 2; // BOUNDARY
} }
if (edgeCount == 2) { if (edgeCount > 1) {
patchType = 3; // CORNER patchType = 3; // CORNER
} }
// XXX: it looks like edgeCount != 0 for some gregory boundary patches. #if OSD_PATCH_ENABLE_SINGLE_CREASE
// there might be a bug somewhere... if (sharpness > 0) {
#if OSD_PATCH_GREGORY patchType = 1;
}
#elif OSD_PATCH_GREGORY
patchType = 4; patchType = 4;
#elif OSD_PATCH_GREGORY_BOUNDARY #elif OSD_PATCH_GREGORY_BOUNDARY
patchType = 5; patchType = 5;
#elif OSD_PATCH_GREGORY_BASIS #elif OSD_PATCH_GREGORY_BASIS
patchType = 6; patchType = 6;
#elif OSD_PATCH_GREGORY_TRIANGLE
patchType = 6;
#endif #endif
int pattern = popcount(OsdGetPatchTransitionMask(patchParam));
return patchColors[6*patchType + pattern]; return patchColors[6*patchType + pattern];
} }
@ -248,10 +251,9 @@ struct FragmentInput
#if OSD_IS_ADAPTIVE #if OSD_IS_ADAPTIVE
#if USE_STAGE_IN #if USE_STAGE_IN
#if OSD_PATCH_REGULAR #if OSD_PATCH_REGULAR || OSD_PATCH_BOX_SPLINE_TRIANGLE
struct ControlPoint struct ControlPoint
{ {
float3 P [[attribute(0)]]; float3 P [[attribute(0)]];
#if OSD_PATCH_ENABLE_SINGLE_CREASE #if OSD_PATCH_ENABLE_SINGLE_CREASE
float3 P1 [[attribute(1)]]; float3 P1 [[attribute(1)]];
@ -261,6 +263,21 @@ struct ControlPoint
#endif #endif
#endif #endif
}; };
#elif OSD_PATCH_GREGORY || OSD_PATCH_GREGORY_BOUNDARY
struct ControlPoint
{
float3 P [[attribute(0)]];
float3 Ep [[attribute(1)]];
float3 Em [[attribute(2)]];
float3 Fp [[attribute(3)]];
float3 Fm [[attribute(4)]];
};
#elif OSD_PATCH_GREGORY_BASIS || OSD_PATCH_GREGORY_TRIANGLE
struct ControlPoint
{
float3 position [[attribute(0)]];
};
#endif
struct PatchInput struct PatchInput
{ {
@ -271,77 +288,67 @@ struct PatchInput
#endif #endif
int3 patchParam [[attribute(10)]]; int3 patchParam [[attribute(10)]];
}; };
#elif OSD_PATCH_GREGORY || OSD_PATCH_GREGORY_BOUNDARY
struct ControlPoint
{
float3 P [[attribute(0)]];
float3 Ep [[attribute(1)]];
float3 Em [[attribute(2)]];
float3 Fp [[attribute(3)]];
float3 Fm [[attribute(4)]];
};
struct PatchInput
{
patch_control_point<ControlPoint> cv;
int3 patchParam [[attribute(10)]];
};
#elif OSD_PATCH_GREGORY_BASIS
struct ControlPoint
{
float3 position [[attribute(0)]];
};
struct PatchInput
{
patch_control_point<ControlPoint> cv;
int3 patchParam [[attribute(10)]];
};
#endif #endif
#if OSD_PATCH_REGULAR || OSD_PATCH_GREGORY_BASIS || OSD_PATCH_GREGORY || OSD_PATCH_GREGORY_BOUNDARY
typedef MTLQuadTessellationFactorsHalf PatchTessFactors;
#elif OSD_PATCH_BOX_SPLINE_TRIANGLE || OSD_PATCH_GREGORY_TRIANGLE
typedef MTLTriangleTessellationFactorsHalf PatchTessFactors;
#endif #endif
kernel void compute_main( kernel void compute_main(
const constant PerFrameConstants& frameConsts [[buffer(FRAME_CONST_BUFFER_INDEX)]], const constant PerFrameConstants& frameConsts [[buffer(FRAME_CONST_BUFFER_INDEX)]],
unsigned thread_position_in_grid [[thread_position_in_grid]], unsigned thread_position_in_grid [[thread_position_in_grid]],
unsigned thread_position_in_threadgroup [[thread_position_in_threadgroup]], unsigned thread_position_in_threadgroup [[thread_position_in_threadgroup]],
unsigned threadgroup_position_in_grid [[threadgroup_position_in_grid]], unsigned threadgroup_position_in_grid [[threadgroup_position_in_grid]],
OsdPatchParamBufferSet osdBuffers, OsdPatchParamBufferSet osdBuffers,
device MTLQuadTessellationFactorsHalf* quadTessellationFactors [[buffer(QUAD_TESSFACTORS_INDEX)]] device PatchTessFactors* patchTessellationFactors [[buffer(PATCH_TESSFACTORS_INDEX)]]
#if OSD_USE_PATCH_INDEX_BUFFER #if OSD_USE_PATCH_INDEX_BUFFER
,device unsigned* patchIndex [[buffer(OSD_PATCH_INDEX_BUFFER_INDEX)]] ,device unsigned* patchIndex [[buffer(OSD_PATCH_INDEX_BUFFER_INDEX)]]
,device MTLDrawPatchIndirectArguments* drawIndirectCommands [[buffer(OSD_DRAWINDIRECT_BUFFER_INDEX)]] ,device MTLDrawPatchIndirectArguments* drawIndirectCommands [[buffer(OSD_DRAWINDIRECT_BUFFER_INDEX)]]
#endif #endif
) )
{ {
//----------------------------------------------------------
// OSD Kernel Setup
//----------------------------------------------------------
#define PATCHES_PER_THREADGROUP (THREADS_PER_THREADGROUP / THREADS_PER_PATCH)
int const primitiveID = thread_position_in_grid / THREADS_PER_PATCH;
int const primitiveIDInTG = thread_position_in_threadgroup / THREADS_PER_PATCH;
int const vertexIndex = threadgroup_position_in_grid * PATCHES_PER_THREADGROUP * CONTROL_POINTS_PER_PATCH +
thread_position_in_threadgroup * CONTROL_POINTS_PER_THREAD;
int const vertexIndexInTG = thread_position_in_threadgroup * CONTROL_POINTS_PER_THREAD;
int const invocationID = (thread_position_in_threadgroup * VERTEX_CONTROL_POINTS_PER_THREAD) % (THREADS_PER_PATCH*VERTEX_CONTROL_POINTS_PER_THREAD);
//Contains the shared patchParam value used by all threads that act upon a single patch
//the .z (sharpness) field is set to -1 (NAN) if that patch should be culled to signal other threads to return.
threadgroup int3 patchParam[PATCHES_PER_THREADGROUP]; threadgroup int3 patchParam[PATCHES_PER_THREADGROUP];
threadgroup PatchVertexType patchVertices[PATCHES_PER_THREADGROUP * CONTROL_POINTS_PER_PATCH]; threadgroup PatchVertexType patchVertices[PATCHES_PER_THREADGROUP * CONTROL_POINTS_PER_PATCH];
const auto real_threadgroup = thread_position_in_grid / REAL_THREADGROUP_DIVISOR; //----------------------------------------------------------
const auto subthreadgroup_in_threadgroup = thread_position_in_threadgroup / REAL_THREADGROUP_DIVISOR; // OSD Vertex Transform
const auto real_thread_in_threadgroup = thread_position_in_threadgroup & (REAL_THREADGROUP_DIVISOR - 1); //----------------------------------------------------------
#if NEEDS_BARRIER
const auto validThread = thread_position_in_grid * CONTROL_POINTS_PER_THREAD < osdBuffers.kernelExecutionLimit;
#else
const auto validThread = true;
if(thread_position_in_grid * CONTROL_POINTS_PER_THREAD >= osdBuffers.kernelExecutionLimit)
return;
#endif
if(validThread)
{ {
patchParam[subthreadgroup_in_threadgroup] = OsdGetPatchParam(real_threadgroup, osdBuffers.patchParamBuffer); patchParam[primitiveIDInTG] = OsdGetPatchParam(primitiveID, osdBuffers.patchParamBuffer);
for(unsigned threadOffset = 0; threadOffset < CONTROL_POINTS_PER_THREAD; threadOffset++) for (unsigned threadOffset = 0; threadOffset < CONTROL_POINTS_PER_THREAD; ++threadOffset)
{ {
const auto vertexId = osdBuffers.indexBuffer[(thread_position_in_grid * CONTROL_POINTS_PER_THREAD + threadOffset) * IndexLookupStride]; if (vertexIndexInTG + threadOffset < PATCHES_PER_THREADGROUP * CONTROL_POINTS_PER_PATCH)
{
const auto vertexId = osdBuffers.indexBuffer[(vertexIndex + threadOffset)];
const auto v = osdBuffers.vertexBuffer[vertexId]; const auto v = osdBuffers.vertexBuffer[vertexId];
threadgroup auto& patchVertex = patchVertices[thread_position_in_threadgroup * CONTROL_POINTS_PER_THREAD + threadOffset]; threadgroup auto& patchVertex = patchVertices[vertexIndexInTG + threadOffset];
//----------------------------------------------------------
// User Vertex Transform
//----------------------------------------------------------
OsdComputePerVertex(float4(v.position,1), patchVertex, vertexId, frameConsts.ModelViewProjectionMatrix, osdBuffers); OsdComputePerVertex(float4(v.position,1), patchVertex, vertexId, frameConsts.ModelViewProjectionMatrix, osdBuffers);
//User per vertex goes here, modifying 'patchVertex' }
} }
} }
@ -349,27 +356,31 @@ kernel void compute_main(
threadgroup_barrier(mem_flags::mem_threadgroup); threadgroup_barrier(mem_flags::mem_threadgroup);
#endif #endif
if(validThread) //----------------------------------------------------------
// OSD Patch Cull
//----------------------------------------------------------
{ {
#if PATCHES_PER_THREADGROUP > 1 auto patch = patchVertices + primitiveIDInTG * CONTROL_POINTS_PER_PATCH;
auto patch = patchVertices + subthreadgroup_in_threadgroup * CONTROL_POINTS_PER_THREAD * CONTROL_POINTS_PER_PATCH;
#else
//Small optimization for the '1 patch per threadgroup' case
auto patch = patchVertices;
#endif
if (!OsdCullPerPatchVertex(patch, frameConsts.ModelViewMatrix)) if (!OsdCullPerPatchVertex(patch, frameConsts.ModelViewMatrix))
{ {
#if !OSD_USE_PATCH_INDEX_BUFFER #if !OSD_USE_PATCH_INDEX_BUFFER
quadTessellationFactors[real_threadgroup].edgeTessellationFactor[0] = 0.0h; #if OSD_PATCH_REGULAR || OSD_PATCH_GREGORY_BASIS || OSD_PATCH_GREGORY || OSD_PATCH_GREGORY_BOUNDARY
quadTessellationFactors[real_threadgroup].edgeTessellationFactor[1] = 0.0h; patchTessellationFactors[primitiveID].edgeTessellationFactor[0] = 0.0h;
quadTessellationFactors[real_threadgroup].edgeTessellationFactor[2] = 0.0h; patchTessellationFactors[primitiveID].edgeTessellationFactor[1] = 0.0h;
quadTessellationFactors[real_threadgroup].edgeTessellationFactor[3] = 0.0h; patchTessellationFactors[primitiveID].edgeTessellationFactor[2] = 0.0h;
quadTessellationFactors[real_threadgroup].insideTessellationFactor[0] = 0.0h; patchTessellationFactors[primitiveID].edgeTessellationFactor[3] = 0.0h;
quadTessellationFactors[real_threadgroup].insideTessellationFactor[1] = 0.0h; patchTessellationFactors[primitiveID].insideTessellationFactor[0] = 0.0h;
patchTessellationFactors[primitiveID].insideTessellationFactor[1] = 0.0h;
#elif OSD_PATCH_BOX_SPLINE_TRIANGLE || OSD_PATCH_GREGORY_TRIANGLE
patchTessellationFactors[primitiveID].edgeTessellationFactor[0] = 0.0h;
patchTessellationFactors[primitiveID].edgeTessellationFactor[1] = 0.0h;
patchTessellationFactors[primitiveID].edgeTessellationFactor[2] = 0.0h;
patchTessellationFactors[primitiveID].insideTessellationFactor = 0.0h;
#endif
#endif #endif
patchParam[subthreadgroup_in_threadgroup].z = -1; patchParam[primitiveIDInTG].z = -1;
#if !NEEDS_BARRIER #if !NEEDS_BARRIER
return; return;
#endif #endif
@ -380,44 +391,53 @@ kernel void compute_main(
threadgroup_barrier(mem_flags::mem_threadgroup); threadgroup_barrier(mem_flags::mem_threadgroup);
#endif #endif
if(validThread && patchParam[subthreadgroup_in_threadgroup].z != -1) //----------------------------------------------------------
// OSD Patch Compute
//----------------------------------------------------------
if (patchParam[primitiveIDInTG].z != -1)
{ {
for(unsigned threadOffset = 0; threadOffset < CONTROL_POINTS_PER_THREAD; threadOffset++) for (unsigned threadOffset = 0; threadOffset < VERTEX_CONTROL_POINTS_PER_THREAD; ++threadOffset)
{
if (invocationID + threadOffset < VERTEX_CONTROL_POINTS_PER_PATCH)
{ {
OsdComputePerPatchVertex( OsdComputePerPatchVertex(
patchParam[subthreadgroup_in_threadgroup], patchParam[primitiveIDInTG],
real_thread_in_threadgroup * CONTROL_POINTS_PER_THREAD + threadOffset, invocationID + threadOffset,
real_threadgroup, primitiveID,
thread_position_in_grid * CONTROL_POINTS_PER_THREAD + threadOffset, invocationID + threadOffset + primitiveID * VERTEX_CONTROL_POINTS_PER_PATCH,
patchVertices + subthreadgroup_in_threadgroup * CONTROL_POINTS_PER_PATCH, patchVertices + primitiveIDInTG * CONTROL_POINTS_PER_PATCH,
osdBuffers osdBuffers
); );
} }
} }
}
#if NEEDS_BARRIER #if NEEDS_BARRIER
threadgroup_barrier(mem_flags::mem_device_and_threadgroup); threadgroup_barrier(mem_flags::mem_device_and_threadgroup);
#endif #endif
if(validThread && real_thread_in_threadgroup == 0) //----------------------------------------------------------
// OSD Tessellation Factors
//----------------------------------------------------------
if (invocationID == 0)
{ {
#if OSD_USE_PATCH_INDEX_BUFFER #if OSD_USE_PATCH_INDEX_BUFFER
const auto patchId = atomic_fetch_add_explicit((device atomic_uint*)&drawIndirectCommands->patchCount, 1, memory_order_relaxed); const auto patchId = atomic_fetch_add_explicit((device atomic_uint*)&drawIndirectCommands->patchCount, 1, memory_order_relaxed);
patchIndex[patchId] = real_threadgroup; patchIndex[patchId] = primitiveID;
#else #else
const auto patchId = real_threadgroup; const auto patchId = primitiveID;
#endif #endif
OsdComputePerPatchFactors( OsdComputePerPatchFactors(
patchParam[subthreadgroup_in_threadgroup], patchParam[primitiveIDInTG],
frameConsts.TessLevel, frameConsts.TessLevel,
real_threadgroup, primitiveID,
frameConsts.ProjectionMatrix, frameConsts.ProjectionMatrix,
frameConsts.ModelViewMatrix, frameConsts.ModelViewMatrix,
osdBuffers, osdBuffers,
patchVertices + subthreadgroup_in_threadgroup * CONTROL_POINTS_PER_PATCH, patchVertices + primitiveIDInTG * CONTROL_POINTS_PER_PATCH,
quadTessellationFactors[patchId] patchTessellationFactors[patchId]
); );
} }
} }
@ -607,14 +627,14 @@ fragment float4 fragment_main(
float3 normal = perturbNormalFromDisplacement(input.position.xyz, float3 normal = perturbNormalFromDisplacement(input.position.xyz,
input.normal, input.normal,
input.patchCoord, input.patchCoord,
config.mipmapBias, mipmapBias,
textureDisplace_Data, textureDisplace_Data,
textureDisplace_Packing, textureDisplace_Packing,
config.displacementScale); displacementScale);
#elif NORMAL_BIQUADRATIC || NORMAL_BIQUADRATIC_WG #elif NORMAL_BIQUADRATIC || NORMAL_BIQUADRATIC_WG
float4 du, dv; float4 du, dv;
float4 disp = PtexMipmapLookupQuadratic(du, dv, input.patchCoord, float4 disp = PtexMipmapLookupQuadratic(du, dv, input.patchCoord,
config.mipmapBias, mipmapBias,
textureDisplace_Data, textureDisplace_Data,
textureDisplace_Packing); textureDisplace_Packing);
@ -655,15 +675,15 @@ fragment float4 fragment_main(
textureImage_Packing); textureImage_Packing);
#elif COLOR_PATCHTYPE #elif COLOR_PATCHTYPE
float4 texColor = lighting(float4(input.patchColor), input.position.xyz, normal, 0, lightSource); float4 texColor = lighting(float4(input.patchColor), input.position.xyz, normal, 0, lightSource);
outColor = texColor; outColor = max(texColor, shade);
return outColor; return outColor;
#elif COLOR_PATCHCOORD #elif COLOR_PATCHCOORD
float4 texColor = lighting(input.patchCoord, input.position.xyz, normal, 0, lightSource); float4 texColor = lighting(input.patchCoord, input.position.xyz, normal, 0, lightSource);
outColor = texColor; outColor = max(texColor, shade);
return outColor; return outColor;
#elif COLOR_NORMAL #elif COLOR_NORMAL
float4 texColor = float4(normal.x, normal.y, normal.z, 1); float4 texColor = float4(normal.x, normal.y, normal.z, 1);
outColor = texColor; outColor = max(texColor, shade);
return outColor; return outColor;
#else // COLOR_NONE #else // COLOR_NONE
float4 texColor = float4(0.5, 0.5, 0.5, 1); float4 texColor = float4(0.5, 0.5, 0.5, 1);
@ -672,7 +692,7 @@ fragment float4 fragment_main(
// ------------ occlusion --------------- // ------------ occlusion ---------------
#if USE_PTEX_OCCLUSION #if USE_PTEX_OCCLUSION
float occ = PtexMipmapLookup(input.patchCoord, config.mipmapBias, float occ = PtexMipmapLookup(input.patchCoord, mipmapBias,
textureOcclusion_Data, textureOcclusion_Data,
textureOcclusion_Packing).x; textureOcclusion_Packing).x;
#else #else
@ -682,7 +702,7 @@ fragment float4 fragment_main(
// ------------ specular --------------- // ------------ specular ---------------
#if USE_PTEX_SPECULAR #if USE_PTEX_SPECULAR
float specular = PtexMipmapLookup(input.patchCoord, config.mipmapBias, float specular = PtexMipmapLookup(input.patchCoord, mipmapBias,
textureSpecular_Data, textureSpecular_Data,
textureSpecular_Packing).x; textureSpecular_Packing).x;
#else #else

File diff suppressed because it is too large Load Diff

View File

@ -87,13 +87,18 @@ enum {
-(void)keyDown:(NSEvent *)event { -(void)keyDown:(NSEvent *)event {
const auto key = [event.charactersIgnoringModifiers characterAtIndex:0]; const auto key = [event.charactersIgnoringModifiers characterAtIndex:0];
if(key == '=') { if (hud.KeyDown(key)) {
return;
} else if(key == '=') {
_controller.osdRenderer.tessellationLevel = std::min(_controller.osdRenderer.tessellationLevel + 1, 16); _controller.osdRenderer.tessellationLevel = std::min(_controller.osdRenderer.tessellationLevel + 1, 16);
} else if (key == '-') { } else if (key == '-') {
_controller.osdRenderer.tessellationLevel = std::max(_controller.osdRenderer.tessellationLevel - 1, 0); _controller.osdRenderer.tessellationLevel = std::max(_controller.osdRenderer.tessellationLevel - 1, 0);
} else if(!hud.KeyDown(key)) } else if (key == 'f') {
[_controller.osdRenderer fitFrame];
} else {
[super keyDown:event]; [super keyDown:event];
} }
}
-(void)scrollWheel:(NSEvent *)event { -(void)scrollWheel:(NSEvent *)event {
_controller.osdRenderer.camera->dollyDistance += event.deltaY / 100.0; _controller.osdRenderer.camera->dollyDistance += event.deltaY / 100.0;
@ -300,8 +305,8 @@ enum {
hud.AddCheckBox("Fractional spacing (T)", _osdRenderer.useFractionalTessellation, hud.AddCheckBox("Fractional spacing (T)", _osdRenderer.useFractionalTessellation,
10, y, callbackCheckbox, kHUD_CB_FRACTIONAL_SPACING, 't'); 10, y, callbackCheckbox, kHUD_CB_FRACTIONAL_SPACING, 't');
y += 20; y += 20;
hud.AddCheckBox("Frustum Patch Culling (F)", _osdRenderer.usePatchClipCulling, hud.AddCheckBox("Frustum Patch Culling (P)", _osdRenderer.usePatchClipCulling,
10, y, callbackCheckbox, kHUD_CB_PATCH_CULL, 'f'); 10, y, callbackCheckbox, kHUD_CB_PATCH_CULL, 'p');
y += 20; y += 20;
hud.AddCheckBox("Backface Culling (B)", _osdRenderer.usePatchBackfaceCulling, hud.AddCheckBox("Backface Culling (B)", _osdRenderer.usePatchBackfaceCulling,
10, y, callbackCheckbox, kHUD_CB_BACK_CULL, 'b'); 10, y, callbackCheckbox, kHUD_CB_BACK_CULL, 'b');
@ -392,7 +397,7 @@ enum {
hud.AddPullDownButton(endcap_pulldown, "Gregory", hud.AddPullDownButton(endcap_pulldown, "Gregory",
kEndCapGregoryBasis, kEndCapGregoryBasis,
_osdRenderer.endCapMode == kEndCapGregoryBasis); _osdRenderer.endCapMode == kEndCapGregoryBasis);
if (true || _osdRenderer.legacyGregoryEnabled) { if (_osdRenderer.legacyGregoryEnabled) {
hud.AddPullDownButton(endcap_pulldown, "LegacyGregory", hud.AddPullDownButton(endcap_pulldown, "LegacyGregory",
kEndCapLegacyGregory, kEndCapLegacyGregory,
_osdRenderer.endCapMode == kEndCapLegacyGregory); _osdRenderer.endCapMode == kEndCapLegacyGregory);
@ -402,7 +407,7 @@ enum {
for (int i = 1; i < 11; ++i) { for (int i = 1; i < 11; ++i) {
char level[16]; char level[16];
sprintf(level, "Lv. %d", i); sprintf(level, "Lv. %d", i);
hud.AddRadioButton(3, level, i==2, 10, 310+i*20, callbackLevel, i, '0'+(i%10)); hud.AddRadioButton(3, level, i==_osdRenderer.refinementLevel, 10, 310+i*20, callbackLevel, i, '0'+(i%10));
} }
int shapes_pulldown = hud.AddPullDown("Shape (N)", -300, 10, 300, callbackModel, 'n'); int shapes_pulldown = hud.AddPullDown("Shape (N)", -300, 10, 300, callbackModel, 'n');

View File

@ -98,7 +98,7 @@
_osdRenderer.displayControlMeshVertices = _controlMeshSwitch.isOn; _osdRenderer.displayControlMeshVertices = _controlMeshSwitch.isOn;
_osdRenderer.displayControlMeshEdges = _controlMeshSwitch.isOn; _osdRenderer.displayControlMeshEdges = _controlMeshSwitch.isOn;
_osdRenderer.usePatchClipCulling = _patchClipCullingSwitch.isOn; _osdRenderer.usePatchClipCulling = _patchClipCullingSwitch.isOn;
_osdRenderer.useFractionalTessellation = _osdRenderer.useScreenspaceTessellation; _osdRenderer.useFractionalTessellation = _osdRenderer.useFractionalTessellation;
_osdRenderer.useAdaptive = true; _osdRenderer.useAdaptive = true;
_osdRenderer.freeze = true; _osdRenderer.freeze = true;
_osdRenderer.animateVertices = false; _osdRenderer.animateVertices = false;
@ -210,7 +210,7 @@
_osdRenderer.displayControlMeshVertices = sender.isOn; _osdRenderer.displayControlMeshVertices = sender.isOn;
} else if(sender == _screenspaceTessellationSwitch) { } else if(sender == _screenspaceTessellationSwitch) {
_osdRenderer.useScreenspaceTessellation = sender.isOn; _osdRenderer.useScreenspaceTessellation = sender.isOn;
_osdRenderer.useFractionalTessellation = _osdRenderer.useScreenspaceTessellation; _osdRenderer.useFractionalTessellation = _osdRenderer.useFractionalTessellation;
} }
} }

View File

@ -72,6 +72,7 @@ static void initShapes() {
g_defaultShapes.push_back(ShapeDesc("catmark_car", catmark_car, kCatmark)); g_defaultShapes.push_back(ShapeDesc("catmark_car", catmark_car, kCatmark));
g_defaultShapes.push_back(ShapeDesc("loop_toroidal_tet", loop_toroidal_tet, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_toroidal_tet", loop_toroidal_tet, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_tetrahedron", loop_tetrahedron, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_cube", loop_cube, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_cube", loop_cube, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_cubes_semisharp", loop_cubes_semisharp, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_cubes_semisharp", loop_cubes_semisharp, kLoop));
g_defaultShapes.push_back(ShapeDesc("loop_cubes_infsharp", loop_cubes_infsharp, kLoop)); g_defaultShapes.push_back(ShapeDesc("loop_cubes_infsharp", loop_cubes_infsharp, kLoop));

View File

@ -30,8 +30,8 @@
typedef enum { typedef enum {
kEndCapBilinearBasis = 0, kEndCapBilinearBasis = 0,
kEndCapBSplineBasis, kEndCapBSplineBasis,
kEndCapLegacyGregory,
kEndCapGregoryBasis, kEndCapGregoryBasis,
kEndCapLegacyGregory,
} EndCap; } EndCap;
typedef enum { typedef enum {
@ -86,6 +86,8 @@ typedef struct {
-(id<MTLRenderCommandEncoder>)drawFrame:(id<MTLCommandBuffer>)commandBuffer; -(id<MTLRenderCommandEncoder>)drawFrame:(id<MTLCommandBuffer>)commandBuffer;
-(void)fitFrame;
@property (readonly, nonatomic) id<OSDRendererDelegate> delegate; @property (readonly, nonatomic) id<OSDRendererDelegate> delegate;
@property (nonatomic) unsigned refinementLevel; @property (nonatomic) unsigned refinementLevel;
@ -109,6 +111,7 @@ typedef struct {
@property (nonatomic) bool useStageIn; @property (nonatomic) bool useStageIn;
@property (nonatomic) bool usePrimitiveBackfaceCulling; @property (nonatomic) bool usePrimitiveBackfaceCulling;
@property (nonatomic) bool useAdaptive; @property (nonatomic) bool useAdaptive;
@property (nonatomic) bool yup;
@property (nonatomic) bool freeze; @property (nonatomic) bool freeze;
@property (nonatomic) bool animateVertices; @property (nonatomic) bool animateVertices;
@property (nonatomic) bool displayControlMeshEdges; @property (nonatomic) bool displayControlMeshEdges;

View File

@ -47,11 +47,13 @@
#import <opensubdiv/osd/mtlComputeEvaluator.h> #import <opensubdiv/osd/mtlComputeEvaluator.h>
#import <opensubdiv/osd/mtlPatchShaderSource.h> #import <opensubdiv/osd/mtlPatchShaderSource.h>
#import "../common/simple_math.h"
#import "../../regression/common/far_utils.h" #import "../../regression/common/far_utils.h"
#import "init_shapes.h" #import "../common/argOptions.h"
#import "../common/mtlUtils.h" #import "../common/mtlUtils.h"
#import "../common/mtlControlMeshDisplay.h" #import "../common/mtlControlMeshDisplay.h"
#import "../common/simple_math.h"
#import "../common/viewerArgsUtils.h"
#import "init_shapes.h"
#define VERTEX_BUFFER_INDEX 0 #define VERTEX_BUFFER_INDEX 0
#define PATCH_INDICES_BUFFER_INDEX 1 #define PATCH_INDICES_BUFFER_INDEX 1
@ -150,8 +152,9 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
PerFrameBuffer<unsigned> _patchIndexBuffers[DISPATCHSLOTS]; PerFrameBuffer<unsigned> _patchIndexBuffers[DISPATCHSLOTS];
unsigned _tessFactorOffsets[DISPATCHSLOTS]; unsigned _tessFactorsOffsets[DISPATCHSLOTS];
unsigned _perPatchVertexOffsets[DISPATCHSLOTS]; unsigned _perPatchVertexOffsets[DISPATCHSLOTS];
unsigned _perPatchTessFactorsOffsets[DISPATCHSLOTS];
unsigned _threadgroupSizes[DISPATCHSLOTS]; unsigned _threadgroupSizes[DISPATCHSLOTS];
id<MTLComputePipelineState> _computePipelines[DISPATCHSLOTS]; id<MTLComputePipelineState> _computePipelines[DISPATCHSLOTS];
@ -187,6 +190,7 @@ using PerFrameBuffer = MTLRingBuffer<DataType, FRAME_LAG>;
bool _needsRebuild; bool _needsRebuild;
NSString* _osdShaderSource; NSString* _osdShaderSource;
simd::float3 _meshCenter; simd::float3 _meshCenter;
float _meshSize;
NSMutableArray<NSString*>* _loadedModels; NSMutableArray<NSString*>* _loadedModels;
int _patchCounts[DISPATCHSLOTS]; int _patchCounts[DISPATCHSLOTS];
} }
@ -300,26 +304,62 @@ struct PipelineConfig {
return config; return config;
} }
-(void)_processArgs {
NSEnumerator *argsArray =
[[[NSProcessInfo processInfo] arguments] objectEnumerator];
std::vector<char *> argsVector;
for (id arg in argsArray) {
argsVector.push_back((char *)[arg UTF8String]);
}
ArgOptions args;
args.Parse(argsVector.size(), argsVector.data());
// Parse remaining args
const std::vector<const char *> &rargs = args.GetRemainingArgs();
for (size_t i = 0; i < rargs.size(); ++i) {
if (!strcmp(rargs[i], "-lg")) {
self.legacyGregoryEnabled = true;
} else {
args.PrintUnrecognizedArgWarning(rargs[i]);
}
}
self.yup = args.GetYUp();
self.useAdaptive = args.GetAdaptive();
self.refinementLevel = args.GetLevel();
ViewerArgsUtils::PopulateShapes(args, &g_defaultShapes);
}
-(instancetype)initWithDelegate:(id<OSDRendererDelegate>)delegate { -(instancetype)initWithDelegate:(id<OSDRendererDelegate>)delegate {
self = [super init]; self = [super init];
if (self) { if (self) {
self.useSmoothCornerPatch = false; self.useSmoothCornerPatch = true;
self.useSingleCreasePatch = true; self.useSingleCreasePatch = true;
self.useInfinitelySharpPatch = false; self.useInfinitelySharpPatch = true;
self.useStageIn = !TARGET_OS_EMBEDDED; self.useStageIn = true;
self.endCapMode = kEndCapBSplineBasis; self.endCapMode = kEndCapGregoryBasis;
self.useScreenspaceTessellation = true; self.useScreenspaceTessellation = false;
self.useFractionalTessellation = false;
self.usePatchClipCulling = false; self.usePatchClipCulling = false;
self.usePatchIndexBuffer = false; self.usePatchIndexBuffer = false;
self.usePatchBackfaceCulling = false; self.usePatchBackfaceCulling = false;
self.usePrimitiveBackfaceCulling = false; self.usePrimitiveBackfaceCulling = false;
self.useAdaptive = true; self.useAdaptive = true;
self.yup = false;
self.kernelType = kMetal; self.kernelType = kMetal;
self.refinementLevel = 2; self.refinementLevel = 2;
self.tessellationLevel = 1; self.tessellationLevel = 1;
self.shadingMode = kShadingPatchType; self.shadingMode = kShadingPatchType;
self.displayStyle = kDisplayStyleWireOnShaded; self.displayStyle = kDisplayStyleWireOnShaded;
self.legacyGregoryEnabled = true; self.legacyGregoryEnabled = false;
[self _processArgs];
_frameCount = 0; _frameCount = 0;
_animationFrames = 0; _animationFrames = 0;
@ -409,6 +449,10 @@ struct PipelineConfig {
return renderEncoder; return renderEncoder;
} }
-(void)fitFrame {
_cameraData.dollyDistance = _meshSize;
}
-(void)_renderMesh:(id<MTLRenderCommandEncoder>)renderCommandEncoder { -(void)_renderMesh:(id<MTLRenderCommandEncoder>)renderCommandEncoder {
auto patchVertexBuffer = _mesh->BindVertexBuffer(); auto patchVertexBuffer = _mesh->BindVertexBuffer();
@ -476,7 +520,8 @@ struct PipelineConfig {
if (pipelineConfig.useTessellation) { if (pipelineConfig.useTessellation) {
[renderCommandEncoder setVertexBufferOffset:patch.primitiveIdBase * sizeof(int) * 3 atIndex:OSD_PATCHPARAM_BUFFER_INDEX]; [renderCommandEncoder setVertexBufferOffset:patch.primitiveIdBase * sizeof(int) * 3 atIndex:OSD_PATCHPARAM_BUFFER_INDEX];
[renderCommandEncoder setTessellationFactorBuffer:_tessFactorsBuffer offset:_tessFactorOffsets[patchType] instanceStride:0]; [renderCommandEncoder setTessellationFactorBuffer:_tessFactorsBuffer offset:_tessFactorsOffsets[patchType] instanceStride:0];
[renderCommandEncoder setVertexBufferOffset:_perPatchTessFactorsOffsets[patchType] atIndex:OSD_PERPATCHTESSFACTORS_BUFFER_INDEX];
if (!pipelineConfig.drawIndexed) { if (!pipelineConfig.drawIndexed) {
[renderCommandEncoder setVertexBufferOffset:_perPatchVertexOffsets[patchType] atIndex:OSD_PERPATCHVERTEX_BUFFER_INDEX]; [renderCommandEncoder setVertexBufferOffset:_perPatchVertexOffsets[patchType] atIndex:OSD_PERPATCHVERTEX_BUFFER_INDEX];
@ -619,20 +664,24 @@ struct PipelineConfig {
[computeCommandEncoder setBuffer:_mesh->GetPatchTable()->GetPatchParamBuffer() offset:0 atIndex:OSD_PATCHPARAM_BUFFER_INDEX]; [computeCommandEncoder setBuffer:_mesh->GetPatchTable()->GetPatchParamBuffer() offset:0 atIndex:OSD_PATCHPARAM_BUFFER_INDEX];
[computeCommandEncoder setBuffer:_frameConstantsBuffer offset:0 atIndex:FRAME_CONST_BUFFER_INDEX]; [computeCommandEncoder setBuffer:_frameConstantsBuffer offset:0 atIndex:FRAME_CONST_BUFFER_INDEX];
[computeCommandEncoder setBuffer:_perPatchTessFactorsBuffer offset:0 atIndex:OSD_PERPATCHTESSFACTORS_BUFFER_INDEX];
for (auto& patch : _mesh->GetPatchTable()->GetPatchArrays()) for (auto& patch : _mesh->GetPatchTable()->GetPatchArrays())
{ {
auto patchType = patch.desc.GetType(); auto patchType = patch.desc.GetType();
PipelineConfig pipelineConfig = [self _lookupPipelineConfig:patchType useSingleCreasePatch:_useSingleCreasePatch]; PipelineConfig pipelineConfig = [self _lookupPipelineConfig:patchType useSingleCreasePatch:_useSingleCreasePatch];
// Don't compute tess factors when not using tessellation
if (!pipelineConfig.useTessellation) {
continue;
}
[computeCommandEncoder setComputePipelineState:_computePipelines[patchType]]; [computeCommandEncoder setComputePipelineState:_computePipelines[patchType]];
[computeCommandEncoder setBufferOffset:patch.primitiveIdBase * sizeof(int) * 3 atIndex:OSD_PATCHPARAM_BUFFER_INDEX]; [computeCommandEncoder setBufferOffset:patch.primitiveIdBase * sizeof(int) * 3 atIndex:OSD_PATCHPARAM_BUFFER_INDEX];
[computeCommandEncoder setBufferOffset:patch.indexBase * sizeof(unsigned) atIndex:CONTROL_INDICES_BUFFER_INDEX]; [computeCommandEncoder setBufferOffset:patch.indexBase * sizeof(unsigned) atIndex:CONTROL_INDICES_BUFFER_INDEX];
if (pipelineConfig.useTessellation) { if (pipelineConfig.useTessellation) {
[computeCommandEncoder setBuffer:_tessFactorsBuffer offset:_tessFactorOffsets[patchType] atIndex:PATCH_TESSFACTORS_INDEX]; [computeCommandEncoder setBuffer:_tessFactorsBuffer offset:_tessFactorsOffsets[patchType] atIndex:PATCH_TESSFACTORS_INDEX];
[computeCommandEncoder setBuffer:_perPatchTessFactorsBuffer offset:_perPatchTessFactorsOffsets[patchType] atIndex:OSD_PERPATCHTESSFACTORS_BUFFER_INDEX];
[computeCommandEncoder setBuffer:_perPatchVertexBuffer offset:_perPatchVertexOffsets[patchType] atIndex:OSD_PERPATCHVERTEX_BUFFER_INDEX]; [computeCommandEncoder setBuffer:_perPatchVertexBuffer offset:_perPatchVertexOffsets[patchType] atIndex:OSD_PERPATCHVERTEX_BUFFER_INDEX];
} }
if (pipelineConfig.useLegacyBuffers) { if (pipelineConfig.useLegacyBuffers) {
@ -668,7 +717,6 @@ struct PipelineConfig {
auto shapeDesc = &g_defaultShapes[[_loadedModels indexOfObject:_currentModel]]; auto shapeDesc = &g_defaultShapes[[_loadedModels indexOfObject:_currentModel]];
_shape.reset(Shape::parseObj(shapeDesc->data.c_str(), shapeDesc->scheme)); _shape.reset(Shape::parseObj(shapeDesc->data.c_str(), shapeDesc->scheme));
const auto scheme = shapeDesc->scheme;
// create Far mesh (topology) // create Far mesh (topology)
Sdc::SchemeType sdctype = GetSdcType(*_shape); Sdc::SchemeType sdctype = GetSdcType(*_shape);
@ -746,7 +794,6 @@ struct PipelineConfig {
} }
_vertexData.resize(refBaseLevel.GetNumVertices() * numElements); _vertexData.resize(refBaseLevel.GetNumVertices() * numElements);
_meshCenter = simd::float3{0,0,0};
for(int i = 0; i < refBaseLevel.GetNumVertices(); ++i) for(int i = 0; i < refBaseLevel.GetNumVertices(); ++i)
{ {
@ -755,14 +802,24 @@ struct PipelineConfig {
_vertexData[i * numElements + 2] = _shape->verts[i * 3 + 2]; _vertexData[i * numElements + 2] = _shape->verts[i * 3 + 2];
} }
for(auto vertexIdx = 0; vertexIdx < refBaseLevel.GetNumVertices(); ++vertexIdx) // compute model bounding
{ float min[3] = { FLT_MAX, FLT_MAX, FLT_MAX};
_meshCenter[0] += _vertexData[vertexIdx * numElements + 0]; float max[3] = {-FLT_MAX,-FLT_MAX,-FLT_MAX};
_meshCenter[1] += _vertexData[vertexIdx * numElements + 1]; for (int i = 0; i < refBaseLevel.GetNumVertices(); ++i) {
_meshCenter[2] += _vertexData[vertexIdx * numElements + 2]; for (int j = 0; j < 3; ++j) {
float v = _vertexData[i*numElements+j];
min[j] = std::min(min[j], v);
max[j] = std::max(max[j], v);
}
} }
_meshCenter /= (_shape->verts.size() / 3); _meshSize = 0.0f;
for (int j = 0; j < 3; ++j) {
_meshCenter[j] = (min[j] + max[j]) * 0.5f;
_meshSize += (max[j]-min[j])*(max[j]-min[j]);
}
_meshSize = sqrt(_meshSize);
_mesh->UpdateVertexBuffer(_vertexData.data(), 0, refBaseLevel.GetNumVertices()); _mesh->UpdateVertexBuffer(_vertexData.data(), 0, refBaseLevel.GetNumVertices());
_mesh->Refine(); _mesh->Refine();
_mesh->Synchronize(); _mesh->Synchronize();
@ -879,7 +936,8 @@ struct PipelineConfig {
-(void)_rebuildBuffers { -(void)_rebuildBuffers {
auto totalPatches = 0; auto totalPatches = 0;
auto totalPatchDataSize = 0; auto totalPerPatchVertexSize = 0;
auto totalPerPatchTessFactorsSize = 0;
auto totalTessFactorsSize = 0; auto totalTessFactorsSize = 0;
if (_usePatchIndexBuffer) if (_usePatchIndexBuffer)
@ -906,9 +964,11 @@ struct PipelineConfig {
{ {
_patchIndexBuffers[patchType].alloc(_context.device, patch.GetNumPatches(), @"patch indices", MTLResourceStorageModePrivate); _patchIndexBuffers[patchType].alloc(_context.device, patch.GetNumPatches(), @"patch indices", MTLResourceStorageModePrivate);
} }
_perPatchVertexOffsets[patchType] = totalPatchDataSize; _perPatchTessFactorsOffsets[patchType] = totalPerPatchTessFactorsSize;
_tessFactorOffsets[patchType] = totalTessFactorsSize; _perPatchVertexOffsets[patchType] = totalPerPatchVertexSize;
totalPatchDataSize += elementFloats * sizeof(float) * patch.GetNumPatches() * pipelineConfig.numControlPointsPerPatchToDraw; _tessFactorsOffsets[patchType] = totalTessFactorsSize;
totalPerPatchTessFactorsSize += 2 * 4 * sizeof(float) * patch.GetNumPatches();
totalPerPatchVertexSize += elementFloats * sizeof(float) * patch.GetNumPatches() * pipelineConfig.numControlPointsPerPatchToDraw;
totalTessFactorsSize += patch.GetNumPatches() * (pipelineConfig.useTriangleTessellation totalTessFactorsSize += patch.GetNumPatches() * (pipelineConfig.useTriangleTessellation
? sizeof(MTLTriangleTessellationFactorsHalf) ? sizeof(MTLTriangleTessellationFactorsHalf)
: sizeof(MTLQuadTessellationFactorsHalf)); : sizeof(MTLQuadTessellationFactorsHalf));
@ -918,8 +978,8 @@ struct PipelineConfig {
} }
_tessFactorsBuffer.alloc(_context.device, totalTessFactorsSize, @"tessellation factors buffer", MTLResourceStorageModePrivate); _tessFactorsBuffer.alloc(_context.device, totalTessFactorsSize, @"tessellation factors buffer", MTLResourceStorageModePrivate);
_perPatchVertexBuffer.alloc(_context.device, totalPatchDataSize, @"per patch data", MTLResourceStorageModePrivate); _perPatchVertexBuffer.alloc(_context.device, totalPerPatchVertexSize, @"per patch data", MTLResourceStorageModePrivate);
_perPatchTessFactorsBuffer.alloc(_context.device, 2 * 4 * sizeof(float) * totalPatches, @"hs constant data", MTLResourceStorageModePrivate); _perPatchTessFactorsBuffer.alloc(_context.device, totalPerPatchTessFactorsSize, @"per patch tess factors", MTLResourceStorageModePrivate);
} }
} }
@ -1178,6 +1238,25 @@ struct PipelineConfig {
vertexDesc.attributes[i].format = MTLVertexFormatFloat3; vertexDesc.attributes[i].format = MTLVertexFormatFloat3;
vertexDesc.attributes[i].offset = i * sizeof(float) * 3; vertexDesc.attributes[i].offset = i * sizeof(float) * 3;
} }
if(_useScreenspaceTessellation)
{
vertexDesc.layouts[OSD_PERPATCHTESSFACTORS_BUFFER_INDEX].stepFunction = MTLVertexStepFunctionPerPatch;
vertexDesc.layouts[OSD_PERPATCHTESSFACTORS_BUFFER_INDEX].stepRate = 1;
vertexDesc.layouts[OSD_PERPATCHTESSFACTORS_BUFFER_INDEX].stride = sizeof(float) * 4 * 2;
// PatchInput :: float4 tessOuterLo [[attribute(5)]];
// OsdPerPatchTessFactors :: float4 tessOuterLo;
vertexDesc.attributes[5].bufferIndex = OSD_PERPATCHTESSFACTORS_BUFFER_INDEX;
vertexDesc.attributes[5].format = MTLVertexFormatFloat4;
vertexDesc.attributes[5].offset = 0;
// PatchInput :: float4 tessOuterHi [[attribute(6)]];
// OsdPerPatchTessFactors :: float4 tessOuterHi;
vertexDesc.attributes[6].bufferIndex = OSD_PERPATCHTESSFACTORS_BUFFER_INDEX;
vertexDesc.attributes[6].format = MTLVertexFormatFloat4;
vertexDesc.attributes[6].offset = sizeof(float) * 4;
}
break; break;
case Far::PatchDescriptor::QUADS: case Far::PatchDescriptor::QUADS:
//Quads cannot use stage in, due to the need for re-indexing. //Quads cannot use stage in, due to the need for re-indexing.
@ -1277,14 +1356,15 @@ struct PipelineConfig {
translate(pData->ModelViewMatrix, 0, 0, -_cameraData.dollyDistance); translate(pData->ModelViewMatrix, 0, 0, -_cameraData.dollyDistance);
rotate(pData->ModelViewMatrix, _cameraData.rotationY, 1, 0, 0); rotate(pData->ModelViewMatrix, _cameraData.rotationY, 1, 0, 0);
rotate(pData->ModelViewMatrix, _cameraData.rotationX, 0, 1, 0); rotate(pData->ModelViewMatrix, _cameraData.rotationX, 0, 1, 0);
rotate(pData->ModelViewMatrix, -90, 1, 0, 0); // z-up model if (!_yup) {
rotate(pData->ModelViewMatrix, -90, 1, 0, 0);
}
translate(pData->ModelViewMatrix, -_meshCenter[0], -_meshCenter[1], -_meshCenter[2]); translate(pData->ModelViewMatrix, -_meshCenter[0], -_meshCenter[1], -_meshCenter[2]);
inverseMatrix(pData->ModelViewInverseMatrix, pData->ModelViewMatrix); inverseMatrix(pData->ModelViewInverseMatrix, pData->ModelViewMatrix);
identity(pData->ProjectionMatrix); identity(pData->ProjectionMatrix);
perspective(pData->ProjectionMatrix, 45.0, _cameraData.aspectRatio, 0.01f, 500.0); perspective(pData->ProjectionMatrix, 45.0, _cameraData.aspectRatio, 0.01f, 500.0);
multMatrix(pData->ModelViewProjectionMatrix, pData->ModelViewMatrix, pData->ProjectionMatrix); multMatrix(pData->ModelViewProjectionMatrix, pData->ModelViewMatrix, pData->ProjectionMatrix);
} }
-(void)_initializeBuffers { -(void)_initializeBuffers {
@ -1293,9 +1373,9 @@ struct PipelineConfig {
} }
-(void)_initializeCamera { -(void)_initializeCamera {
_cameraData.dollyDistance = 4;
_cameraData.rotationY = 0; _cameraData.rotationY = 0;
_cameraData.rotationX = 0; _cameraData.rotationX = 0;
_cameraData.dollyDistance = 5;
_cameraData.aspectRatio = 1; _cameraData.aspectRatio = 1;
} }

View File

@ -833,7 +833,12 @@ PatchBuilder::GetIrregularPatchCornerSpans(int levelIndex, Index faceIndex,
// Sharpen the span if a corner or subject to inf-sharp features: // Sharpen the span if a corner or subject to inf-sharp features:
if (vTag._corner) { if (vTag._corner) {
// Corners tagged in FVar space need additional qualification:
if (isFVarMisMatch) {
cornerSpans[i]._sharp = (cornerSpans[i]._numFaces == 1) || isNonManifold;
} else {
cornerSpans[i]._sharp = true; cornerSpans[i]._sharp = true;
}
} else if (isNonManifold) { } else if (isNonManifold) {
cornerSpans[i]._sharp = vTag._infSharp; cornerSpans[i]._sharp = vTag._infSharp;
} else if (testInfSharpFeatures) { } else if (testInfSharpFeatures) {
@ -1592,8 +1597,13 @@ SourcePatch::GetCornerRingPoints(int corner, int ringPoints[]) const {
} }
} else { } else {
if (_corners[corner]._sharesWithNext) { if (_corners[corner]._sharesWithNext) {
ringPoints[ringSize++] = _corners[cNext]._val2Interior if (_corners[cNext]._val2Interior) {
? cPrev : _localRingOffsets[cNext]; ringPoints[ringSize++] = cPrev;
} else if (_localRingSizes[cNext] == 0) {
ringPoints[ringSize++] = _localRingOffsets[cPrev];
} else {
ringPoints[ringSize++] = _localRingOffsets[cNext];
}
} }
} }
assert(ringSize == _ringSizes[corner]); assert(ringSize == _ringSizes[corner]);

View File

@ -62,7 +62,7 @@ public:
/// face indices and not the base face indices (see Far::PtexIndices for more /// face indices and not the base face indices (see Far::PtexIndices for more
/// details). /// details).
/// ///
/// @param patchFaceId The index of the face /// @param patchFaceId The index of the patch (Ptex) face
/// ///
/// @param u Local u parameter /// @param u Local u parameter
/// ///

View File

@ -168,7 +168,7 @@ public:
StencilTableReal<REAL> const *GetLocalPointStencilTable() const; StencilTableReal<REAL> const *GetLocalPointStencilTable() const;
/// \brief Tests if the precision of the stencil table to compute local point /// \brief Tests if the precision of the stencil table to compute local point
/// vertex values matches the given floating point type <REAL>. /// vertex values matches the given floating point type \<REAL\>.
template <typename REAL> bool LocalPointStencilPrecisionMatchesType() const; template <typename REAL> bool LocalPointStencilPrecisionMatchesType() const;
/// \brief Updates local point vertex values. /// \brief Updates local point vertex values.
@ -198,7 +198,7 @@ public:
StencilTableReal<REAL> const *GetLocalPointVaryingStencilTable() const; StencilTableReal<REAL> const *GetLocalPointVaryingStencilTable() const;
/// \brief Tests if the precision of the stencil table to compute local point /// \brief Tests if the precision of the stencil table to compute local point
/// varying values matches the given floating point type <REAL>. /// varying values matches the given floating point type \<REAL\>.
template <typename REAL> bool LocalPointVaryingStencilPrecisionMatchesType() const; template <typename REAL> bool LocalPointVaryingStencilPrecisionMatchesType() const;
/// \brief Updates local point varying values. /// \brief Updates local point varying values.
@ -228,7 +228,7 @@ public:
StencilTableReal<REAL> const * GetLocalPointFaceVaryingStencilTable(int channel = 0) const; StencilTableReal<REAL> const * GetLocalPointFaceVaryingStencilTable(int channel = 0) const;
/// \brief Tests if the precision of the stencil table to compute local point /// \brief Tests if the precision of the stencil table to compute local point
/// face-varying values matches the given floating point type <REAL>. /// face-varying values matches the given floating point type \<REAL\>.
template <typename REAL> bool LocalPointFaceVaryingStencilPrecisionMatchesType() const; template <typename REAL> bool LocalPointFaceVaryingStencilPrecisionMatchesType() const;
/// \brief Updates local point face-varying values. /// \brief Updates local point face-varying values.

View File

@ -44,12 +44,20 @@ public:
/// ///
struct Options { struct Options {
/// \brief Choice for approximating irregular patches (end-caps)
///
/// This enum specifies how irregular patches (end-caps) are approximated.
/// A basis is chosen, rather than a specific patch type, and has a
/// corresponding patch type for each subdivision scheme, i.e. a quad and
/// triangular patch type exists for each basis. These choices provide a
/// trade-off between surface quality and performance.
///
enum EndCapType { enum EndCapType {
ENDCAP_NONE = 0, ///< no endcap ENDCAP_NONE = 0, ///< unspecified
ENDCAP_BILINEAR_BASIS, ///< use bilinear quads (4 cp) as end-caps ENDCAP_BILINEAR_BASIS, ///< use linear patches (simple quads or tris)
ENDCAP_BSPLINE_BASIS, ///< use BSpline basis patches (16 cp) as end-caps ENDCAP_BSPLINE_BASIS, ///< use BSpline-like patches (same patch type as regular)
ENDCAP_GREGORY_BASIS, ///< use Gregory basis patches (20 cp) as end-caps ENDCAP_GREGORY_BASIS, ///< use Gregory patches (highest quality, recommended default)
ENDCAP_LEGACY_GREGORY ///< use legacy (2.x) Gregory patches (4 cp + valence table) as end-caps ENDCAP_LEGACY_GREGORY ///< legacy option for 2.x style Gregory patches (Catmark only)
}; };
Options(unsigned int maxIsolation=10) : Options(unsigned int maxIsolation=10) :
@ -73,10 +81,10 @@ public:
fvarChannelIndices(0) fvarChannelIndices(0)
{ } { }
/// \brief Get endcap patch type /// \brief Get endcap basis type
EndCapType GetEndCapType() const { return (EndCapType)endCapType; } EndCapType GetEndCapType() const { return (EndCapType)endCapType; }
/// \brief Set endcap patch type /// \brief Set endcap basis type
void SetEndCapType(EndCapType e) { endCapType = e; } void SetEndCapType(EndCapType e) { endCapType = e; }
/// \brief Set precision of vertex patches /// \brief Set precision of vertex patches
@ -175,7 +183,7 @@ public:
// It is no longer used internally and is being kept here to respect preservation // It is no longer used internally and is being kept here to respect preservation
// of the public interface, but it will be deprecated at the earliest opportunity. // of the public interface, but it will be deprecated at the earliest opportunity.
// //
/// \brief Obsolete internal struct accidentally exposed for public use -- due to /// \brief Obsolete internal struct not intended for public use -- due to
/// be deprecated. /// be deprecated.
// //
struct PatchFaceTag { struct PatchFaceTag {

View File

@ -120,7 +120,7 @@ public:
/// @param localPointStencilTable /// @param localPointStencilTable
/// StencilTable for the change of basis patch points. /// StencilTable for the change of basis patch points.
/// ///
/// @param factorize If factorize set to true, endcap stencils will be /// @param factorize If factorize is set to true, endcap stencils will be
/// factorized with supporting vertices from baseStencil /// factorized with supporting vertices from baseStencil
/// table so that the endcap points can be computed /// table so that the endcap points can be computed
/// directly from control vertices. /// directly from control vertices.
@ -140,7 +140,7 @@ public:
/// @param localPointStencilTable /// @param localPointStencilTable
/// StencilTable for the change of basis patch points. /// StencilTable for the change of basis patch points.
/// ///
/// @param factorize If factorize set to true, endcap stencils will be /// @param factorize If factorize is set to true, endcap stencils will be
/// factorized with supporting vertices from baseStencil /// factorized with supporting vertices from baseStencil
/// table so that the endcap points can be computed /// table so that the endcap points can be computed
/// directly from control vertices. /// directly from control vertices.
@ -166,7 +166,7 @@ public:
/// ///
/// @param channel face-varying channel /// @param channel face-varying channel
/// ///
/// @param factorize If factorize sets to true, endcap stencils will be /// @param factorize If factorize is set to true, endcap stencils will be
/// factorized with supporting vertices from baseStencil /// factorized with supporting vertices from baseStencil
/// table so that the endcap points can be computed /// table so that the endcap points can be computed
/// directly from control vertices. /// directly from control vertices.

View File

@ -255,16 +255,16 @@ kernel void eval_patches(
as_type<float>(patchCoords[current*5+3]), as_type<float>(patchCoords[current*5+3]),
as_type<float>(patchCoords[current*5+4])); as_type<float>(patchCoords[current*5+4]));
OsdPatchArray patchArray = OsdPatchArrayInit(patchArrays[current*6+0], OsdPatchArray patchArray = OsdPatchArrayInit(patchArrays[patchCoord.arrayIndex*6+0],
patchArrays[current*6+1], patchArrays[patchCoord.arrayIndex*6+1],
patchArrays[current*6+2], patchArrays[patchCoord.arrayIndex*6+2],
patchArrays[current*6+3], patchArrays[patchCoord.arrayIndex*6+3],
patchArrays[current*6+4], patchArrays[patchCoord.arrayIndex*6+4],
patchArrays[current*6+5]); patchArrays[patchCoord.arrayIndex*6+5]);
OsdPatchParam patchParam = OsdPatchParamInit(patchParams[current*3+0], OsdPatchParam patchParam = OsdPatchParamInit(patchParams[patchCoord.patchIndex*3+0],
patchParams[current*3+1], patchParams[patchCoord.patchIndex*3+1],
as_type<float>(patchParams[current*3+2])); as_type<float>(patchParams[patchCoord.patchIndex*3+2]));
int patchType = OsdPatchParamIsRegular(patchParam) int patchType = OsdPatchParamIsRegular(patchParam)
? patchArray.regDesc : patchArray.desc; ? patchArray.regDesc : patchArray.desc;

View File

@ -34,8 +34,8 @@
#include <opensubdiv/far/primvarRefiner.h> #include <opensubdiv/far/primvarRefiner.h>
#include <opensubdiv/far/stencilTableFactory.h> #include <opensubdiv/far/stencilTableFactory.h>
#include <opensubdiv/far/patchTableFactory.h> #include <opensubdiv/far/patchTableFactory.h>
#include "../../regression/common/far_utils.h" #include "../../regression/common/far_utils.h"
// XXX: revisit the directory structure for examples/tests
#include "../../examples/common/stopwatch.h" #include "../../examples/common/stopwatch.h"
#include "init_shapes.h" #include "init_shapes.h"
@ -44,8 +44,33 @@
using namespace OpenSubdiv; using namespace OpenSubdiv;
struct Result { struct TestOptions {
TestOptions() :
refineLevel(2),
refineAdaptive(true),
createPatches(true),
createStencils(true),
endCapType(Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS) { }
int refineLevel;
bool refineAdaptive;
bool createPatches;
bool createStencils;
Far::PatchTableFactory::Options::EndCapType endCapType;
};
struct TestResult {
TestResult() :
level(-1),
timeTotal(0),
timeRefine(0),
timePatchFactory(0),
timeStencilFactory(0),
timeAppendStencil(0) { }
std::string name; std::string name;
int level;
double timeTotal; double timeTotal;
double timeRefine; double timeRefine;
double timePatchFactory; double timePatchFactory;
@ -54,74 +79,76 @@ struct Result {
}; };
template <typename REAL> template <typename REAL>
static Result static TestResult
doPerf(std::string const & name, RunPerfTest(Shape const & shape, TestOptions const & options) {
Shape const * shape,
int level,
bool adaptive,
Far::PatchTableFactory::Options::EndCapType endCapType)
{
typedef Far::StencilTableReal<REAL> FarStencilTable; typedef Far::StencilTableReal<REAL> FarStencilTable;
typedef Far::StencilTableFactoryReal<REAL> FarStencilTableFactory; typedef Far::StencilTableFactoryReal<REAL> FarStencilTableFactory;
Sdc::SchemeType sdcType = GetSdcType(*shape); Sdc::SchemeType sdcType = GetSdcType(shape);
Sdc::Options sdcOptions = GetSdcOptions(*shape); Sdc::Options sdcOptions = GetSdcOptions(shape);
Result result; TestResult result;
result.name = name; result.level = options.refineLevel;
Stopwatch s; Stopwatch s;
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// Configure the patch table factory options // Configure the patch table factory options
Far::PatchTableFactory::Options poptions(level); Far::PatchTableFactory::Options poptions(options.refineLevel);
poptions.SetEndCapType(endCapType); poptions.SetEndCapType(options.endCapType);
poptions.SetPatchPrecision<REAL>(); poptions.SetPatchPrecision<REAL>();
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// Instantiate a FarTopologyRefiner from the descriptor and refine // Instantiate a FarTopologyRefiner from the descriptor and refine
s.Start();
Far::TopologyRefiner * refiner = Far::TopologyRefinerFactory<Shape>::Create( Far::TopologyRefiner * refiner = Far::TopologyRefinerFactory<Shape>::Create(
*shape, Far::TopologyRefinerFactory<Shape>::Options(sdcType, sdcOptions)); shape, Far::TopologyRefinerFactory<Shape>::Options(sdcType, sdcOptions));
{ assert(refiner);
if (adaptive) {
Far::TopologyRefiner::AdaptiveOptions options = s.Start();
if (options.refineAdaptive) {
Far::TopologyRefiner::AdaptiveOptions rOptions =
poptions.GetRefineAdaptiveOptions(); poptions.GetRefineAdaptiveOptions();
refiner->RefineAdaptive(options); refiner->RefineAdaptive(rOptions);
} else { } else {
Far::TopologyRefiner::UniformOptions options(level); Far::TopologyRefiner::UniformOptions rOptions(options.refineLevel);
refiner->RefineUniform(options); refiner->RefineUniform(rOptions);
}
} }
s.Stop(); s.Stop();
result.timeRefine = s.GetElapsed(); result.timeRefine = s.GetElapsed();
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// Create patch table // Create patch table
s.Start();
Far::PatchTable const * patchTable = NULL; Far::PatchTable const * patchTable = NULL;
{ if (options.createPatches) {
s.Start();
patchTable = Far::PatchTableFactory::Create(*refiner, poptions); patchTable = Far::PatchTableFactory::Create(*refiner, poptions);
}
s.Stop(); s.Stop();
result.timePatchFactory = s.GetElapsed(); result.timePatchFactory = s.GetElapsed();
} else {
result.timePatchFactory = 0;
}
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// Create stencil table // Create stencil table
s.Start();
FarStencilTable const * vertexStencils = NULL; FarStencilTable const * vertexStencils = NULL;
{ if (options.createStencils) {
s.Start();
typename FarStencilTableFactory::Options options; typename FarStencilTableFactory::Options options;
vertexStencils = FarStencilTableFactory::Create(*refiner, options); vertexStencils = FarStencilTableFactory::Create(*refiner, options);
}
s.Stop(); s.Stop();
result.timeStencilFactory = s.GetElapsed(); result.timeStencilFactory = s.GetElapsed();
} else {
result.timeStencilFactory = 0;
}
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// append local points to stencils // append local points to stencils
if (options.createPatches && options.createStencils) {
s.Start(); s.Start();
{
if (FarStencilTable const *vertexStencilsWithLocalPoints = if (FarStencilTable const *vertexStencilsWithLocalPoints =
FarStencilTableFactory::AppendLocalPointStencilTable( FarStencilTableFactory::AppendLocalPointStencilTable(
*refiner, vertexStencils, *refiner, vertexStencils,
@ -129,24 +156,127 @@ doPerf(std::string const & name,
delete vertexStencils; delete vertexStencils;
vertexStencils = vertexStencilsWithLocalPoints; vertexStencils = vertexStencilsWithLocalPoints;
} }
}
s.Stop(); s.Stop();
result.timeAppendStencil = s.GetElapsed(); result.timeAppendStencil = s.GetElapsed();
} else {
result.timeAppendStencil = 0;
}
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
result.timeTotal = s.GetTotalElapsed(); result.timeTotal = s.GetTotalElapsed();
delete vertexStencils;
delete patchTable;
delete refiner;
return result; return result;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
struct PrintOptions {
PrintOptions() :
csvFormat(false),
refineTime(true),
patchTime(true),
stencilTime(true),
appendTime(true),
totalTime(true) { }
bool csvFormat;
bool refineTime;
bool patchTime;
bool stencilTime;
bool appendTime;
bool totalTime;
};
static void
PrintShape(ShapeDesc const & shapeDesc, PrintOptions const & ) {
static char const * g_schemeNames[3] = { "bilinear", "catmark", "loop" };
char const * shapeName = shapeDesc.name.c_str();
Scheme shapeScheme = shapeDesc.scheme;
printf("%s (%s):\n", shapeName, g_schemeNames[shapeScheme]);
}
static void
PrintResult(TestResult const & result, PrintOptions const & options) {
// If only printing the total, combine on same line as level:
if (!options.refineTime && !options.patchTime &&
!options.stencilTime && !options.appendTime) {
printf(" level %d: %f\n", result.level, result.timeTotal);
return;
}
printf(" level %d:\n", result.level);
if (options.refineTime) {
printf(" TopologyRefiner::Refine %f %5.2f%%\n",
result.timeRefine,
result.timeRefine/result.timeTotal*100);
}
if (options.patchTime) {
printf(" PatchTableFactory::Create %f %5.2f%%\n",
result.timePatchFactory,
result.timePatchFactory/result.timeTotal*100);
}
if (options.stencilTime) {
printf(" StencilTableFactory::Create %f %5.2f%%\n",
result.timeStencilFactory,
result.timeStencilFactory/result.timeTotal*100);
}
if (options.appendTime) {
printf(" StencilTableFactory::Append %f %5.2f%%\n",
result.timeAppendStencil,
result.timeAppendStencil/result.timeTotal*100);
}
if (options.totalTime) {
printf(" Total %f\n",
result.timeTotal);
}
}
static void
PrintHeaderCSV(PrintOptions const & options) {
// spreadsheet header row
printf("shape");
printf(",level");
if (options.refineTime) printf(",refine");
if (options.patchTime) printf(",patch");
if (options.stencilTime) printf(",stencilFactory");
if (options.appendTime) printf(",stencilAppend");
if (options.totalTime) printf(",total");
printf("\n");
}
static void
PrintResultCSV(TestResult const & result, PrintOptions const & options) {
// spreadsheet data row
printf("%s", result.name.c_str());
printf(",%d", result.level);
if (options.refineTime) printf(",%f", result.timeRefine);
if (options.patchTime) printf(",%f", result.timePatchFactory);
if (options.stencilTime) printf(",%f", result.timeStencilFactory);
if (options.appendTime) printf(",%f", result.timeAppendStencil);
if (options.totalTime) printf(",%f", result.timeTotal);
printf("\n");
}
//------------------------------------------------------------------------------
static int static int
parseIntArg(char const * argString, int dfltValue = 0) { parseIntArg(char const * argString, int dfltValue = 0) {
char *argEndptr; char *argEndptr;
int argValue = strtol(argString, &argEndptr, 10); int argValue = strtol(argString, &argEndptr, 10);
if (*argEndptr != 0) { if (*argEndptr != 0) {
printf("Warning: non-integer option parameter '%s' ignored\n", fprintf(stderr,
"Warning: non-integer option parameter '%s' ignored\n",
argString); argString);
argValue = dfltValue; argValue = dfltValue;
} }
@ -155,30 +285,23 @@ parseIntArg(char const * argString, int dfltValue = 0) {
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
bool adaptive = true; TestOptions testOptions;
int level = 8; PrintOptions printOptions;
std::vector<std::string> objFiles;
Scheme defaultScheme = kCatmark; Scheme defaultScheme = kCatmark;
Far::PatchTableFactory::Options::EndCapType endCapType = int minLevel = 1;
Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS; int maxLevel = 2;
bool runDouble = false; bool runDouble = false;
bool spreadsheet = false;
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
if (strstr(argv[i], ".obj")) { if (strstr(argv[i], ".obj")) {
std::ifstream ifs(argv[i]); objFiles.push_back(std::string(argv[i]));
if (ifs) {
std::stringstream ss;
ss << ifs.rdbuf();
ifs.close();
g_shapes.push_back(
ShapeDesc(argv[i], ss.str(), defaultScheme));
}
} else if (!strcmp(argv[i], "-a")) { } else if (!strcmp(argv[i], "-a")) {
adaptive = true; testOptions.refineAdaptive = true;
} else if (!strcmp(argv[i], "-u")) { } else if (!strcmp(argv[i], "-u")) {
adaptive = false; testOptions.refineAdaptive = false;
} else if (!strcmp(argv[i], "-l")) { } else if (!strcmp(argv[i], "-l")) {
if (++i < argc) level = parseIntArg(argv[i], 8); if (++i < argc) maxLevel = parseIntArg(argv[i], maxLevel);
} else if (!strcmp(argv[i], "-bilinear")) { } else if (!strcmp(argv[i], "-bilinear")) {
defaultScheme = kBilinear; defaultScheme = kBilinear;
} else if (!strcmp(argv[i], "-catmark")) { } else if (!strcmp(argv[i], "-catmark")) {
@ -188,22 +311,57 @@ int main(int argc, char **argv)
} else if (!strcmp(argv[i], "-e")) { } else if (!strcmp(argv[i], "-e")) {
char const * type = argv[++i]; char const * type = argv[++i];
if (!strcmp(type, "linear")) { if (!strcmp(type, "linear")) {
endCapType = testOptions.endCapType =
Far::PatchTableFactory::Options::ENDCAP_BILINEAR_BASIS; Far::PatchTableFactory::Options::ENDCAP_BILINEAR_BASIS;
} else if (!strcmp(type, "regular")) { } else if (!strcmp(type, "regular")) {
endCapType = testOptions.endCapType =
Far::PatchTableFactory::Options::ENDCAP_BSPLINE_BASIS; Far::PatchTableFactory::Options::ENDCAP_BSPLINE_BASIS;
} else if (!strcmp(type, "gregory")) { } else if (!strcmp(type, "gregory")) {
endCapType = testOptions.endCapType =
Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS; Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS;
} else { } else {
printf("Unknown endcap type %s\n", type); fprintf(stderr, "Error: Unknown endcap type %s\n", type);
return 1; return 1;
} }
} else if (!strcmp(argv[i], "-double")) { } else if (!strcmp(argv[i], "-double")) {
runDouble = true; runDouble = true;
} else if (!strcmp(argv[i], "-spreadsheet")) { } else if (!strcmp(argv[i], "-nopatches")) {
spreadsheet = true; testOptions.createPatches = false;
printOptions.patchTime = false;
printOptions.appendTime = false;
} else if (!strcmp(argv[i], "-nostencils")) {
testOptions.createStencils = false;
printOptions.stencilTime = false;
printOptions.appendTime = false;
} else if (!strcmp(argv[i], "-total")) {
printOptions.refineTime = false;
printOptions.patchTime = false;
printOptions.stencilTime = false;
printOptions.appendTime = false;
} else if (!strcmp(argv[i], "-csv")) {
printOptions.csvFormat = true;
} else {
fprintf(stderr,
"Warning: unrecognized argument '%s' ignored\n", argv[i]);
}
}
assert(minLevel <= maxLevel);
if (!objFiles.empty()) {
for (size_t i = 0; i < objFiles.size(); ++i) {
char const * objFile = objFiles[i].c_str();
std::ifstream ifs(objFile);
if (ifs) {
std::stringstream ss;
ss << ifs.rdbuf();
ifs.close();
g_shapes.push_back(ShapeDesc(objFile, ss.str(), defaultScheme));
} else {
fprintf(stderr,
"Warning: cannot open shape file '%s'\n", objFile);
}
} }
} }
@ -211,67 +369,38 @@ int main(int argc, char **argv)
initShapes(); initShapes();
} }
std::vector< std::vector<Result> > resultsByLevel(level+1); // For each shape, run tests for all specified levels -- printing the
// results in the specified format:
//
if (printOptions.csvFormat) {
PrintHeaderCSV(printOptions);
}
for (size_t i = 0; i < g_shapes.size(); ++i) {
ShapeDesc const & shapeDesc = g_shapes[i];
Shape const * shape = Shape::parseObj(shapeDesc);
for (int i = 0; i < (int)g_shapes.size(); ++i) { if (!printOptions.csvFormat) {
std::string const & name = g_shapes[i].name; PrintShape(shapeDesc, printOptions);
Shape const * shape = Shape::parseObj(g_shapes[i]); }
for (int lv = 1; lv <= level; ++lv) { for (int levelIndex = minLevel; levelIndex <= maxLevel; ++levelIndex) {
Result result; testOptions.refineLevel = levelIndex;
TestResult result;
if (runDouble) { if (runDouble) {
result = doPerf<double>(name, shape, lv, adaptive, endCapType); result = RunPerfTest<double>(*shape, testOptions);
} else { } else {
result = doPerf<float>(name, shape, lv, adaptive, endCapType); result = RunPerfTest<float>(*shape, testOptions);
} }
printf("---- %s, level %d ----\n", result.name.c_str(), lv); result.name = shapeDesc.name;
printf("TopologyRefiner::Refine %f %5.2f%%\n",
result.timeRefine, if (printOptions.csvFormat) {
result.timeRefine/result.timeTotal*100); PrintResultCSV(result, printOptions);
printf("StencilTableFactory::Create %f %5.2f%%\n", } else {
result.timeStencilFactory, PrintResult(result, printOptions);
result.timeStencilFactory/result.timeTotal*100);
printf("PatchTableFactory::Create %f %5.2f%%\n",
result.timePatchFactory,
result.timePatchFactory/result.timeTotal*100);
printf("StencilTableFactory::Append %f %5.2f%%\n",
result.timeAppendStencil,
result.timeAppendStencil/result.timeTotal*100);
printf("Total %f\n",
result.timeTotal);
if (spreadsheet) {
resultsByLevel[lv].push_back(result);
} }
} }
} delete shape;
if (spreadsheet) {
for (int lv=1; lv<(int)resultsByLevel.size(); ++lv) {
std::vector<Result> const & results = resultsByLevel[lv];
if (lv == 1) {
// spreadsheet header row
printf("level,");
for (int s=0; s<(int)results.size(); ++s) {
Result const & result = results[s];
printf("%s total,", result.name.c_str());
printf("%s refine,", result.name.c_str());
printf("%s patchFactory,", result.name.c_str());
printf("%s stencilFactory,", result.name.c_str());
printf("%s stencilAppend,", result.name.c_str());
}
printf("\n");
}
// spreadsheet data row
printf("%d,", lv);
for (int s=0; s<(int)results.size(); ++s) {
Result const & result = results[s];
printf("%f,", result.timeTotal);
printf("%f,", result.timeRefine);
printf("%f,", result.timePatchFactory);
printf("%f,", result.timeStencilFactory);
printf("%f,", result.timeAppendStencil);
}
printf("\n");
}
} }
} }

View File

@ -136,6 +136,7 @@
#include "loop_pole360.h" #include "loop_pole360.h"
#include "loop_saddle_edgecorner.h" #include "loop_saddle_edgecorner.h"
#include "loop_saddle_edgeonly.h" #include "loop_saddle_edgeonly.h"
#include "loop_tetrahedron.h"
#include "loop_toroidal_tet.h" #include "loop_toroidal_tet.h"
#include "loop_triangle_edgecorner.h" #include "loop_triangle_edgecorner.h"
#include "loop_triangle_edgeonly.h" #include "loop_triangle_edgeonly.h"

View File

@ -47,8 +47,8 @@ static const std::string catmark_xord_boundary =
"vt 0.076795 0.750000\n" "vt 0.076795 0.750000\n"
"\n" "\n"
"f 1/1 2/2 3/3 4/4\n" "f 1/1 2/2 3/3 4/4\n"
"f 1/1 4/4 5/5 6/6 \n" "f 6/6 1/1 4/4 5/5\n"
"f 1/1 6/6 7/7 8/8 \n" "f 6/6 7/7 8/8 1/1\n"
"\n" "\n"
"#\n" "#\n"
"# Shape 2: top-right\n" "# Shape 2: top-right\n"
@ -76,9 +76,9 @@ static const std::string catmark_xord_boundary =
"vt 0.565224 0.750000\n" "vt 0.565224 0.750000\n"
"\n" "\n"
"f 9/9 10/10 11/11 12/12\n" "f 9/9 10/10 11/11 12/12\n"
"f 9/9 12/12 13/13 14/14\n" "f 14/14 9/9 12/12 13/13\n"
"f 9/9 14/14 15/15 16/16\n" "f 15/15 16/16 9/9 14/14\n"
"f 9/9 16/16 17/17 18/18\n" "f 16/16 17/17 18/18 9/9\n"
"\n" "\n"
"#\n" "#\n"
"# Shape 3: bottom-left\n" "# Shape 3: bottom-left\n"
@ -110,9 +110,9 @@ static const std::string catmark_xord_boundary =
"vt 0.059789 0.250000\n" "vt 0.059789 0.250000\n"
"\n" "\n"
"f 19/19 20/20 21/21 22/22\n" "f 19/19 20/20 21/21 22/22\n"
"f 19/19 22/22 23/23 24/24\n" "f 24/24 19/19 22/22 23/23\n"
"f 19/19 24/24 25/25 26/26\n" "f 25/25 26/26 19/19 24/24\n"
"f 19/19 26/26 27/27 28/28\n" "f 26/26 27/27 28/28 19/19\n"
"f 19/19 28/28 29/29 30/30\n" "f 19/19 28/28 29/29 30/30\n"
"\n" "\n"
"#\n" "#\n"
@ -149,9 +149,9 @@ static const std::string catmark_xord_boundary =
"vt 0.556815 0.250000\n" "vt 0.556815 0.250000\n"
"\n" "\n"
"f 31/31 32/32 33/33 34/34\n" "f 31/31 32/32 33/33 34/34\n"
"f 31/31 34/34 35/35 36/36\n" "f 36/36 31/31 34/34 35/35\n"
"f 31/31 36/36 37/37 38/38\n" "f 37/37 38/38 31/31 36/36\n"
"f 31/31 38/38 39/39 40/40\n" "f 38/38 39/39 40/40 31/31\n"
"f 31/31 40/40 41/41 42/42\n" "f 31/31 40/40 41/41 42/42\n"
"f 31/31 42/42 43/43 44/44\n" "f 31/31 42/42 43/43 44/44\n"
"\n" "\n"

View File

@ -45,8 +45,8 @@ static const std::string catmark_xord_interior =
"vt 0.245000 0.700096\n" "vt 0.245000 0.700096\n"
"\n" "\n"
"f 1/1 2/2 3/3 4/4\n" "f 1/1 2/2 3/3 4/4\n"
"f 1/1 4/4 5/5 6/6 \n" "f 6/6 1/1 4/4 5/5\n"
"f 1/1 6/6 7/7 2/2 \n" "f 6/6 7/7 2/2 1/1\n"
"\n" "\n"
"#\n" "#\n"
"# Shape 2: top-middle\n" "# Shape 2: top-middle\n"
@ -76,9 +76,9 @@ static const std::string catmark_xord_interior =
"vt 0.621353 0.741832\n" "vt 0.621353 0.741832\n"
"\n" "\n"
"f 8/8 9/9 10/10 11/11\n" "f 8/8 9/9 10/10 11/11\n"
"f 8/8 11/11 12/12 13/13\n" "f 13/13 8/8 11/11 12/12\n"
"f 8/8 13/13 14/14 15/15\n" "f 14/14 15/15 8/8 13/13\n"
"f 8/8 15/15 16/16 17/17\n" "f 15/15 16/16 17/17 8/8\n"
"f 8/8 17/17 18/18 9/9\n" "f 8/8 17/17 18/18 9/9\n"
"\n" "\n"
"#\n" "#\n"
@ -113,9 +113,9 @@ static const std::string catmark_xord_interior =
"vt 0.959904 0.755000\n" "vt 0.959904 0.755000\n"
"\n" "\n"
"f 19/19 20/20 21/21 22/22\n" "f 19/19 20/20 21/21 22/22\n"
"f 19/19 22/22 23/23 24/24\n" "f 24/24 19/19 22/22 23/23\n"
"f 19/19 24/24 25/25 26/26\n" "f 25/25 26/26 19/19 24/24\n"
"f 19/19 26/26 27/27 28/28\n" "f 26/26 27/27 28/28 19/19\n"
"f 19/19 28/28 29/29 30/30\n" "f 19/19 28/28 29/29 30/30\n"
"f 19/19 30/30 31/31 20/20\n" "f 19/19 30/30 31/31 20/20\n"
"\n" "\n"
@ -155,9 +155,9 @@ static const std::string catmark_xord_interior =
"vt 0.305145 0.434918\n" "vt 0.305145 0.434918\n"
"\n" "\n"
"f 32/32 33/33 34/34 35/35\n" "f 32/32 33/33 34/34 35/35\n"
"f 32/32 35/35 36/36 37/37\n" "f 37/37 32/32 35/35 36/36\n"
"f 32/32 37/37 38/38 39/39\n" "f 38/38 39/39 32/32 37/37\n"
"f 32/32 39/39 40/40 41/41\n" "f 39/39 40/40 41/41 32/32\n"
"f 32/32 41/41 42/42 43/43\n" "f 32/32 41/41 42/42 43/43\n"
"f 32/32 43/43 44/44 45/45\n" "f 32/32 43/43 44/44 45/45\n"
"f 32/32 45/45 46/46 33/33\n" "f 32/32 45/45 46/46 33/33\n"
@ -202,9 +202,9 @@ static const std::string catmark_xord_interior =
"vt 0.638582 0.442598\n" "vt 0.638582 0.442598\n"
"\n" "\n"
"f 47/47 48/48 49/49 50/50\n" "f 47/47 48/48 49/49 50/50\n"
"f 47/47 50/50 51/51 52/52\n" "f 52/52 47/47 50/50 51/51\n"
"f 47/47 52/52 53/53 54/54\n" "f 53/53 54/54 47/47 52/52\n"
"f 47/47 54/54 55/55 56/56\n" "f 54/54 55/55 56/56 47/47\n"
"f 47/47 56/56 57/57 58/58\n" "f 47/47 56/56 57/57 58/58\n"
"f 47/47 58/58 59/59 60/60\n" "f 47/47 58/58 59/59 60/60\n"
"f 47/47 60/60 61/61 62/62\n" "f 47/47 60/60 61/61 62/62\n"
@ -254,9 +254,9 @@ static const std::string catmark_xord_interior =
"vt 0.970954 0.448697\n" "vt 0.970954 0.448697\n"
"\n" "\n"
"f 64/64 65/65 66/66 67/67\n" "f 64/64 65/65 66/66 67/67\n"
"f 64/64 67/67 68/68 69/69\n" "f 69/69 64/64 67/67 68/68\n"
"f 64/64 69/69 70/70 71/71\n" "f 70/70 71/71 64/64 69/69\n"
"f 64/64 71/71 72/72 73/73\n" "f 71/71 72/72 73/73 64/64\n"
"f 64/64 73/73 74/74 75/75\n" "f 64/64 73/73 74/74 75/75\n"
"f 64/64 75/75 76/76 77/77\n" "f 64/64 75/75 76/76 77/77\n"
"f 64/64 77/77 78/78 79/79\n" "f 64/64 77/77 78/78 79/79\n"
@ -311,9 +311,9 @@ static const std::string catmark_xord_interior =
"vt 0.312659 0.123648\n" "vt 0.312659 0.123648\n"
"\n" "\n"
"f 83/83 84/84 85/85 86/86\n" "f 83/83 84/84 85/85 86/86\n"
"f 83/83 86/86 87/87 88/88 \n" "f 88/88 83/83 86/86 87/87\n"
"f 83/83 88/88 89/89 90/90 \n" "f 89/89 90/90 83/83 88/88\n"
"f 83/83 90/90 91/91 92/92 \n" "f 90/90 91/91 92/92 83/83\n"
"f 83/83 92/92 93/93 94/94\n" "f 83/83 92/92 93/93 94/94\n"
"f 83/83 94/94 95/95 96/96\n" "f 83/83 94/94 95/95 96/96\n"
"f 83/83 96/96 97/97 98/98\n" "f 83/83 96/96 97/97 98/98\n"
@ -373,9 +373,9 @@ static const std::string catmark_xord_interior =
"vt 0.643924 0.127740\n" "vt 0.643924 0.127740\n"
"\n" "\n"
"f 104/104 105/105 106/106 107/107\n" "f 104/104 105/105 106/106 107/107\n"
"f 104/104 107/107 108/108 109/109\n" "f 109/109 104/104 107/107 108/108\n"
"f 104/104 109/109 110/110 111/111\n" "f 110/110 111/111 104/104 109/109\n"
"f 104/104 111/111 112/112 113/113\n" "f 111/111 112/112 113/113 104/104\n"
"f 104/104 113/113 114/114 115/115\n" "f 104/104 113/113 114/114 115/115\n"
"f 104/104 115/115 116/116 117/117\n" "f 104/104 115/115 116/116 117/117\n"
"f 104/104 117/117 118/118 119/119\n" "f 104/104 117/117 118/118 119/119\n"
@ -440,9 +440,9 @@ static const std::string catmark_xord_interior =
"vt 0.974889 0.131177\n" "vt 0.974889 0.131177\n"
"\n" "\n"
"f 127/127 128/128 129/129 130/130\n" "f 127/127 128/128 129/129 130/130\n"
"f 127/127 130/130 131/131 132/132\n" "f 132/132 127/127 130/130 131/131\n"
"f 127/127 132/132 133/133 134/134\n" "f 133/133 134/134 127/127 132/132\n"
"f 127/127 134/134 135/135 136/136\n" "f 134/134 135/135 136/136 127/127\n"
"f 127/127 136/136 137/137 138/138\n" "f 127/127 136/136 137/137 138/138\n"
"f 127/127 138/138 139/139 140/140\n" "f 127/127 138/138 139/139 140/140\n"
"f 127/127 140/140 141/141 142/142\n" "f 127/127 140/140 141/141 142/142\n"

View File

@ -0,0 +1,47 @@
//
// Copyright 2019 DreamWorks Animation LLC.
//
// Licensed under the Apache License, Version 2.0 (the "Apache License")
// with the following modification; you may not use this file except in
// compliance with the Apache License and the following modification to it:
// Section 6. Trademarks. is deleted and replaced with:
//
// 6. Trademarks. This License does not grant permission to use the trade
// names, trademarks, service marks, or product names of the Licensor
// and its affiliates, except as required to comply with Section 4(c) of
// the License and to reproduce the content of the NOTICE file.
//
// You may obtain a copy of the Apache License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the Apache License with the above modification is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the Apache License for the specific
// language governing permissions and limitations under the Apache License.
//
static const std::string loop_tetrahedron =
"#\n"
"# Tetrahedron oriented within an axially aligned cube:\n"
"#\n"
"v -1 -1 1\n"
"v 1 -1 -1\n"
"v 1 1 1\n"
"v -1 1 -1\n"
"\n"
"vt 0.375 0.217\n"
"vt 0.75 0.0\n"
"vt 0.375 0.65\n"
"vt 0.0 0.0\n"
"vt 0.25 1.0\n"
"vt 0.625 0.35\n"
"vt 1.0 1.0\n"
"\n"
"f 1/1 2/2 3/3\n"
"f 1/1 3/3 4/4\n"
"f 1/1 4/4 2/2\n"
"f 4/5 3/6 2/7\n"
"\n"
;

View File

@ -24,7 +24,7 @@
static const std::string loop_xord_boundary = static const std::string loop_xord_boundary =
"#\n" "#\n"
"# Nine shapes ordered left->right and top->bottom in the XZ and UV planes\n" "# Four shapes ordered left->right and top->bottom in the XZ and UV planes\n"
"#\n" "#\n"
"# Shape 1: top-left\n" "# Shape 1: top-left\n"
"#\n" "#\n"
@ -43,8 +43,8 @@ static const std::string loop_xord_boundary =
"vt 0.050000 0.750000\n" "vt 0.050000 0.750000\n"
"\n" "\n"
"f 1/1 2/2 3/3\n" "f 1/1 2/2 3/3\n"
"f 1/1 3/3 4/4 \n" "f 4/4 1/1 3/3\n"
"f 1/1 4/4 5/5 \n" "f 4/4 5/5 1/1\n"
"f 1/1 5/5 6/6\n" "f 1/1 5/5 6/6\n"
"\n" "\n"
"#\n" "#\n"
@ -67,8 +67,8 @@ static const std::string loop_xord_boundary =
"vt 0.550000 0.750000\n" "vt 0.550000 0.750000\n"
"\n" "\n"
"f 7/7 8/8 9/9\n" "f 7/7 8/8 9/9\n"
"f 7/7 9/9 10/10\n" "f 10/10 7/7 9/9\n"
"f 7/7 10/10 11/11\n" "f 10/10 11/11 7/7\n"
"f 7/7 11/11 12/12\n" "f 7/7 11/11 12/12\n"
"f 7/7 12/12 13/13\n" "f 7/7 12/12 13/13\n"
"\n" "\n"
@ -94,8 +94,8 @@ static const std::string loop_xord_boundary =
"vt 0.050000 0.250000\n" "vt 0.050000 0.250000\n"
"\n" "\n"
"f 14/14 15/15 16/16\n" "f 14/14 15/15 16/16\n"
"f 14/14 16/16 17/17\n" "f 17/17 14/14 16/16\n"
"f 14/14 17/17 18/18\n" "f 17/17 18/18 14/14\n"
"f 14/14 18/18 19/19\n" "f 14/14 18/18 19/19\n"
"f 14/14 19/19 20/20\n" "f 14/14 19/19 20/20\n"
"f 14/14 20/20 21/21\n" "f 14/14 20/20 21/21\n"
@ -126,8 +126,8 @@ static const std::string loop_xord_boundary =
"vt 0.550000 0.250000\n" "vt 0.550000 0.250000\n"
"\n" "\n"
"f 22/22 23/23 24/24\n" "f 22/22 23/23 24/24\n"
"f 22/22 24/24 25/25\n" "f 25/25 22/22 24/24\n"
"f 22/22 25/25 26/26\n" "f 25/25 26/26 22/22\n"
"f 22/22 26/26 27/27\n" "f 22/22 26/26 27/27\n"
"f 22/22 27/27 28/28\n" "f 22/22 27/27 28/28\n"
"f 22/22 28/28 29/29\n" "f 22/22 28/28 29/29\n"

View File

@ -39,8 +39,8 @@ static const std::string loop_xord_interior =
"vt 0.116 0.703\n" "vt 0.116 0.703\n"
"\n" "\n"
"f 1/1 2/2 3/3\n" "f 1/1 2/2 3/3\n"
"f 1/1 3/3 4/4 \n" "f 4/4 1/1 3/3\n"
"f 1/1 4/4 2/2 \n" "f 4/4 2/2 1/1\n"
"\n" "\n"
"#\n" "#\n"
"# Shape 2: top-middle, valence-4 ring\n" "# Shape 2: top-middle, valence-4 ring\n"
@ -58,8 +58,8 @@ static const std::string loop_xord_interior =
"vt 0.500 0.685\n" "vt 0.500 0.685\n"
"\n" "\n"
"f 5/5 6/6 7/7\n" "f 5/5 6/6 7/7\n"
"f 5/5 7/7 8/8 \n" "f 8/8 5/5 7/7\n"
"f 5/5 8/8 9/9 \n" "f 8/8 9/9 5/5\n"
"f 5/5 9/9 6/6\n" "f 5/5 9/9 6/6\n"
"\n" "\n"
"#\n" "#\n"
@ -80,8 +80,8 @@ static const std::string loop_xord_interior =
"vt 0.859 0.692\n" "vt 0.859 0.692\n"
"\n" "\n"
"f 10/10 11/11 12/12\n" "f 10/10 11/11 12/12\n"
"f 10/10 12/12 13/13 \n" "f 13/13 10/10 12/12\n"
"f 10/10 13/13 14/14 \n" "f 13/13 14/14 10/10\n"
"f 10/10 14/14 15/15\n" "f 10/10 14/14 15/15\n"
"f 10/10 15/15 11/11\n" "f 10/10 15/15 11/11\n"
"\n" "\n"
@ -107,8 +107,8 @@ static const std::string loop_xord_interior =
"vt 0.265 0.397\n" "vt 0.265 0.397\n"
"\n" "\n"
"f 16/16 17/17 18/18\n" "f 16/16 17/17 18/18\n"
"f 16/16 18/18 19/19 \n" "f 19/19 16/16 18/18\n"
"f 16/16 19/19 20/20 \n" "f 19/19 20/20 16/16\n"
"f 16/16 20/20 21/21\n" "f 16/16 20/20 21/21\n"
"f 16/16 21/21 22/22\n" "f 16/16 21/21 22/22\n"
"f 16/16 22/22 23/23\n" "f 16/16 22/22 23/23\n"
@ -138,8 +138,8 @@ static const std::string loop_xord_interior =
"vt 0.594 0.406\n" "vt 0.594 0.406\n"
"\n" "\n"
"f 24/24 25/25 26/26\n" "f 24/24 25/25 26/26\n"
"f 24/24 26/26 27/27 \n" "f 27/27 24/24 26/26\n"
"f 24/24 27/27 28/28 \n" "f 27/27 28/28 24/24\n"
"f 24/24 28/28 29/29\n" "f 24/24 28/28 29/29\n"
"f 24/24 29/29 30/30\n" "f 24/24 29/29 30/30\n"
"f 24/24 30/30 31/31\n" "f 24/24 30/30 31/31\n"
@ -172,8 +172,8 @@ static const std::string loop_xord_interior =
"vt 0.919 0.415\n" "vt 0.919 0.415\n"
"\n" "\n"
"f 33/33 34/34 35/35\n" "f 33/33 34/34 35/35\n"
"f 33/33 35/35 36/36 \n" "f 36/36 33/33 35/35\n"
"f 33/33 36/36 37/37 \n" "f 36/36 37/37 33/33\n"
"f 33/33 37/37 38/38\n" "f 33/33 37/37 38/38\n"
"f 33/33 38/38 39/39\n" "f 33/33 38/38 39/39\n"
"f 33/33 39/39 40/40\n" "f 33/33 39/39 40/40\n"
@ -209,8 +209,8 @@ static const std::string loop_xord_interior =
"vt 0.289 0.105\n" "vt 0.289 0.105\n"
"\n" "\n"
"f 43/43 44/44 45/45\n" "f 43/43 44/44 45/45\n"
"f 43/43 45/45 46/46 \n" "f 46/46 43/43 45/45\n"
"f 43/43 46/46 47/47 \n" "f 46/46 47/47 43/43\n"
"f 43/43 47/47 48/48\n" "f 43/43 47/47 48/48\n"
"f 43/43 48/48 49/49\n" "f 43/43 48/48 49/49\n"
"f 43/43 49/49 50/50\n" "f 43/43 49/49 50/50\n"
@ -249,8 +249,8 @@ static const std::string loop_xord_interior =
"vt 0.611 0.111\n" "vt 0.611 0.111\n"
"\n" "\n"
"f 54/54 55/55 56/56\n" "f 54/54 55/55 56/56\n"
"f 54/54 56/56 57/57 \n" "f 57/57 54/54 56/56\n"
"f 54/54 57/57 58/58 \n" "f 57/57 58/58 54/54\n"
"f 54/54 58/58 59/59\n" "f 54/54 58/58 59/59\n"
"f 54/54 59/59 60/60\n" "f 54/54 59/59 60/60\n"
"f 54/54 60/60 61/61\n" "f 54/54 60/60 61/61\n"
@ -292,8 +292,8 @@ static const std::string loop_xord_interior =
"vt 0.932 0.116\n" "vt 0.932 0.116\n"
"\n" "\n"
"f 66/66 67/67 68/68\n" "f 66/66 67/67 68/68\n"
"f 66/66 68/68 69/69 \n" "f 69/69 66/66 68/68\n"
"f 66/66 69/69 70/70 \n" "f 69/69 70/70 66/66\n"
"f 66/66 70/70 71/71\n" "f 66/66 70/70 71/71\n"
"f 66/66 71/71 72/72\n" "f 66/66 71/71 72/72\n"
"f 66/66 72/72 73/73\n" "f 66/66 72/72 73/73\n"