From 85befb639eb736bc8ec7d4a2e9726ec2ab1d0434 Mon Sep 17 00:00:00 2001 From: Ayoub Belarbi Date: Sun, 10 Dec 2023 01:04:03 +0000 Subject: [PATCH] PhysX SDK 5.3.1 (e9cf8e18b) --- physx/CHANGELOG.md | 85 +++- .../packman/bootstrap/configure.bat | 41 +- .../bootstrap/download_file_from_url.ps1 | 19 +- .../fetch_file_from_packman_bootstrap.cmd | 3 +- .../packman/bootstrap/install_package.py | 143 +++++- physx/buildtools/packman/packman | 96 ++-- physx/buildtools/packman/packman.cmd | 55 ++- physx/buildtools/packman/python.bat | 17 +- physx/buildtools/packman/python.sh | 14 +- physx/dependencies.xml | 8 +- physx/include/PxParticleSystem.h | 7 +- physx/include/PxSceneDesc.h | 2 +- .../characterkinematic/PxControllerManager.h | 6 +- .../cudamanager/PxCudaContextManager.h | 12 +- .../include/extensions/PxCustomGeometryExt.h | 6 +- physx/include/extensions/PxGearJoint.h | 2 +- .../include/extensions/PxRackAndPinionJoint.h | 4 +- physx/include/extensions/PxRemeshingExt.h | 18 + physx/include/extensions/PxSerialization.h | 2 +- .../extensions/PxTriangleMeshAnalysisResult.h | 5 +- physx/include/foundation/PxPhysicsVersion.h | 2 +- physx/include/foundation/PxPinnedArray.h | 1 + physx/include/foundation/PxPreprocessor.h | 13 +- physx/include/geomutils/PxContactPoint.h | 4 +- physx/include/omnipvd/PxOmniPvd.h | 59 ++- physx/include/solver/PxSolverDefs.h | 6 +- physx/snippets/snippetsdf/SnippetSDF.cpp | 30 +- .../compiler/cmake/linux/CMakeLists.txt | 2 +- .../cmake/modules/NvidiaBuildOptions.cmake | 2 +- .../source/geomutils/src/GuGeometryQuery.cpp | 4 +- physx/source/geomutils/src/GuMeshFactory.cpp | 9 +- physx/source/geomutils/src/GuMetaData.cpp | 55 +-- physx/source/geomutils/src/GuSDF.cpp | 459 +++++++++++++++--- physx/source/geomutils/src/GuSDF.h | 30 +- .../geomutils/src/convex/GuConvexMesh.cpp | 21 +- .../cooking/GuCookingConvexMeshBuilder.cpp | 20 +- physx/source/geomutils/src/mesh/GuBV32.cpp | 4 +- .../geomutils/src/mesh/GuTriangleMesh.cpp | 68 ++- .../geomutils/src/mesh/GuTriangleMesh.h | 2 +- .../immediatemode/src/NpImmediateMode.cpp | 13 +- .../lowlevel/software/include/PxsIslandSim.h | 6 +- .../lowlevel/software/src/PxsIslandSim.cpp | 95 ++-- .../include/DyFeatherstoneArticulation.h | 15 +- .../include/DyParticleSystemCore.h | 1 + .../src/DyArticulationContactPrep.cpp | 2 +- .../src/DyArticulationCpuGpu.h | 4 + .../src/DyArticulationPImpl.h | 3 +- .../lowleveldynamics/src/DyConstraintPrep.h | 3 - .../src/DyConstraintSetup.cpp | 1 + .../lowleveldynamics/src/DyContactPrep4.cpp | 13 +- .../lowleveldynamics/src/DyContactPrep4PF.cpp | 65 ++- .../lowleveldynamics/src/DyDynamics.cpp | 22 +- .../src/DyFeatherstoneArticulation.cpp | 113 ++--- .../src/DyFeatherstoneForwardDynamic.cpp | 4 +- .../src/DySolverConstraintDesc.h | 6 +- .../src/DySolverConstraintsBlock.cpp | 3 + .../lowleveldynamics/src/DySolverControl.cpp | 144 +++--- .../lowleveldynamics/src/DySolverControl.h | 55 +-- .../src/DySolverControlPF.cpp | 109 +---- .../lowleveldynamics/src/DySolverControlPF.h | 23 +- .../lowleveldynamics/src/DySolverCore.h | 12 +- .../lowleveldynamics/src/DyTGSContactPrep.cpp | 1 + .../src/DyTGSContactPrepBlock.cpp | 9 +- .../lowleveldynamics/src/DyTGSDynamics.cpp | 12 +- physx/source/physx/src/NpArticulationLink.cpp | 6 + physx/source/physx/src/NpArticulationLink.h | 2 +- physx/source/physx/src/NpFactory.cpp | 6 +- physx/source/physx/src/NpParticleSystem.cpp | 33 ++ physx/source/physx/src/NpParticleSystem.h | 41 +- physx/source/physx/src/NpPhysics.cpp | 2 +- physx/source/physx/src/NpScene.cpp | 2 +- .../physx/src/PvdMetaDataPvdBinding.cpp | 13 +- physx/source/physx/src/omnipvd/NpOmniPvd.cpp | 32 +- physx/source/physx/src/omnipvd/NpOmniPvd.h | 10 + .../physx/src/omnipvd/NpOmniPvdSetData.h | 4 +- .../physx/src/omnipvd/OmniPvdPxSampler.cpp | 70 ++- .../physx/src/omnipvd/OmniPvdPxSampler.h | 9 +- .../src/CctCharacterControllerManager.cpp | 45 +- .../src/CctCharacterControllerManager.h | 2 + .../src/ExtCustomGeometryExt.cpp | 104 ++-- .../physxextensions/src/ExtExtensions.cpp | 2 +- .../physxextensions/src/ExtGearJoint.cpp | 55 ++- .../physxextensions/src/ExtParticleExt.cpp | 50 +- .../src/ExtRackAndPinionJoint.cpp | 53 +- .../physxextensions/src/ExtRemeshingExt.cpp | 236 +++++++++ .../physxextensions/src/ExtSimpleFactory.cpp | 12 +- .../physxextensions/src/ExtSoftBodyExt.cpp | 12 +- .../src/omnipvd/ExtOmniPvdSetData.h | 4 +- .../omnipvd/OmniPvdPxExtensionsSampler.cpp | 23 +- .../src/omnipvd/OmniPvdPxExtensionsSampler.h | 14 +- .../src/tet/ExtDelaunayBoundaryInserter.cpp | 9 + .../simulationcontroller/src/ScBodySim.cpp | 5 + .../simulationcontroller/src/ScFiltering.cpp | 20 + .../simulationcontroller/src/ScPipeline.cpp | 9 +- .../src/ScShapeInteraction.cpp | 75 +-- .../simulationcontroller/src/ScShapeSimBase.h | 1 + physx/version.txt | 2 +- 97 files changed, 2109 insertions(+), 924 deletions(-) diff --git a/physx/CHANGELOG.md b/physx/CHANGELOG.md index 62118932d..23fc42828 100644 --- a/physx/CHANGELOG.md +++ b/physx/CHANGELOG.md @@ -1,4 +1,87 @@ -# v5.3.0 +# v5.3.1-105.1 + +## General + +### Changed + +* PxgDynamicsMemoryConfig::tempBufferCapacity will now be interpreted as a user-provided initial size, and will resize automatically if more memory is needed. + +### Fixed + +* A bug that led to phantom collisions for convex-heightfield interactions on GPU has been fixed. +* A bug that caused velocity and impulse updates of the GPU articulation solver (PGS and TGS) not to be propagated to subsequent iterations, causing slower convergence and potentially unstable collision responses between rigids and articulations. +* Fixed binary serialization for GPU enabled triangle meshes and meshes with SDF support. +* Several bugs with GPU aggregates have been fixed that could have led to missed and phantom collisions. The issues were mostly related to additions/removals of aggregate contents. +* Gpu accelerated SDF cooking is now deterministic. +* SDF snippet shows how to optionally store cooked data into files. +* Small improvements to SDF collisions, especially when objects with wildly different size collide. +* Creating objects from a PxInputData containing invalid data could lead to a confusing (and incorrect) error message about a "double deletion". This has been fixed. +* Bugs in island management related to actors other than rigid bodies. +* A bug that could lead to a crash when calling the PxTetMaker::validateTriangleMesh function with a mesh referencing more vertices than passed into the function. That defect is now reported as eTRIANGLE_INDEX_OUT_OF_RANGE. +* A crash bug that appeared when releasing actors with externally-provided forces and torques has been fixed. [Issue #211](https://github.com/NVIDIA-Omniverse/PhysX/issues/211) +* A bug that caused a memory corruption in the GPU solver when using D6 joints with rigid bodies and articulations has been fixed. + +## Rigid Body + +### Added + +* The extraction of an isosurface from a SDF can now use multiple CPU cores. + +### Fixed + +* A crash happening when using contact report thresholds with point-friction (PxFrictionType::eONE_DIRECTIONAL / PxFrictionType::eTWO_DIRECTIONAL) has been fixed. +* A "fear of the wireframe" issue in Sphere vs TriangleMesh collision when simulating on GPU is fixed. + +## Articulations + +### Fixed + +* Articulation joint velocity limits are respected when articulation joint drives are configured to push past the limit. +* Spherical articulation joints could sometimes flip their position by 2 pi causing problems with joint limits. This has been fixed. + +## Joints + +### Fixed + +* The PxConstraintFlag::eENABLE_EXTENDED_LIMITS flag now works properly for D6 based revolute joints when the GPU pipeline with the TGS solver is active. + +## Character controller + +### Fixed + +* You can now only create one PxCreateControllerManager per PxScene. This avoids filtering-related issues when multiple controller managers are created for the same PxScene. + +## Particles + +### Added + +* PxParticleSystem::getParticleMaterials() to query materials that have been registered with phases. + +### Fixed + +* PxParticleSystem::getNbParticleMaterials() always returned 1, instead of the materials referenced by phases. +* Particle - Convex Shape collisions failing with spread out particles. +* Particle phase references to PxPBDMaterial were broken when releasing (an unreferenced) PxPBDMaterial. + +## Pvd + +### Added + +* A way to get a thread safe OmniPvd writer from the PxOmniPvd interface through using acquireExclusiveWriterAccess() and releaseExclusiveWriterAccess(). + +### Fixed + +* OmniPVD no longer breaks when running and recording multiple scenes in parallel. +* Corrected mirroring of the inbountJoinDOF attribute of PxArticulationLink + +## Extensions + +### Fixed + +* A bug in custom cone/cylinder collision with triangle meshes. There was a gap between a cone/cylinder and a mesh, noticeable for centimeter-scale shapes. Note that the last position argument of e.g.: PxCustomGeometryExt::CylinderCallbacks::useSubstituteGeometry was removed from the API. + + +# v5.3.0-105.1 ## Supported Platforms diff --git a/physx/buildtools/packman/bootstrap/configure.bat b/physx/buildtools/packman/bootstrap/configure.bat index 8c502b3f7..8f8aa66d6 100644 --- a/physx/buildtools/packman/bootstrap/configure.bat +++ b/physx/buildtools/packman/bootstrap/configure.bat @@ -1,4 +1,4 @@ -:: Copyright 2019 NVIDIA CORPORATION +:: Copyright 2019-2023 NVIDIA CORPORATION :: :: Licensed under the Apache License, Version 2.0 (the "License"); :: you may not use this file except in compliance with the License. @@ -12,7 +12,7 @@ :: See the License for the specific language governing permissions and :: limitations under the License. -set PM_PACKMAN_VERSION=6.33.2 +set PM_PACKMAN_VERSION=7.15.1 :: Specify where packman command is rooted set PM_INSTALL_PATH=%~dp0.. @@ -48,7 +48,7 @@ echo. :: that may be needed in the path :ENSURE_DIR if not exist "%PM_PACKAGES_ROOT%" ( - echo Creating directory %PM_PACKAGES_ROOT% + echo Creating packman packages cache at %PM_PACKAGES_ROOT% mkdir "%PM_PACKAGES_ROOT%" ) if %errorlevel% neq 0 ( goto ERROR_MKDIR_PACKAGES_ROOT ) @@ -59,7 +59,7 @@ if defined PM_PYTHON_EXT ( goto PACKMAN ) -set PM_PYTHON_VERSION=3.7.9-windows-x86_64 +set PM_PYTHON_VERSION=3.10.5-1-windows-x86_64 set PM_PYTHON_BASE_DIR=%PM_PACKAGES_ROOT%\python set PM_PYTHON_DIR=%PM_PYTHON_BASE_DIR%\%PM_PYTHON_VERSION% set PM_PYTHON=%PM_PYTHON_DIR%\python.exe @@ -95,11 +95,16 @@ if exist "%PM_PYTHON%" ( if exist "%PM_PYTHON_DIR%" ( rd /s /q "%PM_PYTHON_DIR%" > nul ) ) -:: Perform atomic rename -rename "%TEMP_FOLDER_NAME%" "%PM_PYTHON_VERSION%" 1> nul -:: Failure during move, need to clean up and abort +:: Perform atomic move (allowing overwrite, /y) +move /y "%TEMP_FOLDER_NAME%" "%PM_PYTHON_DIR%" 1> nul +:: Verify that python.exe is now where we expect +if exist "%PM_PYTHON%" goto PACKMAN + +:: Wait a second and try again (can help with access denied weirdness) +timeout /t 1 /nobreak 1> nul +move /y "%TEMP_FOLDER_NAME%" "%PM_PYTHON_DIR%" 1> nul if %errorlevel% neq 0 ( - echo !!! Error renaming python !!! + echo !!! Error moving python %TEMP_FOLDER_NAME% -> %PM_PYTHON_DIR% !!! call :CLEAN_UP_TEMP_FOLDER goto ERROR ) @@ -112,9 +117,12 @@ if defined PM_MODULE_DIR_EXT ( set PM_MODULE_DIR=%PM_PACKAGES_ROOT%\packman-common\%PM_PACKMAN_VERSION% ) -set PM_MODULE=%PM_MODULE_DIR%\packman.py +set PM_MODULE=%PM_MODULE_DIR%\run.py -if exist "%PM_MODULE%" goto ENSURE_7ZA +if exist "%PM_MODULE%" goto END + +:: Clean out broken PM_MODULE_DIR if it exists +if exist "%PM_MODULE_DIR%" ( rd /s /q "%PM_MODULE_DIR%" > nul ) set PM_MODULE_PACKAGE=packman-common@%PM_PACKMAN_VERSION%.zip for /f "delims=" %%a in ('powershell -ExecutionPolicy ByPass -NoLogo -NoProfile -File "%~dp0\generate_temp_file_name.ps1"') do set TEMP_FILE_NAME=%%a @@ -134,19 +142,6 @@ if %errorlevel% neq 0 ( del "%TARGET%" -:ENSURE_7ZA -set PM_7Za_VERSION=16.02.4 -set PM_7Za_PATH=%PM_PACKAGES_ROOT%\7za\%PM_7ZA_VERSION% -if exist "%PM_7Za_PATH%" goto END -set PM_7Za_PATH=%PM_PACKAGES_ROOT%\chk\7za\%PM_7ZA_VERSION% -if exist "%PM_7Za_PATH%" goto END - -"%PM_PYTHON%" -S -s -u -E "%PM_MODULE%" pull "%PM_MODULE_DIR%\deps.packman.xml" -if %errorlevel% neq 0 ( - echo !!! Error fetching packman dependencies !!! - goto ERROR -) - goto END :ERROR_MKDIR_PACKAGES_ROOT diff --git a/physx/buildtools/packman/bootstrap/download_file_from_url.ps1 b/physx/buildtools/packman/bootstrap/download_file_from_url.ps1 index 5a3e2ede8..df5574560 100644 --- a/physx/buildtools/packman/bootstrap/download_file_from_url.ps1 +++ b/physx/buildtools/packman/bootstrap/download_file_from_url.ps1 @@ -20,8 +20,8 @@ param( ) $filename = $output -$triesLeft = 3 - +$triesLeft = 4 +$delay = 2 do { $triesLeft -= 1 @@ -31,12 +31,23 @@ do Write-Host "Downloading from bootstrap.packman.nvidia.com ..." $wc = New-Object net.webclient $wc.Downloadfile($source, $fileName) - $triesLeft = 0 + exit 0 } catch { Write-Host "Error downloading $source!" Write-Host $_.Exception|format-list -force + if ($triesLeft) + { + Write-Host "Retrying in $delay seconds ..." + Start-Sleep -seconds $delay + } + $delay = $delay * $delay } } while ($triesLeft -gt 0) - +# We only get here if the retries have been exhausted, remove any left-overs: +if (Test-Path $fileName) +{ + Remove-Item $fileName +} +exit 1 \ No newline at end of file diff --git a/physx/buildtools/packman/bootstrap/fetch_file_from_packman_bootstrap.cmd b/physx/buildtools/packman/bootstrap/fetch_file_from_packman_bootstrap.cmd index 4339bdc34..bf3a88d50 100644 --- a/physx/buildtools/packman/bootstrap/fetch_file_from_packman_bootstrap.cmd +++ b/physx/buildtools/packman/bootstrap/fetch_file_from_packman_bootstrap.cmd @@ -22,9 +22,8 @@ @powershell -ExecutionPolicy ByPass -NoLogo -NoProfile -File "%~dp0download_file_from_url.ps1" ^ -source "http://bootstrap.packman.nvidia.com/%PACKAGE_NAME%" -output %TARGET_PATH% :: A bug in powershell prevents the errorlevel code from being set when using the -File execution option -:: We must therefore do our own failure analysis, basically make sure the file exists and is larger than 0 bytes: +:: We must therefore do our own failure analysis, basically make sure the file exists: @if not exist %TARGET_PATH% goto ERROR_DOWNLOAD_FAILED -@if %~z2==0 goto ERROR_DOWNLOAD_FAILED @endlocal @exit /b 0 diff --git a/physx/buildtools/packman/bootstrap/install_package.py b/physx/buildtools/packman/bootstrap/install_package.py index 5b56a705f..b8ae7f642 100644 --- a/physx/buildtools/packman/bootstrap/install_package.py +++ b/physx/buildtools/packman/bootstrap/install_package.py @@ -16,42 +16,139 @@ import zipfile import tempfile import sys -import shutil +import os +import stat +import time +from typing import Any, Callable + + +RENAME_RETRY_COUNT = 100 +RENAME_RETRY_DELAY = 0.1 -__author__ = "hfannar" logging.basicConfig(level=logging.WARNING, format="%(message)s") logger = logging.getLogger("install_package") -class TemporaryDirectory: - def __init__(self): - self.path = None +def remove_directory_item(path): + if os.path.islink(path) or os.path.isfile(path): + try: + os.remove(path) + except PermissionError: + # make sure we have access and try again: + os.chmod(path, stat.S_IRWXU) + os.remove(path) + else: + # try first to delete the dir because this will work for folder junctions, otherwise we would follow the junctions and cause destruction! + clean_out_folder = False + try: + # make sure we have access preemptively - this is necessary because recursing into a directory without permissions + # will only lead to heart ache + os.chmod(path, stat.S_IRWXU) + os.rmdir(path) + except OSError: + clean_out_folder = True + + if clean_out_folder: + # we should make sure the directory is empty + names = os.listdir(path) + for name in names: + fullname = os.path.join(path, name) + remove_directory_item(fullname) + # now try to again get rid of the folder - and not catch if it raises: + os.rmdir(path) + + +class StagingDirectory: + def __init__(self, staging_path): + self.staging_path = staging_path + self.temp_folder_path = None + os.makedirs(staging_path, exist_ok=True) def __enter__(self): - self.path = tempfile.mkdtemp() - return self.path + self.temp_folder_path = tempfile.mkdtemp(prefix="ver-", dir=self.staging_path) + return self + + def get_temp_folder_path(self): + return self.temp_folder_path + + # this function renames the temp staging folder to folder_name, it is required that the parent path exists! + def promote_and_rename(self, folder_name): + abs_dst_folder_name = os.path.join(self.staging_path, folder_name) + os.rename(self.temp_folder_path, abs_dst_folder_name) def __exit__(self, type, value, traceback): - # Remove temporary data created - shutil.rmtree(self.path) + # Remove temp staging folder if it's still there (something went wrong): + path = self.temp_folder_path + if os.path.isdir(path): + remove_directory_item(path) -def install_package(package_src_path, package_dst_path): - with zipfile.ZipFile( - package_src_path, allowZip64=True - ) as zip_file, TemporaryDirectory() as temp_dir: - zip_file.extractall(temp_dir) - # Recursively copy (temp_dir will be automatically cleaned up on exit) - try: - # Recursive copy is needed because both package name and version folder could be missing in - # target directory: - shutil.copytree(temp_dir, package_dst_path) - except OSError as exc: +def rename_folder(staging_dir: StagingDirectory, folder_name: str): + try: + staging_dir.promote_and_rename(folder_name) + except OSError as exc: + # if we failed to rename because the folder now exists we can assume that another packman process + # has managed to update the package before us - in all other cases we re-raise the exception + abs_dst_folder_name = os.path.join(staging_dir.staging_path, folder_name) + if os.path.exists(abs_dst_folder_name): logger.warning( - "Directory %s already present, packaged installation aborted" % package_dst_path + f"Directory {abs_dst_folder_name} already present, package installation already completed" ) else: - logger.info("Package successfully installed to %s" % package_dst_path) + raise + + +def call_with_retry( + op_name: str, func: Callable, retry_count: int = 3, retry_delay: float = 20 +) -> Any: + retries_left = retry_count + while True: + try: + return func() + except (OSError, IOError) as exc: + logger.warning(f"Failure while executing {op_name} [{str(exc)}]") + if retries_left: + retry_str = "retry" if retries_left == 1 else "retries" + logger.warning( + f"Retrying after {retry_delay} seconds" + f" ({retries_left} {retry_str} left) ..." + ) + time.sleep(retry_delay) + else: + logger.error("Maximum retries exceeded, giving up") + raise + retries_left -= 1 + + +def rename_folder_with_retry(staging_dir: StagingDirectory, folder_name): + dst_path = os.path.join(staging_dir.staging_path, folder_name) + call_with_retry( + f"rename {staging_dir.get_temp_folder_path()} -> {dst_path}", + lambda: rename_folder(staging_dir, folder_name), + RENAME_RETRY_COUNT, + RENAME_RETRY_DELAY, + ) + + +def install_package(package_path, install_path): + staging_path, version = os.path.split(install_path) + with StagingDirectory(staging_path) as staging_dir: + output_folder = staging_dir.get_temp_folder_path() + with zipfile.ZipFile(package_path, allowZip64=True) as zip_file: + zip_file.extractall(output_folder) + + # attempt the rename operation + rename_folder_with_retry(staging_dir, version) + + print(f"Package successfully installed to {install_path}") -install_package(sys.argv[1], sys.argv[2]) +if __name__ == "__main__": + executable_paths = os.getenv("PATH") + paths_list = executable_paths.split(os.path.pathsep) if executable_paths else [] + target_path_np = os.path.normpath(sys.argv[2]) + target_path_np_nc = os.path.normcase(target_path_np) + for exec_path in paths_list: + if os.path.normcase(os.path.normpath(exec_path)) == target_path_np_nc: + raise RuntimeError(f"packman will not install to executable path '{exec_path}'") + install_package(sys.argv[1], target_path_np) diff --git a/physx/buildtools/packman/packman b/physx/buildtools/packman/packman index f481b87fe..d93d80ebd 100755 --- a/physx/buildtools/packman/packman +++ b/physx/buildtools/packman/packman @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright 2019-2020 NVIDIA CORPORATION +# Copyright 2019-2023 NVIDIA CORPORATION # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -18,11 +18,13 @@ set -eu if echo ${PM_VERBOSITY-} | grep -i "debug" > /dev/null ; then set -x + PM_CURL_SILENT="" + PM_WGET_QUIET="" else PM_CURL_SILENT="-s -S" PM_WGET_QUIET="--quiet" fi -PM_PACKMAN_VERSION=6.33.2 +PM_PACKMAN_VERSION=7.15.1 # This is necessary for newer macOS if [ `uname` == 'Darwin' ]; then @@ -30,33 +32,32 @@ if [ `uname` == 'Darwin' ]; then export LANG=en_US.UTF-8 fi -# Specify where packman command exists -export PM_INSTALL_PATH="$(realpath "$(dirname "${BASH_SOURCE}")")" - -add_packages_root_to_file() -{ - FILE_PATH=$1 - if [ -f "$FILE_PATH" ]; then - if ! grep -Fq "PM_PACKAGES_ROOT" $FILE_PATH ; then - echo "Adjusting $FILE_PATH" - echo -e "export PM_PACKAGES_ROOT=\$HOME/packman-repo\n" >> $FILE_PATH - fi - fi +# We cannot rely on realpath, it isn't installed on macOS and some Linux distros +get_abs_filename() { + echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")" } +# Specify where packman command exists +export PM_INSTALL_PATH="$(get_abs_filename "$(dirname "${BASH_SOURCE}")")" + # The packages root may already be configured by the user if [ -z "${PM_PACKAGES_ROOT:-}" ]; then - # Set variable permanently using .profile for this user (if exists) - add_packages_root_to_file ~/.profile - add_packages_root_to_file ~/.bashrc # Set variable temporarily in this process so that the following execution will work - export PM_PACKAGES_ROOT="${HOME}/packman-repo" + if [ `uname` == 'Darwin' ]; then + export PM_PACKAGES_ROOT="${HOME}/Library/Application Support/packman-cache" + else + if [ -z "${XDG_CACHE_HOME:-}" ]; then + export PM_PACKAGES_ROOT="${HOME}/.cache/packman" + else + export PM_PACKAGES_ROOT="${XDG_CACHE_HOME}/packman" + fi + fi fi # Ensure the packages root path exists: if [ ! -d "$PM_PACKAGES_ROOT" ]; then - echo "Creating packman packages repository at $PM_PACKAGES_ROOT" - mkdir -p "$PM_PACKAGES_ROOT" + echo "Creating packman packages cache at $PM_PACKAGES_ROOT" + mkdir -p -m a+rwx "$PM_PACKAGES_ROOT" fi fetch_file_from_s3() @@ -72,18 +73,28 @@ fetch_file_from_s3() fi } +generate_temp_file_name() +{ + if [ `uname` == "Darwin" ]; then + local tmpfile=`mktemp -t packman` + else + local tmpfile=`mktemp -t packman.XXXXXXXX` + fi + echo "$tmpfile" +} + install_python() { PLATFORM=`uname` PROCESSOR=`uname -m` - PYTHON_VERSION=3.7.9 + PYTHON_VERSION=3.10.5-1 if [ $PLATFORM == 'Darwin' ]; then PYTHON_PACKAGE=$PYTHON_VERSION-macos-x86_64 elif [ $PLATFORM == 'Linux' ] && [ $PROCESSOR == 'x86_64' ]; then PYTHON_PACKAGE=$PYTHON_VERSION-linux-x86_64 elif [ $PLATFORM == 'Linux' ] && [ $PROCESSOR == 'aarch64' ]; then - PYTHON_PACKAGE=$PYTHON_VERSION-177-linux-aarch64 + PYTHON_PACKAGE=$PYTHON_VERSION-linux-aarch64 else echo "Operating system not supported" exit 1 @@ -97,10 +108,12 @@ install_python() export PM_PYTHON="$PYTHON_INSTALL_FOLDER/python" if [ ! -f "$PM_PYTHON" ]; then - fetch_file_from_s3 "python@$PYTHON_PACKAGE.tar.gz" "/tmp/python@$PYTHON_PACKAGE.tar.gz" + PYTHON_PACKAGE_TMP=$(generate_temp_file_name) + fetch_file_from_s3 "python@$PYTHON_PACKAGE.tar.gz" "$PYTHON_PACKAGE_TMP" if [ "$?" -eq "0" ]; then echo "Unpacking python" - tar -xf "/tmp/python@$PYTHON_PACKAGE.tar.gz" -C "$PYTHON_INSTALL_FOLDER" + tar -xf "$PYTHON_PACKAGE_TMP" -C "$PYTHON_INSTALL_FOLDER" + rm "$PYTHON_PACKAGE_TMP" else echo "Failed downloading the Python interpreter" exit $? @@ -121,38 +134,28 @@ if [ -z "${PM_MODULE_DIR_EXT:-}" ]; then else PM_MODULE_DIR="$PM_MODULE_DIR_EXT" fi -export PM_MODULE="$PM_MODULE_DIR/packman.py" +export PM_MODULE="$PM_MODULE_DIR/run.py" # Ensure the packman package exists: if [ ! -f "$PM_MODULE" ]; then + # Remove a previously corrupt packman-common if it's there + if [ -d "$PM_MODULE_DIR" ]; then + rm -rf "$PM_MODULE_DIR" + fi PM_MODULE_PACKAGE="packman-common@$PM_PACKMAN_VERSION.zip" - TARGET="/tmp/$PM_MODULE_PACKAGE" + TARGET=$(generate_temp_file_name) # We always fetch packman from S3: - fetch_file_from_s3 $PM_MODULE_PACKAGE $TARGET + fetch_file_from_s3 "$PM_MODULE_PACKAGE" "$TARGET" if [ "$?" -eq "0" ]; then echo "Unpacking ..." "$PM_PYTHON" -S -s -u -E "$PM_INSTALL_PATH/bootstrap/install_package.py" "$TARGET" "$PM_MODULE_DIR" - rm $TARGET + rm "$TARGET" else echo "Failure while fetching packman module from S3!" exit 1 fi fi -# Ensure 7za package exists: -PM_7za_VERSION=16.02.4 -export PM_7za_PATH="$PM_PACKAGES_ROOT/7za/$PM_7za_VERSION" -if [ ! -d "$PM_7za_PATH" ]; then - export PM_7za_PATH="$PM_PACKAGES_ROOT/chk/7za/$PM_7za_VERSION" - if [ ! -d "$PM_7za_PATH" ]; then - "$PM_PYTHON" -S -s -u -E "$PM_MODULE" pull "$PM_MODULE_DIR/deps.packman.xml" - if [ "$?" -ne 0 ]; then - echo "Failure while installing required 7za package" - exit 1 - fi - fi -fi - # Generate temporary file name for environment variables: PM_VAR_PATH=`mktemp -u -t tmp.$$.pmvars.XXXXXX` @@ -174,11 +177,6 @@ if [ -f "$PM_VAR_PATH" ]; then rm -f "$PM_VAR_PATH" fi -# Return the exit code from python -if [ "$exit_code" != 0 ]; then - exit "$exit_code" -fi - # avoid leaking -e and -u into the host script if they weren't originally set if [[ ! ( "$SAVED_SETTINGS" =~ e ) ]]; then set +e @@ -188,3 +186,7 @@ if [[ ! ( "$SAVED_SETTINGS" =~ u ) ]]; then set +u fi +# Return the exit code from python +if [ "$exit_code" != 0 ]; then + exit "$exit_code" +fi diff --git a/physx/buildtools/packman/packman.cmd b/physx/buildtools/packman/packman.cmd index c7bf3dcfa..e55b2f0e1 100644 --- a/physx/buildtools/packman/packman.cmd +++ b/physx/buildtools/packman/packman.cmd @@ -1,23 +1,22 @@ -:: Reset errorlevel status (don't inherit from caller) [xxxxxxxxxxx] +:: RUN_PM_MODULE must always be at the same spot for packman update to work (batch reloads file during update!) +:: [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx] +:: Reset errorlevel status (don't inherit from caller) @call :ECHO_AND_RESET_ERROR -:: You can remove the call below if you do your own manual configuration of the dev machines -call "%~dp0\bootstrap\configure.bat" +:: You can remove this section if you do your own manual configuration of the dev machines +call :CONFIGURE if %errorlevel% neq 0 ( exit /b %errorlevel% ) + :: Everything below is mandatory if not defined PM_PYTHON goto :PYTHON_ENV_ERROR if not defined PM_MODULE goto :MODULE_ENV_ERROR -:: Generate temporary path for variable file -for /f "delims=" %%a in ('powershell -ExecutionPolicy ByPass -NoLogo -NoProfile ^ --File "%~dp0bootstrap\generate_temp_file_name.ps1"') do set PM_VAR_PATH=%%a +set PM_VAR_PATH_ARG= -if %1.==. ( - set PM_VAR_PATH_ARG= -) else ( - set PM_VAR_PATH_ARG=--var-path="%PM_VAR_PATH%" -) +if "%1"=="pull" goto :SET_VAR_PATH +if "%1"=="install" goto :SET_VAR_PATH +:RUN_PM_MODULE "%PM_PYTHON%" -S -s -u -E "%PM_MODULE%" %* %PM_VAR_PATH_ARG% if %errorlevel% neq 0 ( exit /b %errorlevel% ) @@ -48,9 +47,43 @@ exit /b 1 @echo Error while processing and setting environment variables! exit /b 1 +:: pad [xxxx] :ECHO_AND_RESET_ERROR @echo off if /I "%PM_VERBOSITY%"=="debug" ( @echo on ) exit /b 0 + +:SET_VAR_PATH +:: Generate temporary path for variable file +for /f "delims=" %%a in ('%PM_PYTHON% -S -s -u -E -c "import tempfile;file = tempfile.NamedTemporaryFile(mode='w+t', delete=False);print(file.name)"') do (set PM_VAR_PATH=%%a) +set PM_VAR_PATH_ARG=--var-path="%PM_VAR_PATH%" +goto :RUN_PM_MODULE + +:CONFIGURE +:: Must capture and set code page to work around issue #279, powershell invocation mutates console font +:: This issue only happens in Windows CMD shell when using 65001 code page. Some Git Bash implementations +:: don't support chcp so this workaround is a bit convoluted. +:: Test for chcp: +chcp > nul 2>&1 +if %errorlevel% equ 0 ( + for /f "tokens=2 delims=:" %%a in ('chcp') do (set PM_OLD_CODE_PAGE=%%a) +) else ( + call :ECHO_AND_RESET_ERROR +) +:: trim leading space (this is safe even when PM_OLD_CODE_PAGE has not been set) +set PM_OLD_CODE_PAGE=%PM_OLD_CODE_PAGE:~1% +if "%PM_OLD_CODE_PAGE%" equ "65001" ( + chcp 437 > nul + set PM_RESTORE_CODE_PAGE=1 +) +call "%~dp0\bootstrap\configure.bat" +set PM_CONFIG_ERRORLEVEL=%errorlevel% +if defined PM_RESTORE_CODE_PAGE ( + :: Restore code page + chcp %PM_OLD_CODE_PAGE% > nul +) +set PM_OLD_CODE_PAGE= +set PM_RESTORE_CODE_PAGE= +exit /b %PM_CONFIG_ERRORLEVEL% diff --git a/physx/buildtools/packman/python.bat b/physx/buildtools/packman/python.bat index ef37691b2..08df74f8a 100644 --- a/physx/buildtools/packman/python.bat +++ b/physx/buildtools/packman/python.bat @@ -13,9 +13,20 @@ :: limitations under the License. @echo off -setlocal +setlocal enableextensions call "%~dp0\packman" init set "PYTHONPATH=%PM_MODULE_DIR%;%PYTHONPATH%" -set PYTHONNOUSERSITE=1 -"%PM_PYTHON%" -u %* + +if not defined PYTHONNOUSERSITE ( + set PYTHONNOUSERSITE=1 +) + +REM For performance, default to unbuffered; however, allow overriding via +REM PYTHONUNBUFFERED=0 since PYTHONUNBUFFERED on windows can truncate output +REM when printing long strings +if not defined PYTHONUNBUFFERED ( + set PYTHONUNBUFFERED=1 +) + +"%PM_PYTHON%" %* \ No newline at end of file diff --git a/physx/buildtools/packman/python.sh b/physx/buildtools/packman/python.sh index 37c9f1b89..74328bf0d 100755 --- a/physx/buildtools/packman/python.sh +++ b/physx/buildtools/packman/python.sh @@ -22,11 +22,21 @@ if [ ! -f "$PACKMAN_CMD" ]; then fi source "$PACKMAN_CMD" init export PYTHONPATH="${PM_MODULE_DIR}:${PYTHONPATH}" -export PYTHONNOUSERSITE=1 + +if [ -z "${PYTHONNOUSERSITE:-}" ]; then + export PYTHONNOUSERSITE=1 +fi + +# For performance, default to unbuffered; however, allow overriding via +# PYTHONUNBUFFERED=0 since PYTHONUNBUFFERED on windows can truncate output +# when printing long strings +if [ -z "${PYTHONUNBUFFERED:-}" ]; then + export PYTHONUNBUFFERED=1 +fi # workaround for our python not shipping with certs if [[ -z ${SSL_CERT_DIR:-} ]]; then export SSL_CERT_DIR=/etc/ssl/certs/ fi -"${PM_PYTHON}" -u "$@" +"${PM_PYTHON}" "$@" diff --git a/physx/dependencies.xml b/physx/dependencies.xml index 980da1b51..be975e73e 100644 --- a/physx/dependencies.xml +++ b/physx/dependencies.xml @@ -8,7 +8,7 @@ - + @@ -16,9 +16,9 @@ - - - + + + diff --git a/physx/include/PxParticleSystem.h b/physx/include/PxParticleSystem.h index b4b3b5edc..077a70368 100644 --- a/physx/include/PxParticleSystem.h +++ b/physx/include/PxParticleSystem.h @@ -428,11 +428,16 @@ class PxParticleSystem : public PxActor /** - \brief Returns number of particle materials + \brief Returns number of particle materials referenced by particle phases \return The number of particle materials */ virtual PxU32 getNbParticleMaterials() const = 0; + /** + \brief Returns particle materials referenced by particle phases + \return The particle materials + */ + virtual PxU32 getParticleMaterials(PxParticleMaterial** userBuffer, PxU32 bufferSize, PxU32 startIndex = 0) const = 0; /** \brief Sets a user notify object which receives special simulation events when they occur. diff --git a/physx/include/PxSceneDesc.h b/physx/include/PxSceneDesc.h index 15f1173b8..fad96f857 100644 --- a/physx/include/PxSceneDesc.h +++ b/physx/include/PxSceneDesc.h @@ -377,7 +377,7 @@ PX_INLINE bool PxSceneLimits::isValid() const struct PxgDynamicsMemoryConfig { - PxU32 tempBufferCapacity; //!< Capacity of temp buffer allocated in pinned host memory. + PxU32 tempBufferCapacity; //!< Initial capacity of temp solver buffer allocated in pinned host memory. This buffer will grow if more memory is needed than specified here. PxU32 maxRigidContactCount; //!< Size of contact stream buffer allocated in pinned host memory. This is double-buffered so total allocation size = 2* contactStreamCapacity * sizeof(PxContact). PxU32 maxRigidPatchCount; //!< Size of the contact patch stream buffer allocated in pinned host memory. This is double-buffered so total allocation size = 2 * patchStreamCapacity * sizeof(PxContactPatch). PxU32 heapCapacity; //!< Initial capacity of the GPU and pinned host memory heaps. Additional memory will be allocated if more memory is required. diff --git a/physx/include/characterkinematic/PxControllerManager.h b/physx/include/characterkinematic/PxControllerManager.h index 76c30e775..8177e4399 100644 --- a/physx/include/characterkinematic/PxControllerManager.h +++ b/physx/include/characterkinematic/PxControllerManager.h @@ -278,8 +278,10 @@ class PxControllerManager /** \brief Creates the controller manager. - \param[in] scene PhysX scene. - \param[in] lockingEnabled Enables/disables internal locking. + \param[in] scene PhysX scene. You can only create one PxControllerManager per scene. + \param[in] lockingEnabled Enables/disables internal locking. + + \return New controller manager, or NULL in case of failure (e.g. when a manager has already been created for that scene) The character controller is informed by #PxDeletionListener::onRelease() when actors or shapes are released, and updates its internal caches accordingly. If character controller movement or a call to #PxControllerManager::shiftOrigin() may overlap with actor/shape releases, diff --git a/physx/include/cudamanager/PxCudaContextManager.h b/physx/include/cudamanager/PxCudaContextManager.h index 3159d4ebc..d715262c1 100644 --- a/physx/include/cudamanager/PxCudaContextManager.h +++ b/physx/include/cudamanager/PxCudaContextManager.h @@ -260,7 +260,7 @@ class PxCudaContextManager template void allocDeviceBuffer(T*& deviceBuffer, PxU32 numElements, const char* filename = __FILE__, PxI32 line = __LINE__) { - void* ptr = allocDeviceBufferInternal(numElements * sizeof(T), filename, line); + void* ptr = allocDeviceBufferInternal(PxU64(numElements) * sizeof(T), filename, line); deviceBuffer = reinterpret_cast(ptr); } @@ -272,7 +272,7 @@ class PxCudaContextManager template T* allocDeviceBuffer(PxU32 numElements, const char* filename = __FILE__, PxI32 line = __LINE__) { - void* ptr = allocDeviceBufferInternal(numElements * sizeof(T), filename, line); + void* ptr = allocDeviceBufferInternal(PxU64(numElements) * sizeof(T), filename, line); return reinterpret_cast(ptr); } @@ -298,7 +298,7 @@ class PxCudaContextManager template void allocPinnedHostBuffer(T*& pinnedHostBuffer, PxU32 numElements, const char* filename = __FILE__, PxI32 line = __LINE__) { - void* ptr = allocPinnedHostBufferInternal(numElements * sizeof(T), filename, line); + void* ptr = allocPinnedHostBufferInternal(PxU64(numElements) * sizeof(T), filename, line); pinnedHostBuffer = reinterpret_cast(ptr); } @@ -312,7 +312,7 @@ class PxCudaContextManager template T* allocPinnedHostBuffer(PxU32 numElements, const char* filename = __FILE__, PxI32 line = __LINE__) { - void* ptr = allocPinnedHostBufferInternal(numElements * sizeof(T), filename, line); + void* ptr = allocPinnedHostBufferInternal(PxU64(numElements) * sizeof(T), filename, line); return reinterpret_cast(ptr); } @@ -439,8 +439,8 @@ class PxCudaContextManager */ virtual ~PxCudaContextManager() {} - virtual void* allocDeviceBufferInternal(PxU32 numBytes, const char* filename = NULL, PxI32 line = -1) = 0; - virtual void* allocPinnedHostBufferInternal(PxU32 numBytes, const char* filename = NULL, PxI32 line = -1) = 0; + virtual void* allocDeviceBufferInternal(PxU64 numBytes, const char* filename = NULL, PxI32 line = -1) = 0; + virtual void* allocPinnedHostBufferInternal(PxU64 numBytes, const char* filename = NULL, PxI32 line = -1) = 0; virtual void freeDeviceBufferInternal(void* deviceBuffer) = 0; virtual void freePinnedHostBufferInternal(void* pinnedHostBuffer) = 0; diff --git a/physx/include/extensions/PxCustomGeometryExt.h b/physx/include/extensions/PxCustomGeometryExt.h index dc0024080..3280fb80c 100644 --- a/physx/include/extensions/PxCustomGeometryExt.h +++ b/physx/include/extensions/PxCustomGeometryExt.h @@ -81,7 +81,7 @@ class PxCustomGeometryExt float margin; // Substitute geometry - virtual bool useSubstituteGeometry(PxGeometryHolder& geom, PxTransform& preTransform, const PxContactPoint& p, const PxTransform& pose0, const PxVec3& pos1) const = 0; + virtual bool useSubstituteGeometry(PxGeometryHolder& geom, PxTransform& preTransform, const PxContactPoint& p, const PxTransform& pose0) const = 0; }; /// \endcond @@ -140,7 +140,7 @@ class PxCustomGeometryExt int axis; // Substitute geometry - virtual bool useSubstituteGeometry(PxGeometryHolder& geom, PxTransform& preTransform, const PxContactPoint& p, const PxTransform& pose0, const PxVec3& pos1) const; + virtual bool useSubstituteGeometry(PxGeometryHolder& geom, PxTransform& preTransform, const PxContactPoint& p, const PxTransform& pose0) const; // Radius at height float getRadiusAtHeight(float height) const; @@ -202,7 +202,7 @@ class PxCustomGeometryExt int axis; // Substitute geometry - virtual bool useSubstituteGeometry(PxGeometryHolder& geom, PxTransform& preTransform, const PxContactPoint& p, const PxTransform& pose0, const PxVec3& pos1) const; + virtual bool useSubstituteGeometry(PxGeometryHolder& geom, PxTransform& preTransform, const PxContactPoint& p, const PxTransform& pose0) const; // Radius at height float getRadiusAtHeight(float height) const; diff --git a/physx/include/extensions/PxGearJoint.h b/physx/include/extensions/PxGearJoint.h index 9500f9985..cc6b55931 100644 --- a/physx/include/extensions/PxGearJoint.h +++ b/physx/include/extensions/PxGearJoint.h @@ -67,7 +67,7 @@ namespace physx \brief Set the hinge/revolute joints connected by the gear joint. The passed joints can be either PxRevoluteJoint, PxD6Joint or PxArticulationJointReducedCoordinate. - The joints must define degrees of freedom around the twist axis. They cannot be null. + The joints must define degrees of freedom around the twist axis. Note that these joints are only used to compute the positional error correction term, used to adjust potential drift between jointed actors. The gear joint can run without diff --git a/physx/include/extensions/PxRackAndPinionJoint.h b/physx/include/extensions/PxRackAndPinionJoint.h index 72558815c..ce5d4fc9b 100644 --- a/physx/include/extensions/PxRackAndPinionJoint.h +++ b/physx/include/extensions/PxRackAndPinionJoint.h @@ -67,8 +67,8 @@ namespace physx /** \brief Set the hinge & prismatic joints connected by the rack & pinion joint. - The passed hinge joint can be either PxRevoluteJoint, PxD6Joint or PxArticulationJointReducedCoordinate. It cannot be null. - The passed prismatic joint can be either PxPrismaticJoint or PxD6Joint. It cannot be null. + The passed hinge joint can be either PxRevoluteJoint, PxD6Joint or PxArticulationJointReducedCoordinate. + The passed prismatic joint can be either PxPrismaticJoint or PxD6Joint. Note that these joints are only used to compute the positional error correction term, used to adjust potential drift between jointed actors. The rack & pinion joint can run without diff --git a/physx/include/extensions/PxRemeshingExt.h b/physx/include/extensions/PxRemeshingExt.h index 556a859c7..aa9e2cb2f 100644 --- a/physx/include/extensions/PxRemeshingExt.h +++ b/physx/include/extensions/PxRemeshingExt.h @@ -63,6 +63,24 @@ namespace physx */ static bool limitMaxEdgeLength(PxArray& triangles, PxArray& points, PxReal maxEdgeLength, PxU32 maxIterations = 100, PxArray* triangleMap = NULL, PxU32 triangleCountThreshold = 0xFFFFFFFF); + + /** + \brief Processes a triangle mesh and makes sure that no triangle edge is longer than the maximal edge length specified + + To shorten edges that are too long, additional points get inserted at their center leading to a subdivision of the input mesh. + This process is executed repeatedly until the maximum edge length criterion is satisfied + + \param[in,out] triangles The triangles of the mesh where a maximum edge length should be enforced. They will be modified in place during the process. + \param[in,out] points The vertices of the mesh where a maximum edge length should be enforced. They will be modified in place during the process. + \param[in] maxEdgeLength The maximum edge length allowed after processing the input + \param[in] maxIterations The maximum number of subdivision iterations + \param[out] triangleMap An optional map that provides the index of the original triangle for every triangle after the subdivision + \param[in] triangleCountThreshold Optional limit to the number of triangles. Not guaranteed to match exactly, the algorithm will just stop as soon as possible after reaching the limit. + + \return True if any remeshing was applied + */ + static bool reduceSliverTriangles(PxArray& triangles, PxArray& points, PxReal maxEdgeLength, + PxU32 maxIterations = 3, PxArray* triangleMap = NULL, PxU32 triangleCountThreshold = 0xFFFFFFFF); }; #if !PX_DOXYGEN diff --git a/physx/include/extensions/PxSerialization.h b/physx/include/extensions/PxSerialization.h index 3283822f7..c72cd022d 100644 --- a/physx/include/extensions/PxSerialization.h +++ b/physx/include/extensions/PxSerialization.h @@ -44,7 +44,7 @@ PX_BINARY_SERIAL_VERSION is used to version the PhysX binary data and meta data. The global unique identifier of the PhysX SDK needs to match the one in the data and meta data, otherwise they are considered incompatible. A 32 character wide GUID can be generated with https://www.guidgenerator.com/ for example. */ -#define PX_BINARY_SERIAL_VERSION "C56A614AFD62406E944726BDD9A5E900" +#define PX_BINARY_SERIAL_VERSION "F57A6B4570DF49E38116AB1E0284A98B" #if !PX_DOXYGEN diff --git a/physx/include/extensions/PxTriangleMeshAnalysisResult.h b/physx/include/extensions/PxTriangleMeshAnalysisResult.h index e84bcf95c..e7833066e 100644 --- a/physx/include/extensions/PxTriangleMeshAnalysisResult.h +++ b/physx/include/extensions/PxTriangleMeshAnalysisResult.h @@ -54,9 +54,10 @@ namespace physx eCONTAINS_DUPLICATE_POINTS = (1 << 6), //!< ok: Duplicate points can be handled by the mesher without problems. The resulting tetmesh will only make use of first unique point that is found, duplicate points will get mapped to that unique point in the tetmesh. Therefore the tetmesh can contain points that are not accessed by a tet. eCONTAINS_INVALID_POINTS = (1 << 7), //!< invalid: Points contain NAN, infinity or similar values that will lead to an invalid mesh eREQUIRES_32BIT_INDEX_BUFFER = (1 << 8), //!< invalid: Mesh contains more indices than a 16bit index buffer can address + eTRIANGLE_INDEX_OUT_OF_RANGE = (1 << 9), //!< invalid: A mesh triangle index is negative or lager than the size of the vertex buffer - eMESH_IS_PROBLEMATIC = (1 << 9), //!< flag is set if the mesh is categorized as problematic - eMESH_IS_INVALID = (1 << 10) //!< flag is set if the mesh is categorized as invalid + eMESH_IS_PROBLEMATIC = (1 << 10), //!< flag is set if the mesh is categorized as problematic + eMESH_IS_INVALID = (1 << 11) //!< flag is set if the mesh is categorized as invalid }; }; typedef PxFlags PxTriangleMeshAnalysisResults; diff --git a/physx/include/foundation/PxPhysicsVersion.h b/physx/include/foundation/PxPhysicsVersion.h index d975ab55e..0db1ba0a5 100644 --- a/physx/include/foundation/PxPhysicsVersion.h +++ b/physx/include/foundation/PxPhysicsVersion.h @@ -50,7 +50,7 @@ sometimes they are stored in a byte. #define PX_PHYSICS_VERSION_MAJOR 5 #define PX_PHYSICS_VERSION_MINOR 3 -#define PX_PHYSICS_VERSION_BUGFIX 0 +#define PX_PHYSICS_VERSION_BUGFIX 1 /** The constant PX_PHYSICS_VERSION is used when creating certain PhysX module objects. diff --git a/physx/include/foundation/PxPinnedArray.h b/physx/include/foundation/PxPinnedArray.h index 020fb4383..82fe9a3b6 100644 --- a/physx/include/foundation/PxPinnedArray.h +++ b/physx/include/foundation/PxPinnedArray.h @@ -43,6 +43,7 @@ namespace physx typedef PxArray PxBoundsArrayPinned; typedef PxArray PxFloatArrayPinned; typedef PxArray PxInt32ArrayPinned; + typedef PxArray PxInt16ArrayPinned; typedef PxArray PxInt8ArrayPinned; #if !PX_DOXYGEN diff --git a/physx/include/foundation/PxPreprocessor.h b/physx/include/foundation/PxPreprocessor.h index 2c9e7a1b3..5ea63bb32 100644 --- a/physx/include/foundation/PxPreprocessor.h +++ b/physx/include/foundation/PxPreprocessor.h @@ -30,9 +30,7 @@ #define PX_PREPROCESSOR_H #include -#if !defined(PX_GENERATE_META_DATA) -#include -#endif + /** \addtogroup foundation @{ */ @@ -370,6 +368,15 @@ Final macro */ #define PX_FINAL final +/** +Unused attribute macro. Only on GCC for now. + */ +#if PX_GCC_FAMILY + #define PX_UNUSED_ATTRIBUTE __attribute__((unused)) +#else + #define PX_UNUSED_ATTRIBUTE +#endif + /** Alignment macros diff --git a/physx/include/geomutils/PxContactPoint.h b/physx/include/geomutils/PxContactPoint.h index 9630bf255..c6e363ab9 100644 --- a/physx/include/geomutils/PxContactPoint.h +++ b/physx/include/geomutils/PxContactPoint.h @@ -76,7 +76,6 @@ namespace physx \brief The surface index of shape 1 at the contact point. This is used to identify the surface material. \note This field is only supported by triangle meshes and heightfields, else it will be set to PXC_CONTACT_NO_FACE_INDEX. - \note This value must be directly after internalFaceIndex0 in memory */ PxU32 internalFaceIndex1; @@ -90,6 +89,9 @@ namespace physx */ PxReal restitution; + /** + \brief Damping coefficient (for compliant contacts) + */ PxReal damping; }; diff --git a/physx/include/omnipvd/PxOmniPvd.h b/physx/include/omnipvd/PxOmniPvd.h index cc7b8420b..63224d6c5 100644 --- a/physx/include/omnipvd/PxOmniPvd.h +++ b/physx/include/omnipvd/PxOmniPvd.h @@ -44,16 +44,72 @@ class PxFoundation; class PxOmniPvd { public: + class ScopedExclusiveWriter + { + public: + PX_FORCE_INLINE ScopedExclusiveWriter(PxOmniPvd* omniPvd) + { + mOmniPvd = omniPvd; + mWriter = NULL; + if (mOmniPvd) { + mWriter = mOmniPvd->acquireExclusiveWriterAccess(); + } + } + + PX_FORCE_INLINE ~ScopedExclusiveWriter() + { + if (mOmniPvd && mWriter) { + mOmniPvd->releaseExclusiveWriterAccess(); + } + } + + PX_FORCE_INLINE OmniPvdWriter* operator-> () + { + return mWriter; + } + + PX_FORCE_INLINE OmniPvdWriter* getWriter() + { + return mWriter; + } + private: + OmniPvdWriter* mWriter; + PxOmniPvd* mOmniPvd; + }; + virtual ~PxOmniPvd() { } /** - \brief Gets an instance of the OmniPvd writer + \brief Get the OmniPvd writer. + + Gets an instance of the OmniPvd writer. The writer access will not be thread safe since the OmniPVD API is not thread safe itself. Writing concurrently and simultaneously using the OmniPVD API is undefined. + + For thread safe exlcusive access use the mechanism acquireExclusiveWriterAccess/releaseExclusiveWriterAccess. \return OmniPvdWriter instance on succes, NULL otherwise. */ virtual OmniPvdWriter* getWriter() = 0; + /** + \brief Acquires an exclusive writer access. + + This call blocks until exclusive access to the writer can be acquired. Once access has been granted, it is guaranteed that no other caller can access the writer through this method until releaseExclusiveWriterAccess() has been called. + + This allows to safely write PVD data in environments with concurrent processing workflows. + + \return OmniPvdWriter instance on succes, NULL otherwise. + */ + virtual OmniPvdWriter* acquireExclusiveWriterAccess() = 0; + + /** + \brief Releases the exclusive writer access + + Releases the access to the writer that was previously acquired using acquireExclusiveWriterAccess. + + */ + virtual void releaseExclusiveWriterAccess() = 0; + /** \brief Gets an instance to the OmniPvd file write stream @@ -73,6 +129,7 @@ class PxOmniPvd */ virtual void release() = 0; + }; #if !PX_DOXYGEN } // namespace physx diff --git a/physx/include/solver/PxSolverDefs.h b/physx/include/solver/PxSolverDefs.h index 105f584df..db96cf876 100644 --- a/physx/include/solver/PxSolverDefs.h +++ b/physx/include/solver/PxSolverDefs.h @@ -130,14 +130,14 @@ struct PxSolverConstraintDesc PxU32 bodyADataIndex; //!< Body A's index into the SolverBodyData array PxU32 bodyBDataIndex; //!< Body B's index into the SolverBodyData array - PxU32 linkIndexA; //!< Link index defining which link in Articulation A this constraint affects. If not an articulation, must be NO_LINK - PxU32 linkIndexB; //!< Link index defining which link in Articulation B this constraint affects. If not an articulation, must be NO_LINK + PxU32 linkIndexA; //!< Link index defining which link in Articulation A this constraint affects. If not an articulation, must be PxSolverConstraintDesc::RIGID_BODY + PxU32 linkIndexB; //!< Link index defining which link in Articulation B this constraint affects. If not an articulation, must be PxSolverConstraintDesc::RIGID_BODY PxU8* constraint; //!< Pointer to the constraint rows to be solved void* writeBack; //!< Pointer to the writeback structure results for this given constraint are to be written to PxU16 progressA; //!< Internal progress counter PxU16 progressB; //!< Internal progress counter - PxU16 constraintLengthOver16; //!< constraintLength/16, max constraint length is 1MB, allows PxSolverConstraintDesc to fit in 32 bytes + PxU16 constraintLengthOver16; //!< constraintLength/16, max constraint length is 1MB PxU8 padding[10]; }; diff --git a/physx/snippets/snippetsdf/SnippetSDF.cpp b/physx/snippets/snippetsdf/SnippetSDF.cpp index 472aebb65..5589fafb5 100644 --- a/physx/snippets/snippetsdf/SnippetSDF.cpp +++ b/physx/snippets/snippetsdf/SnippetSDF.cpp @@ -79,7 +79,35 @@ static PxTriangleMesh* createMesh(PxCookingParams& params, const PxArray meshDesc.sdfDesc = &sdfDesc; } - return PxCreateTriangleMesh(params, meshDesc, gPhysics->getPhysicsInsertionCallback()); + bool enableCaching = false; + + if (enableCaching) + { + const char* path = "C:\\tmp\\PhysXSDFSnippetData.dat"; + bool ok = false; + FILE* fp = fopen(path, "rb"); + if (fp) + { + fclose(fp); + ok = true; + } + + if (!ok) + { + PxDefaultFileOutputStream stream(path); + ok = PxCookTriangleMesh(params, meshDesc, stream); + } + + if (ok) + { + PxDefaultFileInputData stream(path); + PxTriangleMesh* triangleMesh = gPhysics->createTriangleMesh(stream); + return triangleMesh; + } + return NULL; + } + else + return PxCreateTriangleMesh(params, meshDesc, gPhysics->getPhysicsInsertionCallback()); } static void addInstance(const PxTransform& transform, PxTriangleMesh* mesh) diff --git a/physx/source/compiler/cmake/linux/CMakeLists.txt b/physx/source/compiler/cmake/linux/CMakeLists.txt index 73529f8c6..e85352e8c 100644 --- a/physx/source/compiler/cmake/linux/CMakeLists.txt +++ b/physx/source/compiler/cmake/linux/CMakeLists.txt @@ -142,7 +142,7 @@ ELSE() SET(PX_SUPPORT_OMNI_PVD_FLAG "PX_SUPPORT_OMNI_PVD=1") ENDIF() SET(PHYSX_LINUX_COMPILE_DEFS "${PHYSX_AUTOBUILD};${PUBLIC_RELEASE_FLAG};${FEATURES_UNDER_CONSTRUCTION_FLAG}" CACHE INTERNAL "Base PhysX preprocessor definitions") -SET(PHYSX_LINUX_DEBUG_COMPILE_DEFS "NDEBUG;PX_DEBUG=1;PX_CHECKED=1;${NVTX_FLAG};PX_SUPPORT_PVD=1;${PX_SUPPORT_OMNI_PVD_FLAG}" CACHE INTERNAL "Debug PhysX preprocessor definitions") +SET(PHYSX_LINUX_DEBUG_COMPILE_DEFS "PX_DEBUG=1;PX_CHECKED=1;${NVTX_FLAG};PX_SUPPORT_PVD=1;${PX_SUPPORT_OMNI_PVD_FLAG}" CACHE INTERNAL "Debug PhysX preprocessor definitions") SET(PHYSX_LINUX_CHECKED_COMPILE_DEFS "NDEBUG;PX_CHECKED=1;${NVTX_FLAG};PX_SUPPORT_PVD=1;${PX_SUPPORT_OMNI_PVD_FLAG}" CACHE INTERNAL "Checked PhysX preprocessor definitions") SET(PHYSX_LINUX_PROFILE_COMPILE_DEFS "NDEBUG;PX_PROFILE=1;${NVTX_FLAG};PX_SUPPORT_PVD=1;${PX_SUPPORT_OMNI_PVD_FLAG}" CACHE INTERNAL "Profile PhysX preprocessor definitions") SET(PHYSX_LINUX_RELEASE_COMPILE_DEFS "NDEBUG;PX_SUPPORT_PVD=0;PX_SUPPORT_OMNI_PVD=0" CACHE INTERNAL "Release PhysX preprocessor definitions") diff --git a/physx/source/compiler/cmake/modules/NvidiaBuildOptions.cmake b/physx/source/compiler/cmake/modules/NvidiaBuildOptions.cmake index bf5c840e8..40ff7c796 100644 --- a/physx/source/compiler/cmake/modules/NvidiaBuildOptions.cmake +++ b/physx/source/compiler/cmake/modules/NvidiaBuildOptions.cmake @@ -84,7 +84,7 @@ SET(CRT_DEBUG_FLAG "/D \"_DEBUG\"") SET(CRT_NDEBUG_FLAG "/D \"NDEBUG\"") # Need a different format for CUDA -SET(CUDA_DEBUG_FLAG "-DNDEBUG ${DISABLE_ITERATOR_DEBUGGING_CUDA}") +SET(CUDA_DEBUG_FLAG "${DISABLE_ITERATOR_DEBUGGING_CUDA}") SET(CUDA_NDEBUG_FLAG "-DNDEBUG") SET(CUDA_CRT_COMPILE_OPTIONS_NDEBUG "") diff --git a/physx/source/geomutils/src/GuGeometryQuery.cpp b/physx/source/geomutils/src/GuGeometryQuery.cpp index 10808e53b..df304caa9 100644 --- a/physx/source/geomutils/src/GuGeometryQuery.cpp +++ b/physx/source/geomutils/src/GuGeometryQuery.cpp @@ -416,7 +416,7 @@ bool PxGeometryQuery::generateTriangleContacts(const PxGeometry& geom, const PxT Gu::PCMConvexVsMeshContactGeneration contactGeneration(contactDist, replaceBreakingThreshold, boxTransform, meshTransform, multiManifold, contactBuffer0, polyData, &boxMap, &deferredContacts, idtScaling, true, true, NULL); contactGeneration.processTriangle(triangleVertices, triangleIndex, Gu::ETD_CONVEX_EDGE_ALL, triangleIndices); - contactGeneration.processContacts(GU_CAPSULE_MANIFOLD_CACHE_SIZE, false); + contactGeneration.processContacts(GU_SINGLE_MANIFOLD_CACHE_SIZE, false); break; } @@ -446,7 +446,7 @@ bool PxGeometryQuery::generateTriangleContacts(const PxGeometry& geom, const PxT Gu::PCMConvexVsMeshContactGeneration contactGeneration(contactDist, replaceBreakingThreshold, convexTransform, meshTransform, multiManifold, contactBuffer0, polyData, &convexMap, &deferredContacts, convexScaling, idtConvexScale, true, NULL); contactGeneration.processTriangle(triangleVertices, triangleIndex, Gu::ETD_CONVEX_EDGE_ALL, triangleIndices); - contactGeneration.processContacts(GU_CAPSULE_MANIFOLD_CACHE_SIZE, false); + contactGeneration.processContacts(GU_SINGLE_MANIFOLD_CACHE_SIZE, false); break; } diff --git a/physx/source/geomutils/src/GuMeshFactory.cpp b/physx/source/geomutils/src/GuMeshFactory.cpp index 4ee1b3513..fcca54058 100644 --- a/physx/source/geomutils/src/GuMeshFactory.cpp +++ b/physx/source/geomutils/src/GuMeshFactory.cpp @@ -830,7 +830,6 @@ PxSoftBodyMesh* MeshFactory::createSoftBodyMesh(PxInputStream& desc) if (!::loadSoftBodyMeshData(desc, data)) return NULL; PxSoftBodyMesh* m = createSoftBodyMesh(data); - //PX_DELETE(data); return m; } @@ -848,8 +847,6 @@ PxTetrahedronMesh* MeshFactory::createTetrahedronMesh(TetrahedronMeshData& data) { TetrahedronMesh* np = NULL; PX_NEW_SERIALIZED(np, TetrahedronMesh)(this, data); - //PX_ASSERT(false); - //PX_UNUSED(data); if (np) addTetrahedronMesh(np); @@ -955,7 +952,7 @@ PxConvexMesh* MeshFactory::createConvexMesh(PxInputStream& desc) if(!np->load(desc)) { - RefCountable_decRefCount(*np); + Cm::deletePxBase(np); return NULL; } @@ -1011,7 +1008,7 @@ PxHeightField* MeshFactory::createHeightField(PxInputStream& stream) if(!np->load(stream)) { - RefCountable_decRefCount(*np); + Cm::deletePxBase(np); return NULL; } @@ -1114,7 +1111,7 @@ PxBVH* MeshFactory::createBVH(PxInputStream& desc) if(!np->load(desc)) { - np->decRefCount(); + Cm::deletePxBase(np); return NULL; } diff --git a/physx/source/geomutils/src/GuMetaData.cpp b/physx/source/geomutils/src/GuMetaData.cpp index 7c1409958..9fb0c0df5 100644 --- a/physx/source/geomutils/src/GuMetaData.cpp +++ b/physx/source/geomutils/src/GuMetaData.cpp @@ -64,22 +64,30 @@ static void getBinaryMetaData_BigConvexRawData(PxOutputStream& stream) void SDF::getBinaryMetaData(PxOutputStream& stream) { + PX_DEF_BIN_METADATA_CLASS(stream, Dim3) + PX_DEF_BIN_METADATA_ITEM(stream, Dim3, PxU32, x, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dim3, PxU32, y, 0) + PX_DEF_BIN_METADATA_ITEM(stream, Dim3, PxU32, z, 0) + PX_DEF_BIN_METADATA_CLASS(stream, SDF) PX_DEF_BIN_METADATA_ITEM(stream, SDF, PxVec3, mMeshLower, 0) PX_DEF_BIN_METADATA_ITEM(stream, SDF, PxReal, mSpacing, 0) PX_DEF_BIN_METADATA_ITEM(stream, SDF, Dim3, mDims, 0) - PX_DEF_BIN_METADATA_ITEM(stream, SDF, PxReal, mNumSdfs, 0) + PX_DEF_BIN_METADATA_ITEM(stream, SDF, PxU32, mNumSdfs, 0) PX_DEF_BIN_METADATA_ITEM(stream, SDF, PxReal, mSdf, PxMetaDataFlag::ePTR) PX_DEF_BIN_METADATA_ITEM(stream, SDF, PxU32, mSubgridSize, 0) PX_DEF_BIN_METADATA_ITEM(stream, SDF, PxU32, mNumStartSlots, 0) PX_DEF_BIN_METADATA_ITEM(stream, SDF, PxU32, mSubgridStartSlots, PxMetaDataFlag::ePTR) PX_DEF_BIN_METADATA_ITEM(stream, SDF, PxU32, mNumSubgridSdfs, 0) - PX_DEF_BIN_METADATA_ITEM(stream, SDF, PxU8, mSubgridSdf, PxMetaDataFlag::ePTR) + PX_DEF_BIN_METADATA_ITEM(stream, SDF, PxU8, mSubgridSdf, PxMetaDataFlag::ePTR) PX_DEF_BIN_METADATA_ITEM(stream, SDF, Dim3, mSdfSubgrids3DTexBlockDim, 0) PX_DEF_BIN_METADATA_ITEM(stream, SDF, PxReal, mSubgridsMinSdfValue, 0) PX_DEF_BIN_METADATA_ITEM(stream, SDF, PxReal, mSubgridsMaxSdfValue, 0) PX_DEF_BIN_METADATA_ITEM(stream, SDF, PxU32, mBytesPerSparsePixel, 0) + PX_DEF_BIN_METADATA_ITEM(stream, SDF, bool, mOwnsMemory, 0) + + } void BigConvexData::getBinaryMetaData(PxOutputStream& stream) @@ -145,6 +153,7 @@ void Gu::ConvexMesh::getBinaryMetaData(PxOutputStream& stream) getBinaryMetaData_InternalObjectsData(stream); getBinaryMetaData_HullPolygonData(stream); getBinaryMetaData_ConvexHullData(stream); + SDF::getBinaryMetaData(stream); BigConvexData::getBinaryMetaData(stream); PX_DEF_BIN_METADATA_VCLASS(stream,ConvexMesh) @@ -174,6 +183,12 @@ void Gu::ConvexMesh::getBinaryMetaData(PxOutputStream& stream) PX_DEF_BIN_METADATA_EXTRA_ARRAY(stream, Gu::ConvexMesh, PxU8, mNb, 0, PxMetaDataFlag::eCOUNT_MASK_MSB) PX_DEF_BIN_METADATA_EXTRA_ALIGN(stream, ConvexMesh, 4) + + //mSdfData this is currently broken + //PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, Gu::SDF, PxReal, mSdf, mNumSdfs, 0, PX_SERIAL_ALIGN) + //PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, Gu::SDF, PxU32, mSubgridStartSlots, mNumStartSlots, 0, PX_SERIAL_ALIGN) + //PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, Gu::SDF, PxU8, mSubgridSdf, mNumSubgridSdfs, 0, PX_SERIAL_ALIGN) + // mBigConvexData PX_DEF_BIN_METADATA_EXTRA_ITEM(stream, Gu::ConvexMesh, BigConvexData, mBigConvexData, PX_SERIAL_ALIGN) } @@ -357,6 +372,8 @@ void BV4Tree::getBinaryMetaData(PxOutputStream& stream) void Gu::TriangleMesh::getBinaryMetaData(PxOutputStream& stream) { + SDF::getBinaryMetaData(stream); + PX_DEF_BIN_METADATA_VCLASS(stream, TriangleMesh) PX_DEF_BIN_METADATA_BASE_CLASS(stream, TriangleMesh, PxBase) @@ -384,27 +401,9 @@ void Gu::TriangleMesh::getBinaryMetaData(PxOutputStream& stream) PX_DEF_BIN_METADATA_ITEM(stream, TriangleMesh, void, mGRB_triAdjacencies, PxMetaDataFlag::ePTR) PX_DEF_BIN_METADATA_ITEM(stream, TriangleMesh, PxU32, mGRB_faceRemap, PxMetaDataFlag::ePTR) PX_DEF_BIN_METADATA_ITEM(stream, TriangleMesh, PxU32, mGRB_faceRemapInverse, PxMetaDataFlag::ePTR) - PX_DEF_BIN_METADATA_ITEM(stream, TriangleMesh, void, mGRB_BV32Tree, PxMetaDataFlag::ePTR) - - PX_DEF_BIN_METADATA_ITEM(stream, TriangleMesh, PxVec3, mSdfData.mMeshLower, 0) - PX_DEF_BIN_METADATA_ITEM(stream, TriangleMesh, PxReal, mSdfData.mSpacing, 0) - PX_DEF_BIN_METADATA_ITEM(stream, TriangleMesh, PxU32, mSdfData.mDims.x, 0) - PX_DEF_BIN_METADATA_ITEM(stream, TriangleMesh, PxU32, mSdfData.mDims.y, 0) - PX_DEF_BIN_METADATA_ITEM(stream, TriangleMesh, PxU32, mSdfData.mDims.z, 0) - PX_DEF_BIN_METADATA_ITEM(stream, TriangleMesh, PxU32, mSdfData.mNumSdfs, 0) - PX_DEF_BIN_METADATA_ITEM(stream, TriangleMesh, PxReal, mSdfData.mSdf, PxMetaDataFlag::ePTR) - - PX_DEF_BIN_METADATA_ITEM(stream, TriangleMesh, PxU32, mSdfData.mSubgridSize, 0) - PX_DEF_BIN_METADATA_ITEM(stream, TriangleMesh, PxU32, mSdfData.mNumStartSlots, 0) - PX_DEF_BIN_METADATA_ITEM(stream, TriangleMesh, PxU32, mSdfData.mSubgridStartSlots, PxMetaDataFlag::ePTR) - PX_DEF_BIN_METADATA_ITEM(stream, TriangleMesh, PxU32, mSdfData.mNumSubgridSdfs, 0) - PX_DEF_BIN_METADATA_ITEM(stream, TriangleMesh, PxU8, mSdfData.mSubgridSdf, PxMetaDataFlag::ePTR) - PX_DEF_BIN_METADATA_ITEM(stream, TriangleMesh, PxU32, mSdfData.mSdfSubgrids3DTexBlockDim.x, 0) - PX_DEF_BIN_METADATA_ITEM(stream, TriangleMesh, PxU32, mSdfData.mSdfSubgrids3DTexBlockDim.y, 0) - PX_DEF_BIN_METADATA_ITEM(stream, TriangleMesh, PxU32, mSdfData.mSdfSubgrids3DTexBlockDim.z, 0) - PX_DEF_BIN_METADATA_ITEM(stream, TriangleMesh, PxReal, mSdfData.mSubgridsMinSdfValue, 0) - PX_DEF_BIN_METADATA_ITEM(stream, TriangleMesh, PxReal, mSdfData.mSubgridsMaxSdfValue, 0) - PX_DEF_BIN_METADATA_ITEM(stream, TriangleMesh, PxU32, mSdfData.mBytesPerSparsePixel, 0) + PX_DEF_BIN_METADATA_ITEM(stream, TriangleMesh, Gu::BV32Tree, mGRB_BV32Tree, PxMetaDataFlag::ePTR) + + PX_DEF_BIN_METADATA_ITEM(stream, TriangleMesh, SDF, mSdfData, 0) PX_DEF_BIN_METADATA_ITEM(stream, TriangleMesh, PxU32, mAccumulatedTrianglesRef, PxMetaDataFlag::ePTR) PX_DEF_BIN_METADATA_ITEM(stream, TriangleMesh, PxU32, mTrianglesReferences, PxMetaDataFlag::ePTR) @@ -442,10 +441,12 @@ void Gu::TriangleMesh::getBinaryMetaData(PxOutputStream& stream) PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, TriangleMesh, PxU32, mAdjacencies, mNbTriangles, 0, 0) PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, TriangleMesh, PxU32, mAdjacencies, mNbTriangles, 0, 0) - // mSdf - PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, TriangleMesh, PxReal, mSdfData.mSdf, mSdfData.mNumSdfs, 0, PX_SERIAL_ALIGN) - PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, TriangleMesh, PxU32, mSdfData.mSubgridStartSlots, mSdfData.mNumStartSlots, 0, PX_SERIAL_ALIGN) - PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, TriangleMesh, PxU8, mSdfData.mSubgridSdf, mSdfData.mNumSubgridSdfs, 0, PX_SERIAL_ALIGN) + // GPU data missing! + + // mSdf, this is currently broken + //PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, TriangleMesh, PxReal, mSdfData.mSdf, mSdfData.mNumSdfs, 0, PX_SERIAL_ALIGN) + //PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, TriangleMesh, PxU32, mSdfData.mSubgridStartSlots, mSdfData.mNumStartSlots, 0, PX_SERIAL_ALIGN) + //PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, TriangleMesh, PxU8, mSdfData.mSubgridSdf, mSdfData.mNumSubgridSdfs, 0, PX_SERIAL_ALIGN) // mAccumulatedTrianglesRef // PX_DEF_BIN_METADATA_EXTRA_ITEMS(stream, TriangleMesh, PxU32, mAccumulatedTrianglesRef, mNbTrianglesReferences, 0, PX_SERIAL_ALIGN) diff --git a/physx/source/geomutils/src/GuSDF.cpp b/physx/source/geomutils/src/GuSDF.cpp index db0aa4fbd..938536068 100644 --- a/physx/source/geomutils/src/GuSDF.cpp +++ b/physx/source/geomutils/src/GuSDF.cpp @@ -47,6 +47,7 @@ #include "PxSDFBuilder.h" #include "GuDistancePointSegment.h" +#include "common/PxSerialFramework.h" #define EXTENDED_DEBUG 0 @@ -56,9 +57,12 @@ namespace Gu { SDF::~SDF() { - PX_FREE(mSdf); - PX_FREE(mSubgridStartSlots); - PX_FREE(mSubgridSdf); + if(mOwnsMemory) + { + PX_FREE(mSdf); + PX_FREE(mSubgridStartSlots); + PX_FREE(mSubgridSdf); + } } PxReal* SDF::allocateSdfs(const PxVec3& meshLower, const PxReal& spacing, const PxU32 dimX, const PxU32 dimY, const PxU32 dimZ, @@ -119,7 +123,38 @@ namespace Gu return mSdf; } + void SDF::exportExtraData(PxSerializationContext& context) + { + if (mSdf) + { + context.alignData(PX_SERIAL_ALIGN); + context.writeData(mSdf, mNumSdfs * sizeof(PxReal)); + } + + if (mNumStartSlots) + { + context.alignData(PX_SERIAL_ALIGN); + context.writeData(mSubgridStartSlots, mNumStartSlots * sizeof(PxU32)); + } + + if (mSubgridSdf) + { + context.alignData(PX_SERIAL_ALIGN); + context.writeData(mSubgridSdf, mNumSubgridSdfs * sizeof(PxU8)); + } + } + + void SDF::importExtraData(PxDeserializationContext& context) + { + if (mSdf) + mSdf = context.readExtraData(mNumSdfs); + + if (mSubgridStartSlots) + mSubgridStartSlots = context.readExtraData(mNumStartSlots); + if (mSubgridSdf) + mSubgridSdf = context.readExtraData(mNumSubgridSdfs); + } void buildTree(const PxU32* triangles, const PxU32 numTriangles, const PxVec3* points, PxArray& tree, PxF32 enlargement = 1e-4f) { @@ -1432,45 +1467,45 @@ namespace Gu } } } - } + } - PxReal SDF::decodeSparse(PxI32 xx, PxI32 yy, PxI32 zz) const + PX_INLINE PxReal decodeSparse2(const SDF& sdf, PxI32 xx, PxI32 yy, PxI32 zz) { - if (xx < 0 || yy < 0 || zz < 0 || xx > PxI32(mDims.x) || yy > PxI32(mDims.y) || zz > PxI32(mDims.z)) + if (xx < 0 || yy < 0 || zz < 0 || xx > PxI32(sdf.mDims.x) || yy > PxI32(sdf.mDims.y) || zz > PxI32(sdf.mDims.z)) return 1.0f; //Return a value >0 that counts as outside - const PxU32 nbX = mDims.x / mSubgridSize; - const PxU32 nbY = mDims.y / mSubgridSize; - const PxU32 nbZ = mDims.z / mSubgridSize; - - PxU32 xBase = xx / mSubgridSize; - PxU32 yBase = yy / mSubgridSize; - PxU32 zBase = zz / mSubgridSize; + const PxU32 nbX = sdf.mDims.x / sdf.mSubgridSize; + const PxU32 nbY = sdf.mDims.y / sdf.mSubgridSize; + const PxU32 nbZ = sdf.mDims.z / sdf.mSubgridSize; + + PxU32 xBase = xx / sdf.mSubgridSize; + PxU32 yBase = yy / sdf.mSubgridSize; + PxU32 zBase = zz / sdf.mSubgridSize; - PxU32 x = xx % mSubgridSize; - PxU32 y = yy % mSubgridSize; - PxU32 z = zz % mSubgridSize; + PxU32 x = xx % sdf.mSubgridSize; + PxU32 y = yy % sdf.mSubgridSize; + PxU32 z = zz % sdf.mSubgridSize; if (xBase == nbX) { --xBase; - x = mSubgridSize; + x = sdf.mSubgridSize; } if (yBase == nbY) { --yBase; - y = mSubgridSize; + y = sdf.mSubgridSize; } if (zBase == nbZ) { --zBase; - z = mSubgridSize; + z = sdf.mSubgridSize; } - PxU32 startId = mSubgridStartSlots[zBase * (nbX) * (nbY)+yBase * (nbX)+xBase]; + PxU32 startId = sdf.mSubgridStartSlots[zBase * (nbX) * (nbY)+yBase * (nbX)+xBase]; if (startId != 0xFFFFFFFFu) { - decodeTriple(startId, xBase, yBase, zBase); + SDF::decodeTriple(startId, xBase, yBase, zBase); /*if (xBase >= mSdfSubgrids3DTexBlockDim.x || yBase >= mSdfSubgrids3DTexBlockDim.y || zBase >= mSdfSubgrids3DTexBlockDim.z) { @@ -1478,29 +1513,37 @@ namespace Gu //printf("%i %i %i %i\n", PxI32(startId), PxI32(xBase), PxI32(yBase), PxI32(zBase)); }*/ - xBase *= (mSubgridSize + 1); - yBase *= (mSubgridSize + 1); - zBase *= (mSubgridSize + 1); + xBase *= (sdf.mSubgridSize + 1); + yBase *= (sdf.mSubgridSize + 1); + zBase *= (sdf.mSubgridSize + 1); - const PxU32 w = mSdfSubgrids3DTexBlockDim.x * (mSubgridSize + 1); - const PxU32 h = mSdfSubgrids3DTexBlockDim.y * (mSubgridSize + 1); + const PxU32 w = sdf.mSdfSubgrids3DTexBlockDim.x * (sdf.mSubgridSize + 1); + const PxU32 h = sdf.mSdfSubgrids3DTexBlockDim.y * (sdf.mSubgridSize + 1); const PxU32 index = idx3D(xBase + x, yBase + y, zBase + z, w, h); //if (mBytesPerSparsePixel * index >= mNumSubgridSdfs) // PxGetFoundation().error(::physx::PxErrorCode::eINTERNAL_ERROR, PX_FL, "Out of bounds sdf subgrid access\n"); - - return decodeSample(&mSubgridSdf[mBytesPerSparsePixel * index], - mBytesPerSparsePixel, mSubgridsMinSdfValue, mSubgridsMaxSdfValue); + + return SDF::decodeSample(sdf.mSubgridSdf, index, + sdf.mBytesPerSparsePixel, sdf.mSubgridsMinSdfValue, sdf.mSubgridsMaxSdfValue); } else { - DenseSDF coarseEval(nbX + 1, nbY + 1, nbZ + 1, mSdf); - PxReal s = 1.0f / mSubgridSize; - return coarseEval.sampleSDFDirect(PxVec3(xBase + x * s, yBase + y * s, zBase + z * s)); + DenseSDF coarseEval(nbX + 1, nbY + 1, nbZ + 1, sdf.mSdf); + + PxReal s = 1.0f / sdf.mSubgridSize; + PxReal result = coarseEval.sampleSDFDirect(PxVec3(xBase + x * s, yBase + y * s, zBase + z * s)); + + return result; } } + PxReal SDF::decodeSparse(PxI32 xx, PxI32 yy, PxI32 zz) const + { + return decodeSparse2(*this, xx, yy, zz); + } + PX_FORCE_INLINE PxU64 key(PxI32 xId, PxI32 yId, PxI32 zId) { const PxI32 offset = 1 << 19; @@ -1640,10 +1683,11 @@ namespace Gu PX_FORCE_INLINE bool generatePointInCellUsingCache(const Gu::SDF& sdf, PxI32 xBase, PxI32 yBase, PxI32 zBase, PxI32 x, PxI32 y, PxI32 z, PxVec3& point, const PxArray& cache) { + const PxU32 s = sdf.mSubgridSize + 1; PxReal corners[2][2][2]; for (PxI32 xx = 0; xx <= 1; ++xx) for (PxI32 yy = 0; yy <= 1; ++yy) for (PxI32 zz = 0; zz <= 1; ++zz) { - PxReal v = cache[idx3D(x + xx, y + yy, z + zz, sdf.mSubgridSize + 1, sdf.mSubgridSize + 1)]; + PxReal v = cache[idx3D(x + xx, y + yy, z + zz, s, s)]; corners[xx][yy][zz] = v; } return generatePointInCell(sdf, xBase * sdf.mSubgridSize + x, yBase * sdf.mSubgridSize + y, zBase * sdf.mSubgridSize + z, point, corners); @@ -1684,7 +1728,7 @@ namespace Gu PxU32 negativeCounter = 0; for (PxI32 xx = 0; xx <= 1; ++xx) for (PxI32 yy = 0; yy <= 1; ++yy) for (PxI32 zz = 0; zz <= 1; ++zz) { - PxReal v = sdf.decodeSparse((i + xx)* sdf.mSubgridSize, (j + yy) * sdf.mSubgridSize, (k + zz) * sdf.mSubgridSize); + PxReal v = decodeSparse2(sdf, (i + xx)* sdf.mSubgridSize, (j + yy) * sdf.mSubgridSize, (k + zz) * sdf.mSubgridSize); if (v > t) ++positiveCounter; if (v < t) @@ -1696,7 +1740,54 @@ namespace Gu return false; } - void createTriangles(PxI32 xId, PxI32 yId, PxI32 zId, PxReal d0, PxReal ds[3], const PxHashMap& cellToPoint, const PxArray& points, PxArray& triangleIndices) + struct Map : public PxHashMap, public PxUserAllocated + { + Map() + { + + } + }; + + struct CellToPoint + { + PxArray cellToPoint; + + CellToPoint(PxU32 numThreads) + { + cellToPoint.resize(numThreads); + for (PxU32 i = 0; i < cellToPoint.size(); ++i) + cellToPoint[i] = PX_NEW(Map); + } + + ~CellToPoint() + { + for (PxU32 i = 0; i < cellToPoint.size(); ++i) + { + PX_DELETE(cellToPoint[i]); + } + } + + const PxPair* find(PxI32 xId, PxI32 yId, PxI32 zId) const + { + PxU64 k = key(xId, yId, zId); + + for (PxU32 i = 0; i < cellToPoint.size(); ++i) + { + const PxPair* f = cellToPoint[i]->find(k); + if (f) + return f; + } + return NULL; + } + + void insert(PxI32 threadId, PxI32 xId, PxI32 yId, PxI32 zId, PxU32 value) + { + cellToPoint[threadId]->insert(key(xId, yId, zId), value); + } + }; + + PX_INLINE void createTriangles(PxI32 xId, PxI32 yId, PxI32 zId, PxReal d0, PxReal ds[3], + const CellToPoint& cellToPoint, const PxArray& points, PxArray& triangleIndices) { bool flipTriangleOrientation = false; const PxReal threshold = 0.0f; @@ -1713,7 +1804,7 @@ namespace Gu PxI32 buffer[4]; - const PxPair* f = cellToPoint.find(key(xId, yId, zId)); + const PxPair* f = cellToPoint.find(xId, yId, zId); if (!f) return; @@ -1729,10 +1820,10 @@ namespace Gu { bool flip = flipTriangleOrientation == b1; bool skip = false; - + for (PxI32 ii = 0; ii < 3; ++ii) { - f = cellToPoint.find(key(xId + offsets[dim][ii][0], yId + offsets[dim][ii][1], zId + offsets[dim][ii][2])); + f = cellToPoint.find(xId + offsets[dim][ii][0], yId + offsets[dim][ii][1], zId + offsets[dim][ii][2]); if (f) buffer[ii + 1] = f->second; else @@ -1762,8 +1853,128 @@ namespace Gu } } + PX_INLINE void populateSubgridCache(const Gu::SDF& sdf, PxArray& sdfCache, PxI32 i, PxI32 j, PxI32 k) + { + const PxU32 s = sdf.mSubgridSize + 1; + + for (PxU32 z = 0; z <= sdf.mSubgridSize; ++z) + for (PxU32 y = 0; y <= sdf.mSubgridSize; ++y) + for (PxU32 x = 0; x <= sdf.mSubgridSize; ++x) + { + sdfCache[idx3D(x, y, z, s, s)] = + decodeSparse2(sdf, i * PxI32(sdf.mSubgridSize) + PxI32(x), + j * PxI32(sdf.mSubgridSize) + PxI32(y), + k * PxI32(sdf.mSubgridSize) + PxI32(z)); + } + } + + struct IsosurfaceThreadData + { + const Gu::SDF& sdf; + PxArray isosurfaceVertices; + const PxArray& allIsosurfaceVertices; + PxArray isosurfaceTriangleIndices; + PxArray sdfCache; + CellToPoint& cellToPoint; + PxU32 startIndex; + PxU32 endIndex; + PxU32 threadIndex; + PxI32 nbX; + PxI32 nbY; + PxI32 nbZ; + + IsosurfaceThreadData(const Gu::SDF& sdf_, CellToPoint& cellToPoint_, const PxArray& allIsosurfaceVertices_) : + sdf(sdf_), allIsosurfaceVertices(allIsosurfaceVertices_), cellToPoint(cellToPoint_) + { } + }; + + void* computeIsosurfaceVerticesThreadJob(void* data) + { + IsosurfaceThreadData & d = *reinterpret_cast(data); + + for (PxU32 indexer = d.startIndex; indexer < d.endIndex; ++indexer) + { + PxU32 ii, jj, kk; + idToXYZ(indexer, d.nbX, d.nbY, ii, jj, kk); + + PxI32 i = PxI32(ii) - 1; + PxI32 j = PxI32(jj) - 1; + PxI32 k = PxI32(kk) - 1; + + if (canSkipSubgrid(d.sdf, i, j, k)) + continue; + + populateSubgridCache(d.sdf, d.sdfCache, i, j, k); - void extractIsosurfaceFromSDF(const Gu::SDF& sdf, PxArray& isosurfaceVertices, PxArray& isosurfaceTriangleIndices) + //Process the subgrid + for (PxU32 z = 0; z < d.sdf.mSubgridSize; ++z) + { + for (PxU32 y = 0; y < d.sdf.mSubgridSize; ++y) + { + for (PxU32 x = 0; x < d.sdf.mSubgridSize; ++x) + { + PxVec3 p; + if (generatePointInCellUsingCache(d.sdf, i, j, k, x, y, z, p, d.sdfCache)) + { + PxU32 xId = i * d.sdf.mSubgridSize + x; + PxU32 yId = j * d.sdf.mSubgridSize + y; + PxU32 zId = k * d.sdf.mSubgridSize + z; + d.cellToPoint.insert(d.threadIndex, xId, yId, zId, d.isosurfaceVertices.size()); + d.isosurfaceVertices.pushBack(p); + } + } + } + } + } + + return NULL; + } + + void* computeIsosurfaceTrianglesThreadJob(void* data) + { + IsosurfaceThreadData & d = *reinterpret_cast(data); + + const PxU32 s = d.sdf.mSubgridSize + 1; + + for (PxU32 indexer = d.startIndex; indexer < d.endIndex; ++indexer) + { + PxU32 ii, jj, kk; + idToXYZ(indexer, d.nbX, d.nbY, ii, jj, kk); + + PxI32 i = PxI32(ii) - 1; + PxI32 j = PxI32(jj) - 1; + PxI32 k = PxI32(kk) - 1; + + if (canSkipSubgrid(d.sdf, i, j, k)) + continue; + + populateSubgridCache(d.sdf, d.sdfCache, i, j, k); + + PxReal ds[3]; + //Process the subgrid + for (PxU32 z = 0; z < d.sdf.mSubgridSize; ++z) + { + for (PxU32 y = 0; y < d.sdf.mSubgridSize; ++y) + { + for (PxU32 x = 0; x < d.sdf.mSubgridSize; ++x) + { + PxReal d0 = d.sdfCache[idx3D(x, y, z, s, s)]; + ds[0] = d.sdfCache[idx3D(x + 1, y, z, s, s)]; + ds[1] = d.sdfCache[idx3D(x, y + 1, z, s, s)]; + ds[2] = d.sdfCache[idx3D(x, y, z + 1, s, s)]; + + createTriangles(x + i * d.sdf.mSubgridSize, y + j * d.sdf.mSubgridSize, z + k * d.sdf.mSubgridSize, d0, ds, + d.cellToPoint, d.allIsosurfaceVertices, d.isosurfaceTriangleIndices); + + } + } + } + } + + return NULL; + } + + void extractIsosurfaceFromSDFSerial(const Gu::SDF& sdf, PxArray& isosurfaceVertices, PxArray& isosurfaceTriangleIndices) { isosurfaceVertices.clear(); isosurfaceTriangleIndices.clear(); @@ -1772,7 +1983,16 @@ namespace Gu const PxI32 nbY = sdf.mDims.y / PxMax(1u, sdf.mSubgridSize); const PxI32 nbZ = sdf.mDims.z / PxMax(1u, sdf.mSubgridSize); - PxHashMap cellToPoint; + PxU32 sizeEstimate = PxU32(PxSqrt(PxReal(nbX*nbY * nbZ))); + CellToPoint cellToPoint(1); + + + isosurfaceVertices.reserve(sizeEstimate); + isosurfaceTriangleIndices.reserve(sizeEstimate); + + PxArray sdfCache; + sdfCache.resize((sdf.mSubgridSize + 1) * (sdf.mSubgridSize + 1) * (sdf.mSubgridSize + 1)); + if (sdf.mSubgridSize == 0) { @@ -1784,16 +2004,13 @@ namespace Gu PxVec3 p; if (generatePointInCellDense(sdf, i, j, k, p)) { - cellToPoint.insert(key(i, j, k), isosurfaceVertices.size()); + cellToPoint.insert(0, i, j, k, isosurfaceVertices.size()); isosurfaceVertices.pushBack(p); } } } else { - PxArray sdfCache; - sdfCache.resize((sdf.mSubgridSize + 1) * (sdf.mSubgridSize + 1) * (sdf.mSubgridSize + 1)); - for (PxI32 k = -1; k <= nbZ; ++k) { for (PxI32 j = -1; j <= nbY; ++j) @@ -1803,13 +2020,7 @@ namespace Gu if (canSkipSubgrid(sdf, i, j, k)) continue; - for (PxU32 z = 0; z <= sdf.mSubgridSize; ++z) - for (PxU32 y = 0; y <= sdf.mSubgridSize; ++y) - for (PxU32 x = 0; x <= sdf.mSubgridSize; ++x) - { - sdfCache[idx3D(x, y, z, sdf.mSubgridSize + 1, sdf.mSubgridSize + 1)] = - sdf.decodeSparse(i * PxI32(sdf.mSubgridSize) + PxI32(x), j * PxI32(sdf.mSubgridSize) + PxI32(y), k * PxI32(sdf.mSubgridSize) + PxI32(z)); - } + populateSubgridCache(sdf, sdfCache, i, j, k); //Process the subgrid for (PxU32 z = 0; z < sdf.mSubgridSize; ++z) @@ -1819,12 +2030,12 @@ namespace Gu for (PxU32 x = 0; x < sdf.mSubgridSize; ++x) { PxVec3 p; - PxU32 xId = i * sdf.mSubgridSize + x; - PxU32 yId = j * sdf.mSubgridSize + y; - PxU32 zId = k * sdf.mSubgridSize + z; if (generatePointInCellUsingCache(sdf, i, j, k, x, y, z, p, sdfCache)) { - cellToPoint.insert(key(xId, yId, zId), isosurfaceVertices.size()); + PxU32 xId = i * sdf.mSubgridSize + x; + PxU32 yId = j * sdf.mSubgridSize + y; + PxU32 zId = k * sdf.mSubgridSize + z; + cellToPoint.insert(0, xId, yId, zId, isosurfaceVertices.size()); isosurfaceVertices.pushBack(p); } } @@ -1852,6 +2063,7 @@ namespace Gu } else { + const PxU32 s = sdf.mSubgridSize + 1; for (PxI32 k = -1; k <= nbZ; ++k) { for (PxI32 j = -1; j <= nbY; ++j) @@ -1861,6 +2073,9 @@ namespace Gu if (canSkipSubgrid(sdf, i, j, k)) continue; + populateSubgridCache(sdf, sdfCache, i, j, k); + + PxReal ds[3]; //Process the subgrid for (PxU32 z = 0; z < sdf.mSubgridSize; ++z) { @@ -1868,13 +2083,13 @@ namespace Gu { for (PxU32 x = 0; x < sdf.mSubgridSize; ++x) { - PxReal d0 = sdf.decodeSparse(i * sdf.mSubgridSize + x, j * sdf.mSubgridSize + y, k * sdf.mSubgridSize + z); - PxReal ds[3]; - ds[0] = sdf.decodeSparse(i * sdf.mSubgridSize + x + 1, j * sdf.mSubgridSize + y, k * sdf.mSubgridSize + z); - ds[1] = sdf.decodeSparse(i * sdf.mSubgridSize + x, j * sdf.mSubgridSize + y + 1, k * sdf.mSubgridSize + z); - ds[2] = sdf.decodeSparse(i * sdf.mSubgridSize + x, j * sdf.mSubgridSize + y, k * sdf.mSubgridSize + z + 1); + PxReal d0 = sdfCache[idx3D(x, y, z, s, s)]; + ds[0] = sdfCache[idx3D(x + 1, y, z, s, s)]; + ds[1] = sdfCache[idx3D(x, y + 1, z, s, s)]; + ds[2] = sdfCache[idx3D(x, y, z + 1, s, s)]; - createTriangles(x + i * sdf.mSubgridSize, y + j * sdf.mSubgridSize, z + k * sdf.mSubgridSize, d0, ds, cellToPoint, isosurfaceVertices, isosurfaceTriangleIndices); + createTriangles(x + i * sdf.mSubgridSize, y + j * sdf.mSubgridSize, z + k * sdf.mSubgridSize, d0, ds, + cellToPoint, isosurfaceVertices, isosurfaceTriangleIndices); } } } @@ -1883,6 +2098,128 @@ namespace Gu } } } + + void extractIsosurfaceFromSDF(const Gu::SDF& sdf, PxArray& isosurfaceVertices, PxArray& isosurfaceTriangleIndices, PxU32 numThreads) + { + if (sdf.mSubgridSize == 0) + { + //Handle dense SDFs using the serial fallback + extractIsosurfaceFromSDFSerial(sdf, isosurfaceVertices, isosurfaceTriangleIndices); + return; + } + + numThreads = PxMax(1u, numThreads); + + PxArray threads; + PxArray perThreadData; + CellToPoint cellToPoint(numThreads); + + + const PxI32 nbX = sdf.mDims.x / PxMax(1u, sdf.mSubgridSize); + const PxI32 nbY = sdf.mDims.y / PxMax(1u, sdf.mSubgridSize); + const PxI32 nbZ = sdf.mDims.z / PxMax(1u, sdf.mSubgridSize); + + PxU32 l = (nbX + 2) * (nbY + 2) * (nbZ + 2); + PxU32 range = l / numThreads; + + for (PxU32 i = 0; i < numThreads; ++i) + { + perThreadData.pushBack(IsosurfaceThreadData(sdf, cellToPoint, isosurfaceVertices)); + + IsosurfaceThreadData& d = perThreadData[i]; + d.startIndex = i * range; + d.endIndex = (i + 1) * range; + if (i == numThreads - 1) + d.endIndex = l; + + d.nbX = nbX + 2; + d.nbY = nbY + 2; + d.nbZ = nbZ + 2; + + d.sdfCache.resize((sdf.mSubgridSize + 1) * (sdf.mSubgridSize + 1) * (sdf.mSubgridSize + 1)); + d.threadIndex = i; + } + + for (PxU32 i = 0; i < numThreads; ++i) + { + if (perThreadData.size() == 1) + computeIsosurfaceVerticesThreadJob(&perThreadData[i]); + else + { + threads.pushBack(PX_NEW(PxThread)(computeIsosurfaceVerticesThreadJob, &perThreadData[i], "thread")); + threads[i]->start(); + } + } + + for (PxU32 i = 0; i < threads.size(); ++i) + { + threads[i]->waitForQuit(); + } + + for (PxU32 i = 0; i < threads.size(); ++i) + { + threads[i]->~PxThreadT(); + PX_FREE(threads[i]); + } + + //Collect vertices + PxU32 sum = 0; + for (PxU32 i = 0; i < perThreadData.size(); ++i) + { + IsosurfaceThreadData& d = perThreadData[i]; + if (sum > 0) + { + for (PxHashMap::Iterator iter = cellToPoint.cellToPoint[i]->getIterator(); !iter.done(); ++iter) + iter->second += sum; + } + sum += d.isosurfaceVertices.size(); + } + + isosurfaceVertices.reserve(sum); + for (PxU32 i = 0; i < perThreadData.size(); ++i) + { + IsosurfaceThreadData& d = perThreadData[i]; + for (PxU32 j = 0; j < d.isosurfaceVertices.size(); ++j) + isosurfaceVertices.pushBack(d.isosurfaceVertices[j]); + d.isosurfaceTriangleIndices.reset(); //Release memory that is not needed anymore + } + + threads.clear(); + for (PxU32 i = 0; i < numThreads; ++i) + { + if (perThreadData.size() == 1) + computeIsosurfaceTrianglesThreadJob(&perThreadData[i]); + else + { + threads.pushBack(PX_NEW(PxThread)(computeIsosurfaceTrianglesThreadJob, &perThreadData[i], "thread")); + threads[i]->start(); + } + } + + for (PxU32 i = 0; i < threads.size(); ++i) + { + threads[i]->waitForQuit(); + } + + for (PxU32 i = 0; i < threads.size(); ++i) + { + threads[i]->~PxThreadT(); + PX_FREE(threads[i]); + } + + //Collect triangles + sum = 0; + for (PxU32 i = 0; i < perThreadData.size(); ++i) + sum += perThreadData[i].isosurfaceTriangleIndices.size(); + + isosurfaceTriangleIndices.resize(sum); + for (PxU32 i = 0; i < perThreadData.size(); ++i) + { + IsosurfaceThreadData& d = perThreadData[i]; + for (PxU32 j = 0; j < d.isosurfaceTriangleIndices.size(); ++j) + isosurfaceTriangleIndices.pushBack(d.isosurfaceTriangleIndices[j]); + } + } } } diff --git a/physx/source/geomutils/src/GuSDF.h b/physx/source/geomutils/src/GuSDF.h index e2e9fad19..4192d7216 100644 --- a/physx/source/geomutils/src/GuSDF.h +++ b/physx/source/geomutils/src/GuSDF.h @@ -41,6 +41,8 @@ namespace physx { class PxSDFBuilder; + class PxSerializationContext; + class PxDeserializationContext; namespace Gu { @@ -92,13 +94,15 @@ namespace physx public: // PX_SERIALIZATION - SDF(const PxEMPTY) {} - static void getBinaryMetaData(PxOutputStream& stream); + SDF(const PxEMPTY) : mOwnsMemory(false) {} + void exportExtraData(PxSerializationContext& context); + void importExtraData(PxDeserializationContext& context); + static void getBinaryMetaData(PxOutputStream& stream); //~PX_SERIALIZATION /** \brief Constructor */ - SDF() : mSdf(NULL), mSubgridStartSlots(NULL), mSubgridSdf(NULL) + SDF() : mSdf(NULL), mSubgridStartSlots(NULL), mSubgridSdf(NULL), mOwnsMemory(true) { } @@ -108,7 +112,7 @@ namespace physx SDF(PxZERO s) : mMeshLower(PxZero), mSpacing(0.0f), mDims(PxZero), mNumSdfs(0), mSdf(NULL), mSubgridSize(PxZero), mNumStartSlots(0), mSubgridStartSlots(NULL), mNumSubgridSdfs(0), mSubgridSdf(NULL), mSdfSubgrids3DTexBlockDim(PxZero), - mSubgridsMinSdfValue(0.0f), mSubgridsMaxSdfValue(0.0f), mBytesPerSparsePixel(0) + mSubgridsMinSdfValue(0.0f), mSubgridsMaxSdfValue(0.0f), mBytesPerSparsePixel(0), mOwnsMemory(true) { PX_UNUSED(s); } @@ -119,7 +123,8 @@ namespace physx SDF(const SDF& sdf) : mMeshLower(sdf.mMeshLower), mSpacing(sdf.mSpacing), mDims(sdf.mDims), mNumSdfs(sdf.mNumSdfs), mSdf(sdf.mSdf), mSubgridSize(sdf.mSubgridSize), mNumStartSlots(sdf.mNumStartSlots), mSubgridStartSlots(sdf.mSubgridStartSlots), mNumSubgridSdfs(sdf.mNumSubgridSdfs), mSubgridSdf(sdf.mSubgridSdf), mSdfSubgrids3DTexBlockDim(sdf.mSdfSubgrids3DTexBlockDim), - mSubgridsMinSdfValue(sdf.mSubgridsMinSdfValue), mSubgridsMaxSdfValue(sdf.mSubgridsMaxSdfValue), mBytesPerSparsePixel(sdf.mBytesPerSparsePixel) + mSubgridsMinSdfValue(sdf.mSubgridsMinSdfValue), mSubgridsMaxSdfValue(sdf.mSubgridsMaxSdfValue), mBytesPerSparsePixel(sdf.mBytesPerSparsePixel), + mOwnsMemory(true) { } @@ -132,23 +137,23 @@ namespace physx z = id & 0x000003FF; } - static PX_FORCE_INLINE PxReal decodeSample(PxU8* data, PxU32 bytesPerSparsePixel, PxReal subgridsMinSdfValue, PxReal subgridsMaxSdfValue) + static PX_FORCE_INLINE PxReal decodeSample(PxU8* data, PxU32 index, PxU32 bytesPerSparsePixel, PxReal subgridsMinSdfValue, PxReal subgridsMaxSdfValue) { switch (bytesPerSparsePixel) { case 1: - return PxReal(data[0]) * (1.0f / 255.0f) * (subgridsMaxSdfValue - subgridsMinSdfValue) + subgridsMinSdfValue; + return PxReal(data[index]) * (1.0f / 255.0f) * (subgridsMaxSdfValue - subgridsMinSdfValue) + subgridsMinSdfValue; case 2: { PxU16* ptr = reinterpret_cast(data); - return PxReal(ptr[0]) * (1.0f / 65535.0f) * (subgridsMaxSdfValue - subgridsMinSdfValue) + subgridsMinSdfValue; + return PxReal(ptr[index]) * (1.0f / 65535.0f) * (subgridsMaxSdfValue - subgridsMinSdfValue) + subgridsMinSdfValue; } case 4: { //If 4 bytes per subgrid pixel are available, then normal floats are used. No need to //de-normalize integer values since the floats already contain real distance values PxReal* ptr = reinterpret_cast(data); - return ptr[0]; + return ptr[index]; } default: PX_ASSERT(0); @@ -192,7 +197,6 @@ namespace physx \brief Destructor */ ~SDF(); - PxReal* allocateSdfs(const PxVec3& meshLower, const PxReal& spacing, const PxU32 dimX, const PxU32 dimY, const PxU32 dimZ, const PxU32 subgridSize, const PxU32 sdfSubgrids3DTexBlockDimX, const PxU32 sdfSubgrids3DTexBlockDimY, const PxU32 sdfSubgrids3DTexBlockDimZ, @@ -214,6 +218,7 @@ namespace physx PxReal mSubgridsMinSdfValue; //!< The minimum value over all subgrid blocks. Used if normalized textures are used which is the case for 8 and 16bit formats PxReal mSubgridsMaxSdfValue; //!< The maximum value over all subgrid blocks. Used if normalized textures are used which is the case for 8 and 16bit formats PxU32 mBytesPerSparsePixel; //!< The number of bytes per subgrid pixel + bool mOwnsMemory; //!< Only false for binary deserialized data }; /** @@ -332,8 +337,9 @@ namespace physx \param[in] sdf The signed distance function \param[out] isosurfaceVertices The vertices of the extracted isosurface \param[out] isosurfaceTriangleIndices The triangles of the extracted isosurface + \param[in] numThreads The number of threads to use */ - PX_PHYSX_COMMON_API void extractIsosurfaceFromSDF(const Gu::SDF& sdf, PxArray& isosurfaceVertices, PxArray& isosurfaceTriangleIndices); + PX_PHYSX_COMMON_API void extractIsosurfaceFromSDF(const Gu::SDF& sdf, PxArray& isosurfaceVertices, PxArray& isosurfaceTriangleIndices, PxU32 numThreads = 1); /** @@ -391,7 +397,7 @@ namespace physx */ PX_FORCE_INLINE PX_CUDA_CALLABLE PxU32 idx3D(PxU32 x, PxU32 y, PxU32 z, PxU32 width, PxU32 height) { - return z * width * height + y * width + x; + return (z * height + y) * width + x; } /** diff --git a/physx/source/geomutils/src/convex/GuConvexMesh.cpp b/physx/source/geomutils/src/convex/GuConvexMesh.cpp index f9299af44..2b3b95616 100644 --- a/physx/source/geomutils/src/convex/GuConvexMesh.cpp +++ b/physx/source/geomutils/src/convex/GuConvexMesh.cpp @@ -84,7 +84,11 @@ ConvexMesh::ConvexMesh(MeshFactory* factory, ConvexHullInitData& data) : mInertia (data.mInertia), mMeshFactory (factory) { - mHullData = data.mHullData; + mHullData = data.mHullData; + + // this constructor takes ownership of memory from the data object + data.mSdfData = NULL; + data.mBigConvexData = NULL; } ConvexMesh::~ConvexMesh() @@ -112,6 +116,14 @@ void ConvexMesh::exportExtraData(PxSerializationContext& context) const PxU32 bufferSize = computeBufferSize(mHullData, getNb()); context.writeData(mHullData.mPolygons, bufferSize); + if (mSdfData) + { + context.alignData(PX_SERIAL_ALIGN); + context.writeData(mSdfData, sizeof(SDF)); + + mSdfData->exportExtraData(context); + } + if(mBigConvexData) { context.alignData(PX_SERIAL_ALIGN); @@ -126,6 +138,13 @@ void ConvexMesh::importExtraData(PxDeserializationContext& context) const PxU32 bufferSize = computeBufferSize(mHullData, getNb()); mHullData.mPolygons = reinterpret_cast(context.readExtraData(bufferSize)); + if (mSdfData) + { + mSdfData = context.readExtraData(); + PX_PLACEMENT_NEW(mSdfData, SDF(PxEmpty)); + mSdfData->importExtraData(context); + } + if(mBigConvexData) { mBigConvexData = context.readExtraData(); diff --git a/physx/source/geomutils/src/cooking/GuCookingConvexMeshBuilder.cpp b/physx/source/geomutils/src/cooking/GuCookingConvexMeshBuilder.cpp index 338fc58e9..a450476b2 100644 --- a/physx/source/geomutils/src/cooking/GuCookingConvexMeshBuilder.cpp +++ b/physx/source/geomutils/src/cooking/GuCookingConvexMeshBuilder.cpp @@ -210,12 +210,12 @@ bool ConvexMeshBuilder::copy(Gu::ConvexHullInitData& hullData) { hullData.mHullData.mSdfData = mSdfData; hullData.mSdfData = mSdfData; + mSdfData = NULL; } else { hullData.mHullData.mSdfData = NULL; hullData.mSdfData = NULL; - mSdfData = NULL; } // internal data @@ -545,7 +545,6 @@ bool ConvexMeshBuilder::checkExtentRadiusRatio() void ConvexMeshBuilder::computeSDF(const PxConvexMeshDesc& desc) { - PX_DELETE(mSdfData); PX_NEW_SERIALIZED(mSdfData, SDF); //create triangle mesh from polygons @@ -610,8 +609,21 @@ void ConvexMeshBuilder::computeSDF(const PxConvexMeshDesc& desc) sdfDesc.subgridSize, sdfDesc.sdfSubgrids3DTexBlockDim.x, sdfDesc.sdfSubgrids3DTexBlockDim.y, sdfDesc.sdfSubgrids3DTexBlockDim.z, sdfDesc.subgridsMinSdfValue, sdfDesc.subgridsMaxSdfValue, sdfDesc.bitsPerSubgridPixel); - //copy, and compact to get rid of strides: - immediateCooking::gatherStrided(sdfDesc.sdf.data, sdf, sdfDesc.dims.x*sdfDesc.dims.y*sdfDesc.dims.z, sizeof(PxReal), sdfDesc.sdf.stride); + if (sdfDesc.subgridSize > 0) + { + //Sparse sdf + immediateCooking::gatherStrided(sdfDesc.sdf.data, sdf, sdfDesc.sdf.count, sizeof(PxReal), sdfDesc.sdf.stride); + + immediateCooking::gatherStrided(sdfDesc.sdfSubgrids.data, mSdfData->mSubgridSdf, + sdfDesc.sdfSubgrids.count, + sizeof(PxU8), sdfDesc.sdfSubgrids.stride); + immediateCooking::gatherStrided(sdfDesc.sdfStartSlots.data, mSdfData->mSubgridStartSlots, sdfDesc.sdfStartSlots.count, sizeof(PxU32), sdfDesc.sdfStartSlots.stride); + } + else + { + //copy, and compact to get rid of strides: + immediateCooking::gatherStrided(sdfDesc.sdf.data, sdf, sdfDesc.dims.x * sdfDesc.dims.y * sdfDesc.dims.z, sizeof(PxReal), sdfDesc.sdf.stride); + } } //~TEST_INTERNAL_OBJECTS diff --git a/physx/source/geomutils/src/mesh/GuBV32.cpp b/physx/source/geomutils/src/mesh/GuBV32.cpp index 4508297c4..32ee60da9 100644 --- a/physx/source/geomutils/src/mesh/GuBV32.cpp +++ b/physx/source/geomutils/src/mesh/GuBV32.cpp @@ -108,13 +108,13 @@ BV32Tree::BV32Tree(const PxEMPTY) void BV32Tree::exportExtraData(PxSerializationContext& stream) { stream.alignData(16); - stream.writeData(mPackedNodes, mNbNodes*sizeof(BV32DataPacked)); + stream.writeData(mPackedNodes, mNbPackedNodes*sizeof(BV32DataPacked)); } void BV32Tree::importExtraData(PxDeserializationContext& context) { context.alignExtraData(16); - mPackedNodes = context.readExtraData(mNbNodes); + mPackedNodes = context.readExtraData(mNbPackedNodes); } //~PX_SERIALIZATION diff --git a/physx/source/geomutils/src/mesh/GuTriangleMesh.cpp b/physx/source/geomutils/src/mesh/GuTriangleMesh.cpp index 30ef518e4..5bd23f11b 100644 --- a/physx/source/geomutils/src/mesh/GuTriangleMesh.cpp +++ b/physx/source/geomutils/src/mesh/GuTriangleMesh.cpp @@ -136,11 +136,9 @@ TriangleMesh::~TriangleMesh() PX_FREE(mVertices); PX_FREE(mGRB_triIndices); - PX_FREE(mGRB_triAdjacencies); PX_FREE(mGRB_faceRemap); PX_FREE(mGRB_faceRemapInverse); - PX_DELETE(mGRB_BV32Tree); PX_FREE(mAccumulatedTrianglesRef); @@ -196,23 +194,39 @@ void TriangleMesh::exportExtraData(PxSerializationContext& stream) stream.writeData(mAdjacencies, mNbTriangles * sizeof(PxU32) * 3); } - if(mSdfData.mSdf) + if(mGRB_triIndices) + { + const PxU32 triangleSize = mFlags & PxTriangleMeshFlag::e16_BIT_INDICES ? sizeof(PxU16) : sizeof(PxU32); + stream.alignData(PX_SERIAL_ALIGN); + stream.writeData(mGRB_triIndices, mNbTriangles * 3 * triangleSize); + } + + if(mGRB_triAdjacencies) { stream.alignData(PX_SERIAL_ALIGN); - stream.writeData(mSdfData.mSdf, mSdfData.mNumSdfs * sizeof(PxReal)); + stream.writeData(mGRB_triAdjacencies, mNbTriangles * sizeof(PxU32) * 4); } - if (mSdfData.mNumStartSlots) + if(mGRB_faceRemap) { stream.alignData(PX_SERIAL_ALIGN); - stream.writeData(mSdfData.mSubgridStartSlots, mSdfData.mNumStartSlots * sizeof(PxU32)); + stream.writeData(mGRB_faceRemap, mNbTriangles * sizeof(PxU32)); } - if (mSdfData.mSubgridSdf) + if(mGRB_faceRemapInverse) { stream.alignData(PX_SERIAL_ALIGN); - stream.writeData(mSdfData.mSubgridSdf, mSdfData.mNumSubgridSdfs * sizeof(PxU8)); + stream.writeData(mGRB_faceRemapInverse, mNbTriangles * sizeof(PxU32)); } + + if(mGRB_BV32Tree) + { + stream.alignData(PX_SERIAL_ALIGN); + stream.writeData(mGRB_BV32Tree, sizeof(BV32Tree)); + mGRB_BV32Tree->exportExtraData(stream); + } + + mSdfData.exportExtraData(stream); } void TriangleMesh::importExtraData(PxDeserializationContext& context) @@ -241,21 +255,37 @@ void TriangleMesh::importExtraData(PxDeserializationContext& context) if(mAdjacencies) mAdjacencies = context.readExtraData(3*mNbTriangles); - if(mSdfData.mSdf) - mSdfData.mSdf = context.readExtraData(mSdfData.mNumSdfs); + if(mGRB_triIndices) + { + if(mFlags & PxTriangleMeshFlag::e16_BIT_INDICES) + mGRB_triIndices = context.readExtraData(3 * mNbTriangles); + else + mGRB_triIndices = context.readExtraData(3 * mNbTriangles); + } + + if(mGRB_triAdjacencies) + { + mGRB_triAdjacencies = context.readExtraData(4 * mNbTriangles); + } - if (mSdfData.mSubgridStartSlots) - mSdfData.mSubgridStartSlots = context.readExtraData(mSdfData.mNumStartSlots); + if(mGRB_faceRemap) + { + mGRB_faceRemap = context.readExtraData(mNbTriangles); + } - if (mSdfData.mSubgridSdf) - mSdfData.mSubgridSdf = context.readExtraData(mSdfData.mNumSubgridSdfs); + if(mGRB_faceRemapInverse) + { + mGRB_faceRemapInverse = context.readExtraData(mNbTriangles); + } + if(mGRB_BV32Tree) + { + mGRB_BV32Tree = context.readExtraData(); + PX_PLACEMENT_NEW(mGRB_BV32Tree, BV32Tree(PxEmpty)); + mGRB_BV32Tree->importExtraData(context); + } - mGRB_triIndices = NULL; - mGRB_triAdjacencies = NULL; - mGRB_faceRemap = NULL; - mGRB_faceRemapInverse = NULL; - mGRB_BV32Tree = NULL; + mSdfData.importExtraData(context); } void TriangleMesh::onRefCountZero() diff --git a/physx/source/geomutils/src/mesh/GuTriangleMesh.h b/physx/source/geomutils/src/mesh/GuTriangleMesh.h index 761022842..69379b60d 100644 --- a/physx/source/geomutils/src/mesh/GuTriangleMesh.h +++ b/physx/source/geomutils/src/mesh/GuTriangleMesh.h @@ -79,7 +79,7 @@ class TriangleMesh : public PxTriangleMesh, public PxUserAllocated public: // PX_SERIALIZATION - TriangleMesh(PxBaseFlags baseFlags) : PxTriangleMesh(baseFlags) {} + TriangleMesh(PxBaseFlags baseFlags) : PxTriangleMesh(baseFlags), mSdfData(PxEmpty) {} void preExportDataReset() { Cm::RefCountable_preExportDataReset(*this); } virtual void exportExtraData(PxSerializationContext& context); diff --git a/physx/source/immediatemode/src/NpImmediateMode.cpp b/physx/source/immediatemode/src/NpImmediateMode.cpp index 2d6ad97d6..e9a9b824f 100644 --- a/physx/source/immediatemode/src/NpImmediateMode.cpp +++ b/physx/source/immediatemode/src/NpImmediateMode.cpp @@ -38,6 +38,7 @@ #include "../../lowleveldynamics/src/DyTGSContactPrep.h" #include "../../lowleveldynamics/src/DyTGS.h" #include "../../lowleveldynamics/src/DyConstraintPartition.h" +#include "../../lowleveldynamics/src/DyArticulationCpuGpu.h" #include "GuPersistentContactManifold.h" #include "NpConstraint.h" #include "common/PxProfileZone.h" @@ -106,7 +107,8 @@ namespace PX_FORCE_INLINE void immSolveInternalConstraints(PxReal dt, PxReal invDt, Cm::SpatialVectorF* impulses, Cm::SpatialVectorF* DeltaV, PxReal elapsedTime, bool velocityIteration, bool isTGS) { - FeatherstoneArticulation::solveInternalConstraints(dt, invDt, impulses, DeltaV, velocityIteration, isTGS, elapsedTime, isTGS ? 0.7f : 1.0f); + // PT: TODO: revisit the TGS coeff (PX-4516) + FeatherstoneArticulation::solveInternalConstraints(dt, invDt, impulses, DeltaV, velocityIteration, isTGS, elapsedTime, isTGS ? 0.7f : DY_ARTICULATION_PGS_BIAS_COEFFICIENT); } PX_FORCE_INLINE void immComputeUnconstrainedVelocitiesTGS(PxReal dt, PxReal totalDt, PxReal invDt, PxReal /*invTotalDt*/, const PxVec3& gravity, PxReal invLengthScale) @@ -119,7 +121,7 @@ namespace FeatherstoneArticulation::computeUnconstrainedVelocitiesInternal(gravity, Z, deltaV, invLengthScale); setupInternalConstraints(mArticulationData.getLinks(), mArticulationData.getLinkCount(), - mArticulationData.getArticulationFlags() & PxArticulationFlag::eFIX_BASE, mArticulationData, Z, dt, totalDt, invDt, 0.7f, true); + mArticulationData.getArticulationFlags() & PxArticulationFlag::eFIX_BASE, mArticulationData, Z, dt, totalDt, invDt, true); } PX_FORCE_INLINE void immComputeUnconstrainedVelocities(PxReal dt, const PxVec3& gravity, PxReal invLengthScale) @@ -131,7 +133,7 @@ namespace FeatherstoneArticulation::computeUnconstrainedVelocitiesInternal(gravity, Z, deltaV, invLengthScale); const PxReal invDt = 1.0f/dt; setupInternalConstraints(mArticulationData.getLinks(), mArticulationData.getLinkCount(), - mArticulationData.getArticulationFlags() & PxArticulationFlag::eFIX_BASE, mArticulationData, Z, dt, dt, invDt, 1.0f, false); + mArticulationData.getArticulationFlags() & PxArticulationFlag::eFIX_BASE, mArticulationData, Z, dt, dt, invDt, false); } void allocate(const PxU32 nbLinks); @@ -512,11 +514,6 @@ namespace } } - PX_FORCE_INLINE bool isArticulationConstraint(const PxSolverConstraintDesc& desc) - { - return desc.linkIndexA != PxSolverConstraintDesc::RIGID_BODY || desc.linkIndexB != PxSolverConstraintDesc::RIGID_BODY; - } - template PxU32 BatchConstraints(const PxSolverConstraintDesc* solverConstraintDescs, PxU32 nbConstraints, PxConstraintBatchHeader* outBatchHeaders, PxSolverConstraintDesc* outOrderedConstraintDescs, Classification& classification) diff --git a/physx/source/lowlevel/software/include/PxsIslandSim.h b/physx/source/lowlevel/software/include/PxsIslandSim.h index 7c2795d9f..9b88e1584 100644 --- a/physx/source/lowlevel/software/include/PxsIslandSim.h +++ b/physx/source/lowlevel/software/include/PxsIslandSim.h @@ -316,7 +316,7 @@ struct Island { PxNodeIndex mRootNode; PxNodeIndex mLastNode; - PxU32 mSize[Node::eTYPE_COUNT]; + PxU32 mNodeCount[Node::eTYPE_COUNT]; PxU32 mActiveIndex; EdgeIndex mFirstEdge[Edge::eEDGE_TYPE_COUNT], mLastEdge[Edge::eEDGE_TYPE_COUNT]; @@ -333,7 +333,7 @@ struct Island for(PxU32 a = 0; a < Node::eTYPE_COUNT; ++a) { - mSize[a] = 0; + mNodeCount[a] = 0; } } }; @@ -922,7 +922,7 @@ class IslandSim island.mRootNode = node.mNextNode; } - island.mSize[node.mType]--; + island.mNodeCount[node.mType]--; node.mNextNode = PxNodeIndex(); node.mPrevNode = PxNodeIndex(); } diff --git a/physx/source/lowlevel/software/src/PxsIslandSim.cpp b/physx/source/lowlevel/software/src/PxsIslandSim.cpp index 71998c096..bec41e6d4 100644 --- a/physx/source/lowlevel/software/src/PxsIslandSim.cpp +++ b/physx/source/lowlevel/software/src/PxsIslandSim.cpp @@ -140,7 +140,7 @@ void IslandSim::addNode(bool isActive, bool isKinematic, Node::NodeType type, Px mIslandAwake.growAndReset(PxMax(islandHandle+1, mIslands.size())); Island& island = mIslands[islandHandle]; island.mLastNode = island.mRootNode = nodeIndex; - island.mSize[type] = 1; + island.mNodeCount[type] = 1; mIslandIds[handle] = islandHandle; mIslandStaticTouchCount[islandHandle] = 0; } @@ -1022,7 +1022,7 @@ void IslandSim::processNewEdges() lastNode.mNextNode = nodeIndex1; node.mPrevNode = island.mLastNode; island.mLastNode = nodeIndex1; - island.mSize[node.mType]++; + island.mNodeCount[node.mType]++; mIslandIds[nodeIndex1.index()] = islandId2; mHopCounts[nodeIndex1.index()] = mHopCounts[nodeIndex2.index()] + 1; mFastRoute[nodeIndex1.index()] = nodeIndex2; @@ -1077,7 +1077,7 @@ void IslandSim::processNewEdges() lastNode.mNextNode = nodeIndex2; node.mPrevNode = island.mLastNode; island.mLastNode = nodeIndex2; - island.mSize[node.mType]++; + island.mNodeCount[node.mType]++; mIslandIds[nodeIndex2.index()] = islandId1; mHopCounts[nodeIndex2.index()] = mHopCounts[nodeIndex1.index()] + 1; mFastRoute[nodeIndex2.index()] = nodeIndex1; @@ -1470,7 +1470,7 @@ void IslandSim::processLostEdges(PxArray& destroyedNodes, bool allo //Verify state (that we can see the root from this node)... #if IG_SANITY_CHECKS - PX_ASSERT(canFindRoot(dirtyNode, searchNode, NULL)); //Verify that we found the connection + PX_ASSERT(canFindRoot(dirtyNodeIndex, searchNode, NULL)); //Verify that we found the connection #endif for (PxU32 b = 0; b < mVisitedNodes.size(); ++b) @@ -1502,20 +1502,24 @@ void IslandSim::processLostEdges(PxArray& destroyedNodes, bool allo //the island to establish the last node again #if IG_SANITY_CHECKS - PX_ASSERT(!canFindRoot(dirtyNode, searchNode, NULL)); + PX_ASSERT(!canFindRoot(dirtyNodeIndex, searchNode, NULL)); #endif PxU32 totalStaticTouchCount = 0; - PxU32 size[Edge::eEDGE_TYPE_COUNT]; - for (PxU32 i = 0; i < Edge::eEDGE_TYPE_COUNT; ++i) + PxU32 nodeCount[Node::eTYPE_COUNT]; + for (PxU32 t = 0; t < Node::eTYPE_COUNT; ++t) { - mIslandSplitEdges[i].forceSize_Unsafe(0); - size[i] = 0; + nodeCount[t] = 0; + } + + for (PxU32 t = 0; t < Edge::eEDGE_TYPE_COUNT; ++t) + { + mIslandSplitEdges[t].forceSize_Unsafe(0); } //NodeIndex lastIndex = oldIsland.mLastNode; - //size[node.mType] = 1; + //nodeCount[node.mType] = 1; for (PxU32 a = 0; a < mVisitedNodes.size(); ++a) { @@ -1529,7 +1533,7 @@ void IslandSim::processLostEdges(PxArray& destroyedNodes, bool allo if (node.mPrevNode.index() != PX_INVALID_NODE) mNodes[node.mPrevNode.index()].mNextNode = node.mNextNode; - size[node.mType]++; + nodeCount[node.mType]++; node.mNextNode.setIndices(PX_INVALID_NODE); node.mPrevNode.setIndices(PX_INVALID_NODE); @@ -1561,8 +1565,11 @@ void IslandSim::processLostEdges(PxArray& destroyedNodes, bool allo //oldIsland.mStaticTouchCount -= totalStaticTouchCount; mIslandStaticTouchCount[islandId] -= totalStaticTouchCount; - for (PxU32 i = 0; i < Edge::eEDGE_TYPE_COUNT; ++i) - oldIsland.mSize[i] -= size[i]; + for (PxU32 i = 0; i < Node::eTYPE_COUNT; ++i) + { + PX_ASSERT(nodeCount[i] <= oldIsland.mNodeCount[i]); + oldIsland.mNodeCount[i] -= nodeCount[i]; + } //Now add all these nodes to the new island @@ -1595,10 +1602,10 @@ void IslandSim::processLostEdges(PxArray& destroyedNodes, bool allo mNodes[dirtyNodeIndex.index()].mPrevNode.setIndices(PX_INVALID_NODE); //First node so doesn't have a preceding node mFastRoute[dirtyNodeIndex.index()].setIndices(PX_INVALID_NODE); - for (PxU32 i = 0; i < Edge::eEDGE_TYPE_COUNT; ++i) - size[i] = 0; + for (PxU32 i = 0; i < Node::eTYPE_COUNT; ++i) + nodeCount[i] = 0; - size[dirtyNode.mType] = 1; + nodeCount[dirtyNode.mType] = 1; for (PxU32 a = 1; a < mVisitedNodes.size(); ++a) { @@ -1607,14 +1614,14 @@ void IslandSim::processLostEdges(PxArray& destroyedNodes, bool allo const PxNodeIndex prevNodeIndex = mVisitedNodes[a - 1].mNodeIndex; thisNode.mPrevNode = prevNodeIndex; mNodes[prevNodeIndex.index()].mNextNode = index; - size[thisNode.mType]++; + nodeCount[thisNode.mType]++; mIslandIds[index.index()] = newIslandHandle; mHopCounts[index.index()] = mVisitedNodes[a].mDepth; //How many hops to root mFastRoute[index.index()] = mVisitedNodes[mVisitedNodes[a].mPrevIndex].mNodeIndex; } - for (PxU32 i = 0; i < Edge::eEDGE_TYPE_COUNT; ++i) - newIsland.mSize[i] = size[i]; + for (PxU32 i = 0; i < Node::eTYPE_COUNT; ++i) + newIsland.mNodeCount[i] = nodeCount[i]; //Last node in the island const PxNodeIndex lastIndex = mVisitedNodes[mVisitedNodes.size() - 1].mNodeIndex; @@ -1714,7 +1721,13 @@ void IslandSim::processLostEdges(PxArray& destroyedNodes, bool allo mIslandIds[nodeIndex.index()] = IG_INVALID_ISLAND; - if ((island.mSize[0] + island.mSize[1] + island.mSize[2] + island.mSize[3]) == 0) + PxU32 nodeCountTotal = 0; + for (PxU32 t = 0; t < Node::eTYPE_COUNT; ++t) + { + nodeCountTotal += island.mNodeCount[t]; + } + + if (nodeCountTotal == 0) { mIslandHandles.freeHandle(islandId); if (island.mActiveIndex != IG_INVALID_ISLAND) @@ -1872,10 +1885,10 @@ IslandId IslandSim::mergeIslands(IslandId island0, IslandId island1, PxNodeIndex PxU32 totalSize0 = 0; PxU32 totalSize1 = 0; - for (PxU32 i = 0; i < Edge::eEDGE_TYPE_COUNT; ++i) + for (PxU32 i = 0; i < Node::eTYPE_COUNT; ++i) { - totalSize0 += is0.mSize[i]; - totalSize1 += is1.mSize[i]; + totalSize0 += is0.mNodeCount[i]; + totalSize1 += is1.mNodeCount[i]; } if(totalSize0 > totalSize1) { @@ -1904,8 +1917,12 @@ bool IslandSim::checkInternalConsistency() const { const Island& island = mIslands[a]; - PxU32 expectedSize = island.mSize[0] + island.mSize[1]; - bool metLastNode = expectedSize == 0; + PxU32 expectedNodeCount = 0; + for (PxU32 t = 0; t < Node::eTYPE_COUNT; ++t) + { + expectedNodeCount += island.mNodeCount[t]; + } + bool metLastNode = expectedNodeCount == 0; PxNodeIndex nodeId = island.mRootNode; @@ -1919,12 +1936,12 @@ bool IslandSim::checkInternalConsistency() const PX_ASSERT(mNodes[nodeId.index()].mNextNode.index() == PX_INVALID_NODE); } - --expectedSize; + --expectedNodeCount; nodeId = mNodes[nodeId.index()].mNextNode; } - PX_ASSERT(expectedSize == 0); + PX_ASSERT(expectedNodeCount == 0); PX_ASSERT(metLastNode); } #endif @@ -1939,8 +1956,8 @@ void IslandSim::mergeIslandsInternal(Island& island0, Island& island1, IslandId PxU32 island1Size = 0; for(PxU32 nodeType = 0; nodeType < Node::eTYPE_COUNT; ++nodeType) { - island0Size += island0.mSize[nodeType]; - island1Size += island1.mSize[nodeType]; + island0Size += island0.mNodeCount[nodeType]; + island1Size += island1.mNodeCount[nodeType]; } #endif PX_ASSERT(island0Size >= island1Size); //We only ever merge the smaller island to the larger island @@ -1993,7 +2010,6 @@ void IslandSim::mergeIslandsInternal(Island& island0, Island& island1, IslandId //Merge the edge list for the islands... for(PxU32 a = 0; a < IG::Edge::eEDGE_TYPE_COUNT; ++a) { - island0.mSize[a] += island1.mSize[a]; if(island0.mLastEdge[a] != IG_INVALID_EDGE) { PX_ASSERT(mEdges[island0.mLastEdge[a]].mNextIslandEdge == IG_INVALID_EDGE); @@ -2015,7 +2031,12 @@ void IslandSim::mergeIslandsInternal(Island& island0, Island& island1, IslandId island1.mFirstEdge[a] = IG_INVALID_EDGE; island1.mLastEdge[a] = IG_INVALID_EDGE; island1.mEdgeCount[a] = 0; - island1.mSize[a] = 0; + } + + for (PxU32 a = 0; a < IG::Node::eTYPE_COUNT; ++a) + { + island0.mNodeCount[a] += island1.mNodeCount[a]; + island1.mNodeCount[a] = 0; } island1.mLastNode.setIndices(PX_INVALID_NODE); @@ -2169,11 +2190,11 @@ void IslandSim::setKinematic(PxNodeIndex nodeIndex) } } - PxU32 newSize = 0; - for(PxU32 i = 0; i < Edge::eEDGE_TYPE_COUNT; ++i) - newSize += island.mSize[i]; - - if(newSize == 0) + PxU32 newNodeCount = 0; + for(PxU32 i = 0; i < Node::eTYPE_COUNT; ++i) + newNodeCount += island.mNodeCount[i]; + + if(newNodeCount == 0) { // If this island is empty after having removed the edges of the node we've just set to kinematic // we invalidate all edges and set the island to inactive @@ -2285,7 +2306,7 @@ void IslandSim::setDynamic(PxNodeIndex nodeIndex) Island& island = mIslands[islandHandle]; island.mLastNode = island.mRootNode = nodeIndex; PX_ASSERT(mNodes[nodeIndex.index()].mNextNode.index() == PX_INVALID_NODE); - island.mSize[node.mType] = 1; + island.mNodeCount[node.mType] = 1; mIslandIds[nodeIndex.index()] = islandHandle; mIslandStaticTouchCount[islandHandle] = 0; diff --git a/physx/source/lowleveldynamics/include/DyFeatherstoneArticulation.h b/physx/source/lowleveldynamics/include/DyFeatherstoneArticulation.h index 3c39b7edd..30aba90a1 100644 --- a/physx/source/lowleveldynamics/include/DyFeatherstoneArticulation.h +++ b/physx/source/lowleveldynamics/include/DyFeatherstoneArticulation.h @@ -122,11 +122,13 @@ namespace Dy struct ArticulationInternalLimit { - //Initial error - PxReal errorLow; //4 4 - PxReal errorHigh; //4 8 - PxReal lowImpulse; //4 12 changed - PxReal highImpulse; //4 16 changed + // Initial error for high and low limits. Negative means limit is violated. + PxReal errorLow; + PxReal errorHigh; + + // Impulses are updated during solver iterations. + PxReal lowImpulse; + PxReal highImpulse; }; struct ArticulationImplicitDriveDesc @@ -775,7 +777,6 @@ namespace Dy PxReal dt, PxReal invDt, PxReal totalDt, - const PxReal biasCoefficient, PxU32& acCount, Cm::SpatialVectorF* Z); @@ -1474,7 +1475,6 @@ namespace Dy PxReal stepDt, PxReal dt, PxReal invDt, - PxReal erp, bool isTGSSolver); void setupInternalConstraintsRecursive( @@ -1486,7 +1486,6 @@ namespace Dy const PxReal stepDt, const PxReal dt, const PxReal invDt, - const PxReal erp, const bool isTGSSolver, const PxU32 linkID, const PxReal maxForceScale); diff --git a/physx/source/lowleveldynamics/include/DyParticleSystemCore.h b/physx/source/lowleveldynamics/include/DyParticleSystemCore.h index ecf20ec64..b15a5b0ee 100644 --- a/physx/source/lowleveldynamics/include/DyParticleSystemCore.h +++ b/physx/source/lowleveldynamics/include/DyParticleSystemCore.h @@ -85,6 +85,7 @@ class ParticleSystemCore PxU32 mMaxNeighborhood; PxArray mPhaseGroupToMaterialHandle; + PxArray mUniqueMaterialHandles; //just for reporting void addParticleBuffer(PxParticleBuffer* particleBuffer) { diff --git a/physx/source/lowleveldynamics/src/DyArticulationContactPrep.cpp b/physx/source/lowleveldynamics/src/DyArticulationContactPrep.cpp index bb90bd2da..d63e67db0 100644 --- a/physx/source/lowleveldynamics/src/DyArticulationContactPrep.cpp +++ b/physx/source/lowleveldynamics/src/DyArticulationContactPrep.cpp @@ -30,7 +30,7 @@ #include "foundation/PxVecMath.h" #include "DyCorrelationBuffer.h" #include "DySolverConstraintExtShared.h" -#include "DyConstraintPrep.h" +#include "DyArticulationCpuGpu.h" #include "DyFeatherstoneArticulation.h" using namespace physx::Gu; diff --git a/physx/source/lowleveldynamics/src/DyArticulationCpuGpu.h b/physx/source/lowleveldynamics/src/DyArticulationCpuGpu.h index b42e15527..8393115c2 100644 --- a/physx/source/lowleveldynamics/src/DyArticulationCpuGpu.h +++ b/physx/source/lowleveldynamics/src/DyArticulationCpuGpu.h @@ -33,6 +33,10 @@ #include "PxArticulationJointReducedCoordinate.h" #include "DyFeatherstoneArticulation.h" +#define DY_ARTICULATION_MIN_RESPONSE 1e-5f +#define DY_ARTICULATION_CFM 2e-4f +#define DY_ARTICULATION_PGS_BIAS_COEFFICIENT 0.8f + namespace physx { namespace Dy diff --git a/physx/source/lowleveldynamics/src/DyArticulationPImpl.h b/physx/source/lowleveldynamics/src/DyArticulationPImpl.h index 2b5d59156..a9de32065 100644 --- a/physx/source/lowleveldynamics/src/DyArticulationPImpl.h +++ b/physx/source/lowleveldynamics/src/DyArticulationPImpl.h @@ -97,11 +97,10 @@ class ArticulationPImpl PxReal dt, PxReal invDt, PxReal totalDt, - const PxReal biasCoefficient, PxU32& acCount, Cm::SpatialVectorF* Z) { - return FeatherstoneArticulation::setupSolverConstraintsTGS(desc, dt, invDt, totalDt, biasCoefficient, acCount, Z); + return FeatherstoneArticulation::setupSolverConstraintsTGS(desc, dt, invDt, totalDt, acCount, Z); } }; diff --git a/physx/source/lowleveldynamics/src/DyConstraintPrep.h b/physx/source/lowleveldynamics/src/DyConstraintPrep.h index 0da2b82cc..2c65563bf 100644 --- a/physx/source/lowleveldynamics/src/DyConstraintPrep.h +++ b/physx/source/lowleveldynamics/src/DyConstraintPrep.h @@ -35,9 +35,6 @@ #include "foundation/PxArray.h" #include "PxConstraint.h" -#define DY_ARTICULATION_MIN_RESPONSE 1e-5f -#define DY_ARTICULATION_CFM 2e-4f - namespace physx { diff --git a/physx/source/lowleveldynamics/src/DyConstraintSetup.cpp b/physx/source/lowleveldynamics/src/DyConstraintSetup.cpp index 537180f60..c62f86c6e 100644 --- a/physx/source/lowleveldynamics/src/DyConstraintSetup.cpp +++ b/physx/source/lowleveldynamics/src/DyConstraintSetup.cpp @@ -29,6 +29,7 @@ #include "foundation/PxMemory.h" #include "foundation/PxMathUtils.h" #include "DyConstraintPrep.h" +#include "DyArticulationCpuGpu.h" #include "PxsRigidBody.h" #include "DySolverConstraint1D.h" #include "foundation/PxSort.h" diff --git a/physx/source/lowleveldynamics/src/DyContactPrep4.cpp b/physx/source/lowleveldynamics/src/DyContactPrep4.cpp index e7cf12173..83d288e25 100644 --- a/physx/source/lowleveldynamics/src/DyContactPrep4.cpp +++ b/physx/source/lowleveldynamics/src/DyContactPrep4.cpp @@ -71,6 +71,7 @@ static void setupFinalizeSolverConstraints4(PxSolverContactDesc* PX_RESTRICT des const Vec4V zero = V4Zero(); const BoolV bFalse = BFFFF(); + const BoolV bTrue = BTTTT(); const FloatV fZero = FZero(); const PxU8 flags[4] = { PxU8(descs[0].hasForceThresholds ? SolverContactHeader::eHAS_FORCE_THRESHOLDS : 0), @@ -396,6 +397,8 @@ static void setupFinalizeSolverConstraints4(PxSolverContactDesc* PX_RESTRICT des ((PxU32(hasFinished[2] || !iter2.hasNextContact())) << 2) | ((PxU32(hasFinished[3] || !iter3.hasNextContact())) << 3); + // finished flags are used to be able to handle pairs with varying number + // of contact points in the same loop BoolV bFinished = BLoad(hasFinished); while(finished != 0xf) @@ -594,13 +597,15 @@ static void setupFinalizeSolverConstraints4(PxSolverContactDesc* PX_RESTRICT des FLoad(con3.maxImpulse)); } } + + // update the finished flags if (!(finished & 0x1)) { iter0.nextContact(patch0, contact0); newFinished |= PxU32(!iter0.hasNextContact()); } else - bFinished = BSetX(bFinished, bFalse); + bFinished = BSetX(bFinished, bTrue); if(!(finished & 0x2)) { @@ -608,7 +613,7 @@ static void setupFinalizeSolverConstraints4(PxSolverContactDesc* PX_RESTRICT des newFinished |= (PxU32(!iter1.hasNextContact()) << 1); } else - bFinished = BSetY(bFinished, bFalse); + bFinished = BSetY(bFinished, bTrue); if(!(finished & 0x4)) { @@ -616,7 +621,7 @@ static void setupFinalizeSolverConstraints4(PxSolverContactDesc* PX_RESTRICT des newFinished |= (PxU32(!iter2.hasNextContact()) << 2); } else - bFinished = BSetZ(bFinished, bFalse); + bFinished = BSetZ(bFinished, bTrue); if(!(finished & 0x8)) { @@ -624,7 +629,7 @@ static void setupFinalizeSolverConstraints4(PxSolverContactDesc* PX_RESTRICT des newFinished |= (PxU32(!iter3.hasNextContact()) << 3); } else - bFinished = BSetW(bFinished, bFalse); + bFinished = BSetW(bFinished, bTrue); } ptr = p; if(hasMaxImpulse) diff --git a/physx/source/lowleveldynamics/src/DyContactPrep4PF.cpp b/physx/source/lowleveldynamics/src/DyContactPrep4PF.cpp index 202260c8b..6cff16efd 100644 --- a/physx/source/lowleveldynamics/src/DyContactPrep4PF.cpp +++ b/physx/source/lowleveldynamics/src/DyContactPrep4PF.cpp @@ -68,6 +68,7 @@ static bool setupFinalizeSolverConstraintsCoulomb4(PxSolverContactDesc* PX_RESTR const Vec4V solverOffsetSlop = aos::V4LoadXYZW(descs[0].offsetSlop, descs[1].offsetSlop, descs[2].offsetSlop, descs[3].offsetSlop); const Vec4V zero = V4Zero(); + const BoolV bTrue = BTTTT(); PxU8 flags[4] = { PxU8(descs[0].hasForceThresholds ? SolverContactHeader::eHAS_FORCE_THRESHOLDS : 0), PxU8(descs[1].hasForceThresholds ? SolverContactHeader::eHAS_FORCE_THRESHOLDS : 0), @@ -241,20 +242,21 @@ static bool setupFinalizeSolverConstraintsCoulomb4(PxSolverContactDesc* PX_RESTR for(PxU32 i=0;i= descs[0].numFrictionPatches; - const bool hasFinished1 = i >= descs[1].numFrictionPatches; - const bool hasFinished2 = i >= descs[2].numFrictionPatches; - const bool hasFinished3 = i >= descs[3].numFrictionPatches; - - frictionIndex0 = hasFinished0 ? frictionIndex0 : descs[0].startFrictionPatchIndex + i; - frictionIndex1 = hasFinished1 ? frictionIndex1 : descs[1].startFrictionPatchIndex + i; - frictionIndex2 = hasFinished2 ? frictionIndex2 : descs[2].startFrictionPatchIndex + i; - frictionIndex3 = hasFinished3 ? frictionIndex3 : descs[3].startFrictionPatchIndex + i; - - const PxU32 clampedContacts0 = hasFinished0 ? 0 : c.frictionPatchContactCounts[frictionIndex0]; - const PxU32 clampedContacts1 = hasFinished1 ? 0 : c.frictionPatchContactCounts[frictionIndex1]; - const PxU32 clampedContacts2 = hasFinished2 ? 0 : c.frictionPatchContactCounts[frictionIndex2]; - const PxU32 clampedContacts3 = hasFinished3 ? 0 : c.frictionPatchContactCounts[frictionIndex3]; + bool hasFinished[4]; + hasFinished[0] = i >= descs[0].numFrictionPatches; + hasFinished[1] = i >= descs[1].numFrictionPatches; + hasFinished[2] = i >= descs[2].numFrictionPatches; + hasFinished[3] = i >= descs[3].numFrictionPatches; + + frictionIndex0 = hasFinished[0] ? frictionIndex0 : descs[0].startFrictionPatchIndex + i; + frictionIndex1 = hasFinished[1] ? frictionIndex1 : descs[1].startFrictionPatchIndex + i; + frictionIndex2 = hasFinished[2] ? frictionIndex2 : descs[2].startFrictionPatchIndex + i; + frictionIndex3 = hasFinished[3] ? frictionIndex3 : descs[3].startFrictionPatchIndex + i; + + const PxU32 clampedContacts0 = hasFinished[0] ? 0 : c.frictionPatchContactCounts[frictionIndex0]; + const PxU32 clampedContacts1 = hasFinished[1] ? 0 : c.frictionPatchContactCounts[frictionIndex1]; + const PxU32 clampedContacts2 = hasFinished[2] ? 0 : c.frictionPatchContactCounts[frictionIndex2]; + const PxU32 clampedContacts3 = hasFinished[3] ? 0 : c.frictionPatchContactCounts[frictionIndex3]; const PxU32 clampedFric0 = clampedContacts0 * numFrictionPerPoint; const PxU32 clampedFric1 = clampedContacts1 * numFrictionPerPoint; @@ -382,10 +384,10 @@ static bool setupFinalizeSolverConstraintsCoulomb4(PxSolverContactDesc* PX_RESTR //For all correlation heads - need to pull this out I think //OK, we have a counter for all our patches... - PxU32 finished = (PxU32(hasFinished0)) | - ((PxU32(hasFinished1)) << 1) | - ((PxU32(hasFinished2)) << 2) | - ((PxU32(hasFinished3)) << 3); + PxU32 finished = (PxU32(hasFinished[0])) | + ((PxU32(hasFinished[1])) << 1) | + ((PxU32(hasFinished[2])) << 2) | + ((PxU32(hasFinished[3])) << 3); CorrelationListIterator iter0(c, firstPatch0); CorrelationListIterator iter1(c, firstPatch1); @@ -404,10 +406,14 @@ static bool setupFinalizeSolverConstraintsCoulomb4(PxSolverContactDesc* PX_RESTR PxU32 contactCount = 0; PxU32 newFinished = - (PxU32(hasFinished0 || !iter0.hasNextContact())) | - ((PxU32(hasFinished1 || !iter1.hasNextContact())) << 1) | - ((PxU32(hasFinished2 || !iter2.hasNextContact())) << 2) | - ((PxU32(hasFinished3 || !iter3.hasNextContact())) << 3); + (PxU32(hasFinished[0] || !iter0.hasNextContact())) | + ((PxU32(hasFinished[1] || !iter1.hasNextContact())) << 1) | + ((PxU32(hasFinished[2] || !iter2.hasNextContact())) << 2) | + ((PxU32(hasFinished[3] || !iter3.hasNextContact())) << 3); + + // finished flags are used to be able to handle pairs with varying number + // of contact points in the same loop + BoolV bFinished = BLoad(hasFinished); PxU32 fricIndex = 0; @@ -557,9 +563,9 @@ static bool setupFinalizeSolverConstraintsCoulomb4(PxSolverContactDesc* PX_RESTR solverContact->raXnX = delAngVel0X; solverContact->raXnY = delAngVel0Y; solverContact->raXnZ = delAngVel0Z; - solverContact->velMultiplier = velMultiplier; + solverContact->velMultiplier = V4Sel(bFinished, zero, velMultiplier); solverContact->appliedForce = zero; - solverContact->scaledBias = scaledBias; + solverContact->scaledBias = V4Sel(bFinished, zero, scaledBias); solverContact->targetVelocity = targetVelocity; solverContact->maxImpulse = maxImpulse; } @@ -658,29 +664,40 @@ static bool setupFinalizeSolverConstraintsCoulomb4(PxSolverContactDesc* PX_RESTR friction->normalZ = tZ; } } + + // update the finished flags if(!(finished & 0x1)) { iter0.nextContact(patch0, contact0); newFinished |= PxU32(!iter0.hasNextContact()); } + else + bFinished = BSetX(bFinished, bTrue); if(!(finished & 0x2)) { iter1.nextContact(patch1, contact1); newFinished |= (PxU32(!iter1.hasNextContact()) << 1); } + else + bFinished = BSetY(bFinished, bTrue); if(!(finished & 0x4)) { iter2.nextContact(patch2, contact2); newFinished |= (PxU32(!iter2.hasNextContact()) << 2); } + else + bFinished = BSetZ(bFinished, bTrue); if(!(finished & 0x8)) { iter3.nextContact(patch3, contact3); newFinished |= (PxU32(!iter3.hasNextContact()) << 3); } + else + bFinished = BSetW(bFinished, bTrue); + } ptr = p; } diff --git a/physx/source/lowleveldynamics/src/DyDynamics.cpp b/physx/source/lowleveldynamics/src/DyDynamics.cpp index 73358dea9..38b97c5f3 100644 --- a/physx/source/lowleveldynamics/src/DyDynamics.cpp +++ b/physx/source/lowleveldynamics/src/DyDynamics.cpp @@ -170,16 +170,16 @@ DynamicsContext::DynamicsContext( PxcNpMemBlockPool* memBlockPool, mWorldSolverBody.maxSolverFrictionProgress=MAX_PERMITTED_SOLVER_PROGRESS; mWorldSolverBodyData.linearVelocity = mWorldSolverBodyData.angularVelocity = PxVec3(0.f); mWorldSolverBodyData.body2World = PxTransform(PxIdentity); - mSolverCore[PxFrictionType::ePATCH] = SolverCoreGeneral::create(frictionEveryIteration); - mSolverCore[PxFrictionType::eONE_DIRECTIONAL] = SolverCoreGeneralPF::create(); - mSolverCore[PxFrictionType::eTWO_DIRECTIONAL] = SolverCoreGeneralPF::create(); + mSolverCore[PxFrictionType::ePATCH] = PX_NEW(SolverCoreGeneral)(frictionEveryIteration); + mSolverCore[PxFrictionType::eONE_DIRECTIONAL] = PX_NEW(SolverCoreGeneralPF); + mSolverCore[PxFrictionType::eTWO_DIRECTIONAL] = PX_NEW(SolverCoreGeneralPF); } DynamicsContext::~DynamicsContext() { for(PxU32 i = 0; i < PxFrictionType::eFRICTION_COUNT; ++i) { - mSolverCore[i]->destroyV(); + PX_DELETE(mSolverCore[i]); } PX_DELETE(mExceededForceThresholdStream[1]); @@ -1703,7 +1703,10 @@ class PxsSolverSetupSolveTask : public Cm::Task const PxU32 unrollSize = 8; const PxU32 denom = PxMax(1u, (mThreadContext.mMaxPartitions*unrollSize)); const PxU32 MaxTasks = getTaskManager()->getCpuDispatcher()->getWorkerCount(); - const PxU32 idealThreads = (mThreadContext.numContactConstraintBatches+denom-1)/denom; + // PT: small improvement: if there's no contacts, use the number of bodies instead. + // That way the integration work still benefits from multiple tasks. + const PxU32 numWorkItems = mThreadContext.numContactConstraintBatches ? mThreadContext.numContactConstraintBatches : mIslandContext.mCounts.bodies; + const PxU32 idealThreads = (numWorkItems+denom-1)/denom; const PxU32 numTasks = PxMax(1u, PxMin(idealThreads, MaxTasks)); if(numTasks > 1) @@ -2271,8 +2274,8 @@ void DynamicsContext::updatePostKinematic(IG::SimpleIslandManager& simpleIslandM nbArticulations < articulationBatchMax) { const IG::Island& island = islandSim.getIsland(islandIds[currentIsland]); - nbBodies += island.mSize[IG::Node::eRIGID_BODY_TYPE]; - nbArticulations += island.mSize[IG::Node::eARTICULATION_TYPE]; + nbBodies += island.mNodeCount[IG::Node::eRIGID_BODY_TYPE]; + nbArticulations += island.mNodeCount[IG::Node::eARTICULATION_TYPE]; nbConstraints += island.mEdgeCount[IG::Edge::eCONSTRAINT]; nbContactManagers += island.mEdgeCount[IG::Edge::eCONTACT_MANAGER]; constraintCount = nbConstraints + nbContactManagers; @@ -2431,11 +2434,6 @@ void DynamicsContext::preIntegrationParallel( PxMemZero(solverBodyPool, bodyCount * sizeof(PxSolverBody)); } -inline void WaitBodyRequiredState(volatile PxU32* state, PxU32 requiredState) -{ - while(requiredState != *state ); -} - void solveParallel(SOLVER_PARALLEL_METHOD_ARGS) { Dy::ThreadContext& threadContext = *context.getThreadContext(); diff --git a/physx/source/lowleveldynamics/src/DyFeatherstoneArticulation.cpp b/physx/source/lowleveldynamics/src/DyFeatherstoneArticulation.cpp index 39785f5fe..13d829d60 100644 --- a/physx/source/lowleveldynamics/src/DyFeatherstoneArticulation.cpp +++ b/physx/source/lowleveldynamics/src/DyFeatherstoneArticulation.cpp @@ -1534,7 +1534,7 @@ namespace Dy PxTransform FeatherstoneArticulation::propagateTransform(const PxU32 linkID, ArticulationLink* links, ArticulationJointCoreData& jointDatum, Cm::SpatialVectorF* motionVelocities, const PxReal dt, const PxTransform& pBody2World, const PxTransform& currentTransform, PxReal* jointVelocities, PxReal* jointPositions, - const Cm::UnAlignedSpatialVector* motionMatrix, const Cm::UnAlignedSpatialVector* worldMotionMatrix) + const Cm::UnAlignedSpatialVector* motionMatrix, const Cm::UnAlignedSpatialVector* /*worldMotionMatrix*/) { ArticulationLink& link = links[linkID]; @@ -1611,86 +1611,55 @@ namespace Dy } case PxArticulationJointType::eSPHERICAL: { - if (1)//jointDatum.dof < 3) - { - Cm::SpatialVectorF worldVel = motionVelocities[linkID]; - - const PxTransform oldTransform = currentTransform; - - - PxVec3 worldAngVel = worldVel.top; - //PxVec3 worldAngVel = motionVelocities[linkID].top; - - PxReal dist = worldAngVel.normalize() * dt; - - if (dist > 1e-6f) - newWorldQ = PxQuat(dist, worldAngVel) * oldTransform.q; - else - newWorldQ = oldTransform.q; - - //newWorldQ = Ps::exp(worldAngVel*dt) * oldTransform.q; + Cm::SpatialVectorF worldVel = motionVelocities[linkID]; - //PxVec3 axis; + const PxTransform oldTransform = currentTransform; - newParentToChild = computeSphericalJointPositions(mArticulationData.mRelativeQuat[linkID], newWorldQ, - pBody2World.q); + PxVec3 worldAngVel = worldVel.top; + //PxVec3 worldAngVel = motionVelocities[linkID].top; - PxQuat jointRotation = newParentToChild * relativeQuat.getConjugate(); + PxReal dist = worldAngVel.normalize() * dt; - /*PxVec3 axis = jointRotation.getImaginaryPart(); - for (PxU32 i = 0; i < jointDatum.dof; ++i) - { - PxVec3 sa = mArticulationData.getMotionMatrix(jointDatum.jointOffset + i).top; - PxReal angle = -compAng(sa.dot(axis), jointRotation.w); - jPosition[i] = angle; - }*/ - - PxVec3 axis; PxReal angle; - jointRotation.toRadiansAndUnitAxis(angle, axis); - axis *= angle; - for (PxU32 i = 0; i < jointDatum.dof; ++i) - { - PxVec3 sa = mArticulationData.getMotionMatrix(jointDatum.jointOffset + i).top; - PxReal ang = -sa.dot(axis); - jPosition[i] = ang; - } - const PxVec3 e = newParentToChild.rotate(parentOffset); - const PxVec3 d = childOffset; - r = e + d; - - PX_ASSERT(r.isFinite()); - } + if (dist > 1e-6f) + newWorldQ = PxQuat(dist, worldAngVel) * oldTransform.q; else - { - PxVec3 worldAngVel = motionVelocities[linkID].top; - - newWorldQ = PxExp(worldAngVel*dt) * currentTransform.q; + newWorldQ = oldTransform.q; - newParentToChild = computeSphericalJointPositions(mArticulationData.mRelativeQuat[linkID], newWorldQ, - pBody2World.q, jPosition, motionMatrix, jointDatum.dof); + //newWorldQ = Ps::exp(worldAngVel*dt) * oldTransform.q; - /*PxQuat newQ = (pBody2World.q * newParentToChild.getConjugate()).getNormalized(); + //PxVec3 axis; - const PxQuat cB2w = newQ * joint->childPose.q; + newParentToChild = computeSphericalJointPositions(mArticulationData.mRelativeQuat[linkID], newWorldQ, + pBody2World.q); - const PxMat33 cB2w_m(cB2w); + PxQuat jointRotation = newParentToChild * relativeQuat.getConjugate(); - const PxVec3* axis = &cB2w_m.column0; + if(jointRotation.w < 0.0f) + jointRotation = -jointRotation; - PxU32 dofIdx = 0;*/ - PxVec3 relAngVel = worldAngVel - motionVelocities[link.parent].top; + /*PxVec3 axis = jointRotation.getImaginaryPart(); + for (PxU32 i = 0; i < jointDatum.dof; ++i) + { + PxVec3 sa = mArticulationData.getMotionMatrix(jointDatum.jointOffset + i).top; + PxReal angle = -compAng(sa.dot(axis), jointRotation.w); + jPosition[i] = angle; + }*/ - for (PxU32 i = 0; i < jointDatum.dof; ++i) - { - jVelocity[i] = worldMotionMatrix[i].top.dot(relAngVel); - } + PxVec3 axis; PxReal angle; + jointRotation.toRadiansAndUnitAxis(angle, axis); + axis *= angle; + for (PxU32 i = 0; i < jointDatum.dof; ++i) + { + PxVec3 sa = mArticulationData.getMotionMatrix(jointDatum.jointOffset + i).top; + PxReal ang = -sa.dot(axis); + jPosition[i] = ang; } - const PxVec3 e = newParentToChild.rotate(parentOffset); const PxVec3 d = childOffset; r = e + d; - + PX_ASSERT(r.isFinite()); + break; } case PxArticulationJointType::eFIX: @@ -2685,7 +2654,6 @@ namespace Dy const PxReal stepDt, const PxReal dt, const PxReal invDt, - const PxReal erp, const bool isTGSSolver, const PxU32 linkID, const PxReal maxForceScale) @@ -3024,7 +2992,7 @@ namespace Dy for (PxU32 i = 0; i < numChildren; ++i) { const PxU32 child = offset + i; - setupInternalConstraintsRecursive(links, linkCount, fixBase, data, Z, stepDt, dt, invDt, erp, isTGSSolver, child, maxForceScale); + setupInternalConstraintsRecursive(links, linkCount, fixBase, data, Z, stepDt, dt, invDt, isTGSSolver, child, maxForceScale); } } @@ -3312,7 +3280,6 @@ namespace Dy PxReal stepDt, PxReal dt, PxReal invDt, - PxReal erp, bool isTGSSolver) { PX_UNUSED(linkCount); @@ -3331,7 +3298,7 @@ namespace Dy { const PxU32 child = offset + i; - setupInternalConstraintsRecursive(links, linkCount, fixBase, data, Z, stepDt, dt, invDt, erp, isTGSSolver, child, maxForceScale); + setupInternalConstraintsRecursive(links, linkCount, fixBase, data, Z, stepDt, dt, invDt, isTGSSolver, child, maxForceScale); } PxU32 totalNumAttachments = 0; @@ -3460,7 +3427,7 @@ namespace Dy { acCount = 0; - setupInternalConstraints(links, linkCount, fixBase, data, Z, data.getDt(), data.getDt(), 1.f / data.getDt(), 1.f, false); + setupInternalConstraints(links, linkCount, fixBase, data, Z, data.getDt(), data.getDt(), 1.f / data.getDt(), false); return 0; } @@ -3469,7 +3436,6 @@ namespace Dy PxReal dt, PxReal invDt, PxReal totalDt, - const PxReal biasCoefficient, PxU32& acCount, Cm::SpatialVectorF* Z) { @@ -3482,9 +3448,8 @@ namespace Dy ArticulationLink* links = thisArtic->mArticulationData.getLinks(); const PxU32 linkCount = thisArtic->mArticulationData.getLinkCount(); const bool fixBase = thisArtic->mArticulationData.getArticulationFlags() & PxArticulationFlag::eFIX_BASE; - const PxReal erp = PxMin(0.7f, biasCoefficient); - thisArtic->setupInternalConstraints(links, linkCount, fixBase, thisArtic->mArticulationData, Z, dt, totalDt, invDt, erp, true); + thisArtic->setupInternalConstraints(links, linkCount, fixBase, thisArtic->mArticulationData, Z, dt, totalDt, invDt, true); return 0; } @@ -4776,7 +4741,7 @@ namespace Dy } - //Takes jointV, returns deltaF + //Takes and updates jointV, returns deltaF static PxReal solveLimit(ArticulationInternalLimit& limit, PxReal& jointV, const PxReal jointPDelta, const PxReal response, const PxReal recipResponse, const InternalConstraintSolverData& data) { @@ -4928,7 +4893,7 @@ namespace Dy if (PxAbs(jointV) > maxJointVel) { PxReal newJointV = PxClamp(jointV, -maxJointVel, maxJointVel); - deltaF += (newJointV - jointV) * constraint.recipResponse*data.erp; + deltaF += (newJointV - jointV) * constraint.recipResponse; jointV = newJointV; } diff --git a/physx/source/lowleveldynamics/src/DyFeatherstoneForwardDynamic.cpp b/physx/source/lowleveldynamics/src/DyFeatherstoneForwardDynamic.cpp index 7e479af8b..721329e0e 100644 --- a/physx/source/lowleveldynamics/src/DyFeatherstoneForwardDynamic.cpp +++ b/physx/source/lowleveldynamics/src/DyFeatherstoneForwardDynamic.cpp @@ -1951,6 +1951,8 @@ namespace Dy //PxQuat newParentToChild = (newRot * pBody2WorldRot.getConjugate()).getNormalized(); PxQuat jointRotation = newParentToChild * relativeQuat.getConjugate(); + if(jointRotation.w < 0.0f) + jointRotation = -jointRotation; PxReal radians; PxVec3 axis; @@ -2196,7 +2198,7 @@ namespace Dy //} #endif - //Gc and Gc are centre of mass poses of parent(p) and child(c) in the world frame. + //Gp and Gc are centre of mass poses of parent(p) and child(c) in the world frame. //Introduce Q(v, dt) = PxExp(worldAngVel*dt); //Lp and Lc are joint frames of parent(p) and child(c) in the parent and child body frames. diff --git a/physx/source/lowleveldynamics/src/DySolverConstraintDesc.h b/physx/source/lowleveldynamics/src/DySolverConstraintDesc.h index 2dcb8bf36..5b63d9448 100644 --- a/physx/source/lowleveldynamics/src/DySolverConstraintDesc.h +++ b/physx/source/lowleveldynamics/src/DySolverConstraintDesc.h @@ -84,10 +84,10 @@ enum Enum }; }; -PX_FORCE_INLINE bool isArticulationConstraint(const PxSolverConstraintDesc& desc) +PX_FORCE_INLINE bool isArticulationConstraint(const PxSolverConstraintDesc& desc) { - return (desc.linkIndexA != PxSolverConstraintDesc::RIGID_BODY ) || - (desc.linkIndexB != PxSolverConstraintDesc::RIGID_BODY); + return desc.linkIndexA != PxSolverConstraintDesc::RIGID_BODY + || desc.linkIndexB != PxSolverConstraintDesc::RIGID_BODY; } diff --git a/physx/source/lowleveldynamics/src/DySolverConstraintsBlock.cpp b/physx/source/lowleveldynamics/src/DySolverConstraintsBlock.cpp index c92079c25..aca43ce92 100644 --- a/physx/source/lowleveldynamics/src/DySolverConstraintsBlock.cpp +++ b/physx/source/lowleveldynamics/src/DySolverConstraintsBlock.cpp @@ -495,6 +495,9 @@ static void solveContact4_StaticBlock(const PxSolverConstraintDesc* PX_RESTRICT Vec4V accumDeltaF = vZero; + // numNormalConstr is the maxium number of normal constraints any of these 4 contacts have. + // Contacts with fewer normal constraints than that maximum apply zero force because their + // c.velMultiplier and c.biasedErr were set to zero in contact prepping (see the bFinished variables there) for(PxU32 i=0;i( - PX_ALLOC(sizeof(SolverCoreGeneral), "SolverCoreGeneral")); - - if (scg) + for(PxU32 i=0; ifrictionEveryIteration = fricEveryIteration; - } + Cm::SpatialVector& motionVel = motionVelocityArray[i]; + const PxSolverBody& atom = solverBodies[i]; - return scg; + V4StoreA(V4LoadA(&atom.linearVelocity.x), &motionVel.linear.x); + V4StoreA(V4LoadA(&atom.angularState.x), &motionVel.angular.x); + } } -void SolverCoreGeneral::destroyV() +// PT: this case is reached when e.g. a lot of objects falling but not touching yet. So there are no contacts but potentially a lot of bodies. +// See LegacyBenchmark/falling_spheres for example. +void solveNoContactsCase( PxU32 nbBodies, PxSolverBody* PX_RESTRICT solverBodies, Cm::SpatialVector* PX_RESTRICT motionVelocityArray, + PxU32 nbArticulations, ArticulationSolverDesc* PX_RESTRICT articulationListStart, Cm::SpatialVectorF* PX_RESTRICT Z, Cm::SpatialVectorF* PX_RESTRICT deltaV, + PxU32 nbPosIter, PxU32 nbVelIter, PxF32 dt, PxF32 invDt) { - this->~SolverCoreGeneral(); - PX_FREE_THIS; + saveMotionVelocities(nbBodies, solverBodies, motionVelocityArray); + + if(!nbArticulations) + return; + + const PxF32 biasCoefficient = DY_ARTICULATION_PGS_BIAS_COEFFICIENT; // PT: TODO: unify this number with immediate mode (it's not 0.8 there!) + const bool isTGS = false; + + //Even thought there are no external constraints, there may still be internal constraints in the articulations... + for(PxU32 i=0; isolveInternalConstraints(dt, invDt, Z, deltaV, false, isTGS, 0.0f, biasCoefficient); + + for(PxU32 i=0; isolveInternalConstraints(dt, invDt, Z, deltaV, true, isTGS, 0.0f, biasCoefficient); + + for(PxU32 j=0; jwritebackInternalConstraints(isTGS); } void SolverCoreGeneral::solveV_Blocks(SolverIslandParams& params) const { + const PxF32 biasCoefficient = DY_ARTICULATION_PGS_BIAS_COEFFICIENT; + const bool isTGS = false; + const PxI32 TempThresholdStreamSize = 32; ThresholdStreamElement tempThresholdStream[TempThresholdStreamSize]; @@ -199,30 +218,9 @@ void SolverCoreGeneral::solveV_Blocks(SolverIslandParams& params) const if(numConstraintHeaders == 0) { - for (PxU32 baIdx = 0; baIdx < bodyListSize; baIdx++) - { - Cm::SpatialVector& motionVel = motionVelocityArray[baIdx]; - const PxSolverBody& atom = bodyListStart[baIdx]; - - motionVel.linear = atom.linearVelocity; - motionVel.angular = atom.angularState; - } - - //Even thought there are no external constraints, there may still be internal constraints in the articulations... - for(PxU32 i = 0; i < positionIterations; ++i) - for (PxU32 j = 0; j < articulationListSize; ++j) - articulationListStart[j].articulation->solveInternalConstraints(params.dt, params.invDt, cache.Z, cache.deltaV, false, false, 0.f, 0.8f); - - for (PxU32 i = 0; i < articulationListSize; i++) - ArticulationPImpl::saveVelocity(articulationListStart[i].articulation, cache.deltaV); - - for (PxU32 i = 0; i < velocityIterations; ++i) - for (PxU32 j = 0; j < articulationListSize; ++j) - articulationListStart[j].articulation->solveInternalConstraints(params.dt, params.invDt, cache.Z, cache.deltaV, true, false, 0.f, 0.8f); - - for (PxU32 j = 0; j < articulationListSize; ++j) - articulationListStart[j].articulation->writebackInternalConstraints(false); - + solveNoContactsCase(bodyListSize, bodyListStart, motionVelocityArray, + articulationListSize, articulationListStart, cache.Z, cache.deltaV, + positionIterations, velocityIterations, params.dt, params.invDt); return; } @@ -235,24 +233,18 @@ void SolverCoreGeneral::solveV_Blocks(SolverIslandParams& params) const for (PxU32 iteration = positionIterations; iteration > 0; iteration--) //decreasing positive numbers == position iters { - cache.doFriction = this->frictionEveryIteration ? true : iteration <= 3; + cache.doFriction = mFrictionEveryIteration ? true : iteration <= 3; SolveBlockParallel(constraintList, batchCount, normalIter * batchCount, batchCount, cache, contactIterator, iteration == 1 ? gVTableSolveConcludeBlock : gVTableSolveBlock, normalIter); for (PxU32 i = 0; i < articulationListSize; ++i) - articulationListStart[i].articulation->solveInternalConstraints(params.dt, params.invDt, cache.Z, cache.deltaV, false, false, 0.f, 0.8f); + articulationListStart[i].articulation->solveInternalConstraints(params.dt, params.invDt, cache.Z, cache.deltaV, false, isTGS, 0.f, biasCoefficient); ++normalIter; } - for (PxU32 baIdx = 0; baIdx < bodyListSize; baIdx++) - { - const PxSolverBody& atom = bodyListStart[baIdx]; - Cm::SpatialVector& motionVel = motionVelocityArray[baIdx]; - motionVel.linear = atom.linearVelocity; - motionVel.angular = atom.angularState; - } + saveMotionVelocities(bodyListSize, bodyListStart, motionVelocityArray); for (PxU32 i = 0; i < articulationListSize; i++) ArticulationPImpl::saveVelocity(articulationListStart[i].articulation, cache.deltaV); @@ -267,7 +259,7 @@ void SolverCoreGeneral::solveV_Blocks(SolverIslandParams& params) const cache, contactIterator, gVTableSolveBlock, normalIter); for (PxU32 i = 0; i < articulationListSize; ++i) - articulationListStart[i].articulation->solveInternalConstraints(params.dt, params.invDt, cache.Z, cache.deltaV, true, false, 0.f, 0.8f); + articulationListStart[i].articulation->solveInternalConstraints(params.dt, params.invDt, cache.Z, cache.deltaV, true, isTGS, 0.f, biasCoefficient); ++normalIter; } @@ -286,7 +278,7 @@ void SolverCoreGeneral::solveV_Blocks(SolverIslandParams& params) const for (PxU32 i = 0; i < articulationListSize; ++i) { - articulationListStart[i].articulation->solveInternalConstraints(params.dt, params.invDt, cache.Z, cache.deltaV, true, false, 0.f, 0.8f); + articulationListStart[i].articulation->solveInternalConstraints(params.dt, params.invDt, cache.Z, cache.deltaV, true, isTGS, 0.f, biasCoefficient); articulationListStart[i].articulation->writebackInternalConstraints(false); } @@ -297,7 +289,7 @@ void SolverCoreGeneral::solveV_Blocks(SolverIslandParams& params) const if(cache.mThresholdStreamIndex > 0) { //Write back to global buffer - PxI32 threshIndex = PxAtomicAdd(outThresholdPairs, PxI32(cache.mThresholdStreamIndex)) - PxI32(cache.mThresholdStreamIndex); + const PxI32 threshIndex = PxAtomicAdd(outThresholdPairs, PxI32(cache.mThresholdStreamIndex)) - PxI32(cache.mThresholdStreamIndex); for(PxU32 b = 0; b < cache.mThresholdStreamIndex; ++b) { thresholdStream[b + threshIndex] = cache.mThresholdStream[b]; @@ -306,14 +298,15 @@ void SolverCoreGeneral::solveV_Blocks(SolverIslandParams& params) const } } -void SolverCoreGeneral::solveVParallelAndWriteBack -(SolverIslandParams& params, Cm::SpatialVectorF* Z, Cm::SpatialVectorF* deltaV) const +void SolverCoreGeneral::solveVParallelAndWriteBack(SolverIslandParams& params, Cm::SpatialVectorF* Z, Cm::SpatialVectorF* deltaV) const { #if PX_PROFILE_SOLVE_STALLS PxU64 startTime = readTimer(); PxU64 stallCount = 0; #endif + const PxF32 biasCoefficient = DY_ARTICULATION_PGS_BIAS_COEFFICIENT; + const bool isTGS = false; SolverContext cache; cache.solverBodyArray = params.bodyDataList; @@ -385,7 +378,7 @@ void SolverCoreGeneral::solveVParallelAndWriteBack { WAIT_FOR_PROGRESS(articIndexCompleted, targetArticIndex); // wait for arti solve of previous iteration - cache.doFriction = this->frictionEveryIteration ? true : (positionIterations - a) <= 3; + cache.doFriction = mFrictionEveryIteration ? true : (positionIterations - a) <= 3; for(PxU32 b = 0; b < nbPartitions; ++b) { WAIT_FOR_PROGRESS(constraintIndexCompleted, targetConstraintIndex); // wait for rigid solve of previous partition @@ -427,7 +420,7 @@ void SolverCoreGeneral::solveVParallelAndWriteBack PxI32 nbSolved = 0; while (articSolveStart < endIdx) { - articulationListStart[articSolveStart - articIndexCounter].articulation->solveInternalConstraints(dt, invDt, cache.Z, cache.deltaV, false, false, 0.f, 0.8f); + articulationListStart[articSolveStart - articIndexCounter].articulation->solveInternalConstraints(dt, invDt, cache.Z, cache.deltaV, false, isTGS, 0.f, biasCoefficient); articSolveStart++; nbSolved++; } @@ -566,7 +559,7 @@ void SolverCoreGeneral::solveVParallelAndWriteBack PxI32 nbSolved = 0; while (articSolveStart < endIdx) { - articulationListStart[articSolveStart - articIndexCounter].articulation->solveInternalConstraints(dt, invDt, cache.Z, cache.deltaV, true, false, 0.f, 0.8f); + articulationListStart[articSolveStart - articIndexCounter].articulation->solveInternalConstraints(dt, invDt, cache.Z, cache.deltaV, true, isTGS, 0.f, biasCoefficient); articSolveStart++; nbSolved++; } @@ -644,7 +637,7 @@ void SolverCoreGeneral::solveVParallelAndWriteBack PxI32 nbSolved = 0; while (articSolveStart < endIdx) { - articulationListStart[articSolveStart - articIndexCounter].articulation->solveInternalConstraints(dt, invDt, cache.Z, cache.deltaV, false, false, 0.f, 0.8f); + articulationListStart[articSolveStart - articIndexCounter].articulation->solveInternalConstraints(dt, invDt, cache.Z, cache.deltaV, false, isTGS, 0.f, biasCoefficient); articulationListStart[articSolveStart - articIndexCounter].articulation->writebackInternalConstraints(false); articSolveStart++; nbSolved++; @@ -687,7 +680,6 @@ void SolverCoreGeneral::solveVParallelAndWriteBack } #if PX_PROFILE_SOLVE_STALLS - PxU64 endTime = readTimer(); PxReal totalTime = (PxReal)(endTime - startTime); PxReal stallTime = (PxReal)stallCount; @@ -702,30 +694,6 @@ void SolverCoreGeneral::solveVParallelAndWriteBack #endif } -void SolverCoreGeneral::writeBackV -(const PxSolverConstraintDesc* PX_RESTRICT constraintList, const PxU32 /*constraintListSize*/, PxConstraintBatchHeader* batchHeaders, const PxU32 numBatches, - ThresholdStreamElement* PX_RESTRICT thresholdStream, const PxU32 thresholdStreamLength, PxU32& outThresholdPairs, - PxSolverBodyData* atomListData, WriteBackBlockMethod writeBackTable[]) const -{ - SolverContext cache; - cache.solverBodyArray = atomListData; - cache.mThresholdStream = thresholdStream; - cache.mThresholdStreamLength = thresholdStreamLength; - cache.mThresholdStreamIndex = 0; - - PxI32 outThreshIndex = 0; - for(PxU32 j = 0; j < numBatches; ++j) - { - PxU8 type = *constraintList[batchHeaders[j].startIndex].constraint; - writeBackTable[type](constraintList + batchHeaders[j].startIndex, - batchHeaders[j].stride, cache); - } - - outThresholdPairs = PxU32(outThreshIndex); -} - } } - -//#endif diff --git a/physx/source/lowleveldynamics/src/DySolverControl.h b/physx/source/lowleveldynamics/src/DySolverControl.h index cd0d4ccdf..52c34b7a0 100644 --- a/physx/source/lowleveldynamics/src/DySolverControl.h +++ b/physx/source/lowleveldynamics/src/DySolverControl.h @@ -34,34 +34,12 @@ namespace physx { - namespace Dy { -struct FsData; - -inline void BusyWaitState(volatile PxU32* state, const PxU32 requiredState) -{ - while(requiredState != *state ); -} - -inline void WaitBodyRequiredState(PxU32* state, const PxU32 requiredState) -{ - if(*state != requiredState) - { - BusyWaitState(state, requiredState); - } -} - -inline void BusyWaitStates(volatile PxU32* stateA, volatile PxU32* stateB, const PxU32 requiredStateA, const PxU32 requiredStateB) -{ - while(*stateA != requiredStateA); - while(*stateB != requiredStateB); -} - - class BatchIterator { + PX_NOCOPY(BatchIterator) public: PxConstraintBatchHeader* constraintBatchHeaders; PxU32 mSize; @@ -81,16 +59,12 @@ class BatchIterator mCurrentIndex = currentIndex; return constraintBatchHeaders[currentIndex]; } -private: - BatchIterator& operator=(const BatchIterator&); }; - -inline void SolveBlockParallel (PxSolverConstraintDesc* PX_RESTRICT constraintList, const PxI32 batchCount, const PxI32 index, - const PxI32 headerCount, SolverContext& cache, BatchIterator& iterator, - SolveBlockMethod solveTable[], - const PxI32 iteration - ) +inline void SolveBlockParallel( PxSolverConstraintDesc* PX_RESTRICT constraintList, const PxI32 batchCount, const PxI32 index, + const PxI32 headerCount, SolverContext& cache, BatchIterator& iterator, + SolveBlockMethod solveTable[], + const PxI32 iteration) { const PxI32 indA = index - (iteration * headerCount); @@ -105,6 +79,7 @@ inline void SolveBlockParallel (PxSolverConstraintDesc* PX_RESTRICT constraintLi const PxI32 numToGrab = header.stride; PxSolverConstraintDesc* PX_RESTRICT block = &constraintList[header.startIndex]; + // PT: TODO: revisit this one PxPrefetch(block[0].constraint, 384); for(PxI32 b = 0; b < numToGrab; ++b) @@ -118,34 +93,28 @@ inline void SolveBlockParallel (PxSolverConstraintDesc* PX_RESTRICT constraintLi } } +// PT: TODO: these "solver core" classes are mostly stateless, at this point they could just be function pointers like the solve methods. class SolverCoreGeneral : public SolverCore { public: - bool frictionEveryIteration; - static SolverCoreGeneral* create(bool fricEveryIteration); + bool mFrictionEveryIteration; + SolverCoreGeneral(bool fricEveryIteration) : mFrictionEveryIteration(fricEveryIteration) {} // SolverCore - virtual void destroyV(); - virtual void solveVParallelAndWriteBack - (SolverIslandParams& params, Cm::SpatialVectorF* Z, Cm::SpatialVectorF* deltaV) const; + (SolverIslandParams& params, Cm::SpatialVectorF* Z, Cm::SpatialVectorF* deltaV) const PX_OVERRIDE PX_FINAL; virtual void solveV_Blocks - (SolverIslandParams& params) const; - - virtual void writeBackV - (const PxSolverConstraintDesc* PX_RESTRICT constraintList, const PxU32 constraintListSize, PxConstraintBatchHeader* contactConstraintBatches, const PxU32 numBatches, - ThresholdStreamElement* PX_RESTRICT thresholdStream, const PxU32 thresholdStreamLength, PxU32& outThresholdPairs, - PxSolverBodyData* atomListData, WriteBackBlockMethod writeBackTable[]) const; + (SolverIslandParams& params) const PX_OVERRIDE PX_FINAL; //~SolverCore }; +// PT: TODO: we use "extern" instead of functions for TGS. Unify. SolveBlockMethod* getSolveBlockTable(); SolveBlockMethod* getSolverConcludeBlockTable(); SolveWriteBackBlockMethod* getSolveWritebackBlockTable(); } - } #endif diff --git a/physx/source/lowleveldynamics/src/DySolverControlPF.cpp b/physx/source/lowleveldynamics/src/DySolverControlPF.cpp index 3b2086136..fd6fd29e6 100644 --- a/physx/source/lowleveldynamics/src/DySolverControlPF.cpp +++ b/physx/source/lowleveldynamics/src/DySolverControlPF.cpp @@ -40,7 +40,7 @@ #include "DySolverConstraintDesc.h" #include "DySolverContext.h" #include "DySolverControlPF.h" -#include "DyFeatherstoneArticulation.h" +#include "DyArticulationCpuGpu.h" namespace physx { @@ -98,14 +98,6 @@ void solveFrictionCoulombPreBlock_WriteBack (DY_PGS_SOLVE_METHOD_PARAMS); void solveFrictionCoulombPreBlock_WriteBackStatic(DY_PGS_SOLVE_METHOD_PARAMS); -// could move this to PxPreprocessor.h but -// no implementation available for MSVC -#if PX_GCC_FAMILY -#define PX_UNUSED_ATTRIBUTE __attribute__((unused)) -#else -#define PX_UNUSED_ATTRIBUTE -#endif - static SolveBlockMethod gVTableSolveBlockCoulomb[] PX_UNUSED_ATTRIBUTE = { 0, @@ -163,25 +155,18 @@ static SolveBlockMethod gVTableSolveConcludeBlockCoulomb[] PX_UNUSED_ATTRIBUTE = solveFrictionCoulombPreBlock_ConcludeStatic // DY_SC_TYPE_BLOCK_STATIC_FRICTION }; -SolverCoreGeneralPF* SolverCoreGeneralPF::create() -{ - SolverCoreGeneralPF* scg = reinterpret_cast( - PX_ALLOC(sizeof(SolverCoreGeneralPF), "SolverCoreGeneral")); - - if(scg) - PX_PLACEMENT_NEW(scg, SolverCoreGeneralPF); +// PT: code shared with patch friction solver. Ideally should move to a shared DySolverCore.cpp file. +void solveNoContactsCase( PxU32 bodyListSize, PxSolverBody* PX_RESTRICT bodyListStart, Cm::SpatialVector* PX_RESTRICT motionVelocityArray, + PxU32 articulationListSize, ArticulationSolverDesc* PX_RESTRICT articulationListStart, Cm::SpatialVectorF* PX_RESTRICT Z, Cm::SpatialVectorF* PX_RESTRICT deltaV, + PxU32 positionIterations, PxU32 velocityIterations, PxF32 dt, PxF32 invDt); - return scg; -} - -void SolverCoreGeneralPF::destroyV() -{ - this->~SolverCoreGeneralPF(); - PX_FREE_THIS; -} +void saveMotionVelocities(PxU32 nbBodies, PxSolverBody* PX_RESTRICT solverBodies, Cm::SpatialVector* PX_RESTRICT motionVelocityArray); void SolverCoreGeneralPF::solveV_Blocks(SolverIslandParams& params) const { + const PxF32 biasCoefficient = DY_ARTICULATION_PGS_BIAS_COEFFICIENT; + const bool isTGS = false; + const PxI32 TempThresholdStreamSize = 32; ThresholdStreamElement tempThresholdStream[TempThresholdStreamSize]; @@ -194,7 +179,7 @@ void SolverCoreGeneralPF::solveV_Blocks(SolverIslandParams& params) const cache.deltaV = params.deltaV; cache.Z = params.Z; - PxI32 batchCount = PxI32(params.numConstraintHeaders); + const PxI32 batchCount = PxI32(params.numConstraintHeaders); PxSolverBody* PX_RESTRICT bodyListStart = params.bodyListStart; const PxU32 bodyListSize = params.bodyListSize; @@ -214,29 +199,9 @@ void SolverCoreGeneralPF::solveV_Blocks(SolverIslandParams& params) const if(numConstraintHeaders == 0) { - for (PxU32 baIdx = 0; baIdx < bodyListSize; baIdx++) - { - Cm::SpatialVector& motionVel = motionVelocityArray[baIdx]; - PxSolverBody& atom = bodyListStart[baIdx]; - motionVel.linear = atom.linearVelocity; - motionVel.angular = atom.angularState; - } - - //Even thought there are no external constraints, there may still be internal constraints in the articulations... - for (PxU32 i = 0; i < positionIterations; ++i) - for (PxU32 j = 0; j < articulationListSize; ++j) - articulationListStart[j].articulation->solveInternalConstraints(params.dt, params.invDt, cache.Z, cache.deltaV, false, false, 0.f, 0.8f); - - for (PxU32 i = 0; i < articulationListSize; i++) - ArticulationPImpl::saveVelocity(articulationListStart[i].articulation, cache.deltaV); - - for (PxU32 i = 0; i < velocityIterations; ++i) - for (PxU32 j = 0; j < articulationListSize; ++j) - articulationListStart[j].articulation->solveInternalConstraints(params.dt, params.invDt, cache.Z, cache.deltaV, true, false, 0.f, 0.8f); - - for (PxU32 j = 0; j < articulationListSize; ++j) - articulationListStart[j].articulation->writebackInternalConstraints(false); - + solveNoContactsCase(bodyListSize, bodyListStart, motionVelocityArray, + articulationListSize, articulationListStart, cache.Z, cache.deltaV, + positionIterations, velocityIterations, params.dt, params.invDt); return; } @@ -254,12 +219,11 @@ void SolverCoreGeneralPF::solveV_Blocks(SolverIslandParams& params) const PxI32 frictionIter = 0; for (PxU32 iteration = positionIterations; iteration > 0; iteration--) //decreasing positive numbers == position iters { - SolveBlockParallel(constraintList, batchCount, normalIter * batchCount, batchCount, cache, contactIterator, iteration == 1 ? gVTableSolveConcludeBlockCoulomb : gVTableSolveBlockCoulomb, normalIter); for (PxU32 i = 0; i < articulationListSize; ++i) - articulationListStart[i].articulation->solveInternalConstraints(params.dt, params.invDt, cache.Z, cache.deltaV, false, false, 0.f, 0.8f); + articulationListStart[i].articulation->solveInternalConstraints(params.dt, params.invDt, cache.Z, cache.deltaV, false, isTGS, 0.f, biasCoefficient); ++normalIter; } @@ -275,13 +239,7 @@ void SolverCoreGeneralPF::solveV_Blocks(SolverIslandParams& params) const } } - for (PxU32 baIdx = 0; baIdx < bodyListSize; baIdx++) - { - const PxSolverBody& atom = bodyListStart[baIdx]; - Cm::SpatialVector& motionVel = motionVelocityArray[baIdx]; - motionVel.linear = atom.linearVelocity; - motionVel.angular = atom.angularState; - } + saveMotionVelocities(bodyListSize, bodyListStart, motionVelocityArray); for (PxU32 i = 0; i < articulationListSize; i++) ArticulationPImpl::saveVelocity(articulationListStart[i].articulation, cache.deltaV); @@ -296,7 +254,7 @@ void SolverCoreGeneralPF::solveV_Blocks(SolverIslandParams& params) const cache, contactIterator, gVTableSolveBlockCoulomb, normalIter); for (PxU32 i = 0; i < articulationListSize; ++i) - articulationListStart[i].articulation->solveInternalConstraints(params.dt, params.invDt, cache.Z, cache.deltaV, true, false, 0.f, 0.8f); + articulationListStart[i].articulation->solveInternalConstraints(params.dt, params.invDt, cache.Z, cache.deltaV, true, isTGS, 0.f, biasCoefficient); ++normalIter; if(frictionBatchCount > 0) @@ -325,7 +283,7 @@ void SolverCoreGeneralPF::solveV_Blocks(SolverIslandParams& params) const for (PxU32 i = 0; i < articulationListSize; ++i) { - articulationListStart[i].articulation->solveInternalConstraints(params.dt, params.invDt, cache.Z, cache.deltaV, true, false, 0.f, 0.8f); + articulationListStart[i].articulation->solveInternalConstraints(params.dt, params.invDt, cache.Z, cache.deltaV, true, isTGS, 0.f, biasCoefficient); articulationListStart[i].articulation->writebackInternalConstraints(false); } @@ -341,7 +299,7 @@ void SolverCoreGeneralPF::solveV_Blocks(SolverIslandParams& params) const if(cache.mThresholdStreamIndex > 0) { //Write back to global buffer - const PxI32 threshIndex = PxAtomicAdd(reinterpret_cast(&outThresholdPairs), PxI32(cache.mThresholdStreamIndex)) - PxI32(cache.mThresholdStreamIndex); + const PxI32 threshIndex = PxAtomicAdd(outThresholdPairs, PxI32(cache.mThresholdStreamIndex)) - PxI32(cache.mThresholdStreamIndex); for(PxU32 b = 0; b < cache.mThresholdStreamIndex; ++b) { thresholdStream[b + threshIndex] = cache.mThresholdStream[b]; @@ -353,6 +311,9 @@ void SolverCoreGeneralPF::solveV_Blocks(SolverIslandParams& params) const void SolverCoreGeneralPF::solveVParallelAndWriteBack(SolverIslandParams& params, Cm::SpatialVectorF* Z, Cm::SpatialVectorF* deltaV) const { + const PxF32 biasCoefficient = DY_ARTICULATION_PGS_BIAS_COEFFICIENT; + const bool isTGS = false; + SolverContext cache; cache.solverBodyArray = params.bodyDataList; @@ -468,7 +429,7 @@ void SolverCoreGeneralPF::solveVParallelAndWriteBack(SolverIslandParams& params, PxI32 nbSolved = 0; while (articSolveStart < endIdx) { - articulationListStart[articSolveStart - articIndexCounter].articulation->solveInternalConstraints(dt, invDt, cache.Z, cache.deltaV, false, false, 0.f, 0.8f); + articulationListStart[articSolveStart - articIndexCounter].articulation->solveInternalConstraints(dt, invDt, cache.Z, cache.deltaV, false, isTGS, 0.f, biasCoefficient); articSolveStart++; nbSolved++; } @@ -674,7 +635,7 @@ void SolverCoreGeneralPF::solveVParallelAndWriteBack(SolverIslandParams& params, PxI32 nbSolved = 0; while (articSolveStart < endIdx) { - articulationListStart[articSolveStart - articIndexCounter].articulation->solveInternalConstraints(dt, invDt, cache.Z, cache.deltaV, true, false, 0.f, 0.8f); + articulationListStart[articSolveStart - articIndexCounter].articulation->solveInternalConstraints(dt, invDt, cache.Z, cache.deltaV, true, isTGS, 0.f, biasCoefficient); articSolveStart++; nbSolved++; } @@ -787,7 +748,7 @@ void SolverCoreGeneralPF::solveVParallelAndWriteBack(SolverIslandParams& params, PxI32 nbSolved = 0; while (articSolveStart < endIdx) { - articulationListStart[articSolveStart - articIndexCounter].articulation->solveInternalConstraints(dt, invDt, cache.Z, cache.deltaV, false, false, 0.f, 0.8f); + articulationListStart[articSolveStart - articIndexCounter].articulation->solveInternalConstraints(dt, invDt, cache.Z, cache.deltaV, false, isTGS, 0.f, biasCoefficient); articulationListStart[articSolveStart - articIndexCounter].articulation->writebackInternalConstraints(false); articSolveStart++; nbSolved++; @@ -829,28 +790,6 @@ void SolverCoreGeneralPF::solveVParallelAndWriteBack(SolverIslandParams& params, } } -void SolverCoreGeneralPF::writeBackV -(const PxSolverConstraintDesc* PX_RESTRICT constraintList, const PxU32 /*constraintListSize*/, PxConstraintBatchHeader* batchHeaders, const PxU32 numBatches, - ThresholdStreamElement* PX_RESTRICT thresholdStream, const PxU32 thresholdStreamLength, PxU32& outThresholdPairs, - PxSolverBodyData* atomListData, WriteBackBlockMethod writeBackTable[]) const -{ - SolverContext cache; - cache.solverBodyArray = atomListData; - cache.mThresholdStream = thresholdStream; - cache.mThresholdStreamLength = thresholdStreamLength; - cache.mThresholdStreamIndex = 0; - - PxI32 outThreshIndex = 0; - for(PxU32 j = 0; j < numBatches; ++j) - { - PxU8 type = *constraintList[batchHeaders[j].startIndex].constraint; - writeBackTable[type](constraintList + batchHeaders[j].startIndex, - batchHeaders[j].stride, cache); - } - - outThresholdPairs = PxU32(outThreshIndex); -} - } } diff --git a/physx/source/lowleveldynamics/src/DySolverControlPF.h b/physx/source/lowleveldynamics/src/DySolverControlPF.h index d3022671f..1f2cfac05 100644 --- a/physx/source/lowleveldynamics/src/DySolverControlPF.h +++ b/physx/source/lowleveldynamics/src/DySolverControlPF.h @@ -34,36 +34,25 @@ namespace physx { - namespace Dy { +// PT: TODO: these "solver core" classes are mostly stateless, at this point they could just be function pointers like the solve methods. class SolverCoreGeneralPF : public SolverCore { public: - static SolverCoreGeneralPF* create(); - - // Implements SolverCore - virtual void destroyV(); + SolverCoreGeneralPF(){} + // SolverCore virtual void solveVParallelAndWriteBack - (SolverIslandParams& params, Cm::SpatialVectorF* Z, Cm::SpatialVectorF* deltaV) const; + (SolverIslandParams& params, Cm::SpatialVectorF* Z, Cm::SpatialVectorF* deltaV) const PX_OVERRIDE PX_FINAL; virtual void solveV_Blocks - (SolverIslandParams& params) const; - - virtual void writeBackV - (const PxSolverConstraintDesc* PX_RESTRICT constraintList, const PxU32 constraintListSize, PxConstraintBatchHeader* contactConstraintBatches, const PxU32 numBatches, - ThresholdStreamElement* PX_RESTRICT thresholdStream, const PxU32 thresholdStreamLength, PxU32& outThresholdPairs, - PxSolverBodyData* atomListData, WriteBackBlockMethod writeBackTable[]) const; - -private: - - //~Implements SolverCore + (SolverIslandParams& params) const PX_OVERRIDE PX_FINAL; + //~SolverCore }; } - } #endif diff --git a/physx/source/lowleveldynamics/src/DySolverCore.h b/physx/source/lowleveldynamics/src/DySolverCore.h index 6fc740d02..6f4b0c530 100644 --- a/physx/source/lowleveldynamics/src/DySolverCore.h +++ b/physx/source/lowleveldynamics/src/DySolverCore.h @@ -32,6 +32,9 @@ #include "PxvConfig.h" #include "foundation/PxArray.h" #include "foundation/PxThread.h" +#include "foundation/PxUserAllocated.h" +// PT: it is not wrong to include DyPGS.h here because the SolverCore class is actually only used by PGS. +// (for patch / point friction). TGS doesn't use the same architecture / class hierarchy. #include "DyPGS.h" namespace physx @@ -195,11 +198,11 @@ struct SolverIslandParams /*! Interface to constraint solver cores */ -class SolverCore +class SolverCore : public PxUserAllocated { public: - virtual void destroyV() = 0; virtual ~SolverCore() {} + /* solves dual problem exactly by GS-iterating until convergence stops only uses regular velocity vector for storing results, and backs up initial state, which is restored. @@ -212,11 +215,6 @@ class SolverCore virtual void solveV_Blocks (SolverIslandParams& params) const = 0; - - virtual void writeBackV - (const PxSolverConstraintDesc* PX_RESTRICT constraintList, const PxU32 constraintListSize, PxConstraintBatchHeader* contactConstraintBatches, const PxU32 numConstraintBatches, - ThresholdStreamElement* PX_RESTRICT thresholdStream, const PxU32 thresholdStreamLength, PxU32& outThresholdPairs, - PxSolverBodyData* atomListData, WriteBackBlockMethod writeBackTable[]) const = 0; }; } diff --git a/physx/source/lowleveldynamics/src/DyTGSContactPrep.cpp b/physx/source/lowleveldynamics/src/DyTGSContactPrep.cpp index 53f44186f..d3c19b843 100644 --- a/physx/source/lowleveldynamics/src/DyTGSContactPrep.cpp +++ b/physx/source/lowleveldynamics/src/DyTGSContactPrep.cpp @@ -32,6 +32,7 @@ #include "DyThreadContext.h" #include "PxcNpContactPrepShared.h" #include "DyFeatherstoneArticulation.h" +#include "DyArticulationCpuGpu.h" using namespace physx; using namespace Gu; diff --git a/physx/source/lowleveldynamics/src/DyTGSContactPrepBlock.cpp b/physx/source/lowleveldynamics/src/DyTGSContactPrepBlock.cpp index bd06c59b1..9eeb37336 100644 --- a/physx/source/lowleveldynamics/src/DyTGSContactPrepBlock.cpp +++ b/physx/source/lowleveldynamics/src/DyTGSContactPrepBlock.cpp @@ -219,6 +219,7 @@ static void setupFinalizeSolverConstraints4Step(PxTGSSolverContactDesc* PX_RESTR const Vec4V zero = V4Zero(); const BoolV bFalse = BFFFF(); + const BoolV bTrue = BTTTT(); const FloatV fZero = FZero(); PxU8 flags[4] = { PxU8(descs[0].hasForceThresholds ? SolverContactHeader::eHAS_FORCE_THRESHOLDS : 0), @@ -758,7 +759,7 @@ static void setupFinalizeSolverConstraints4Step(PxTGSSolverContactDesc* PX_RESTR newFinished |= PxU32(!iter0.hasNextContact()); } else - bFinished = BSetX(bFinished, bFalse); + bFinished = BSetX(bFinished, bTrue); if (!(finished & 0x2)) { @@ -766,7 +767,7 @@ static void setupFinalizeSolverConstraints4Step(PxTGSSolverContactDesc* PX_RESTR newFinished |= (PxU32(!iter1.hasNextContact()) << 1); } else - bFinished = BSetY(bFinished, bFalse); + bFinished = BSetY(bFinished, bTrue); if (!(finished & 0x4)) { @@ -774,7 +775,7 @@ static void setupFinalizeSolverConstraints4Step(PxTGSSolverContactDesc* PX_RESTR newFinished |= (PxU32(!iter2.hasNextContact()) << 2); } else - bFinished = BSetZ(bFinished, bFalse); + bFinished = BSetZ(bFinished, bTrue); if (!(finished & 0x8)) { @@ -782,7 +783,7 @@ static void setupFinalizeSolverConstraints4Step(PxTGSSolverContactDesc* PX_RESTR newFinished |= (PxU32(!iter3.hasNextContact()) << 3); } else - bFinished = BSetW(bFinished, bFalse); + bFinished = BSetW(bFinished, bTrue); } ptr = p; if (hasMaxImpulse) diff --git a/physx/source/lowleveldynamics/src/DyTGSDynamics.cpp b/physx/source/lowleveldynamics/src/DyTGSDynamics.cpp index 263b37795..8b100e1e0 100644 --- a/physx/source/lowleveldynamics/src/DyTGSDynamics.cpp +++ b/physx/source/lowleveldynamics/src/DyTGSDynamics.cpp @@ -805,8 +805,8 @@ void DynamicsTGSContext::updatePostKinematic(IG::SimpleIslandManager& simpleIsla { const IG::Island& island = islandSim.getIsland(islandIds[currentIsland]); - nbBodies += island.mSize[IG::Node::eRIGID_BODY_TYPE]; - nbArticulations += island.mSize[IG::Node::eARTICULATION_TYPE]; + nbBodies += island.mNodeCount[IG::Node::eRIGID_BODY_TYPE]; + nbArticulations += island.mNodeCount[IG::Node::eARTICULATION_TYPE]; nbConstraints += island.mEdgeCount[IG::Edge::eCONSTRAINT]; nbContactManagers += island.mEdgeCount[IG::Edge::eCONTACT_MANAGER]; constraintCount = nbConstraints + nbContactManagers; @@ -1754,7 +1754,7 @@ PxU32 DynamicsTGSContext::setupArticulationInternalConstraints(IslandContextStep PxU32 acCount; PxU32 descCount = ArticulationPImpl::setupSolverInternalConstraintsTGS(desc, - islandContext.mStepDt, invStepDt, dt, islandContext.mBiasCoefficient, acCount, threadContext->mZVector.begin()); + islandContext.mStepDt, invStepDt, dt, acCount, threadContext->mZVector.begin()); desc.numInternalConstraints = PxTo8(descCount); @@ -2165,12 +2165,6 @@ class SetupSolverConstraintsTask : public Cm::Task } }; -static bool isArticulationConstraint(PxSolverConstraintDesc& desc) -{ - return desc.linkIndexA != PxSolverConstraintDesc::RIGID_BODY || - desc.linkIndexB != PxSolverConstraintDesc::RIGID_BODY; -} - class PartitionTask : public Cm::Task { IslandContextStep& mIslandContext; diff --git a/physx/source/physx/src/NpArticulationLink.cpp b/physx/source/physx/src/NpArticulationLink.cpp index 955f10405..27ef2e831 100644 --- a/physx/source/physx/src/NpArticulationLink.cpp +++ b/physx/source/physx/src/NpArticulationLink.cpp @@ -361,6 +361,12 @@ void NpArticulationLink::setGlobalPoseInternal(const PxTransform& pose, bool aut static_cast(mRoot)->setGlobalPose(); } +void NpArticulationLink::setInboundJointDof(const PxU32 index) +{ + mInboundJointDof = index; + OMNI_PVD_SET(OMNI_PVD_CONTEXT_HANDLE, PxArticulationLink, inboundJointDOF, static_cast(*this), mInboundJointDof); +} + void NpArticulationLink::setFixedBaseLink(bool value) { NP_WRITE_CHECK(getNpScene()); diff --git a/physx/source/physx/src/NpArticulationLink.h b/physx/source/physx/src/NpArticulationLink.h index 069aeb668..d734c6cca 100644 --- a/physx/source/physx/src/NpArticulationLink.h +++ b/physx/source/physx/src/NpArticulationLink.h @@ -121,7 +121,7 @@ class NpArticulationLink : public NpArticulationLinkT void setGlobalPoseInternal(const PxTransform& pose, bool autowake); void setLLIndex(const PxU32 index) { mLLIndex = index; } - void setInboundJointDof(const PxU32 index) { mInboundJointDof = index; } + void setInboundJointDof(const PxU32 index); static PX_FORCE_INLINE size_t getCoreOffset() { return PX_OFFSET_OF_RT(NpArticulationLink, mCore); } private: PX_INLINE void addToChildList(NpArticulationLink& link) { mChildLinks.pushBack(&link); } diff --git a/physx/source/physx/src/NpFactory.cpp b/physx/source/physx/src/NpFactory.cpp index 979bda393..3bbeaa32f 100644 --- a/physx/source/physx/src/NpFactory.cpp +++ b/physx/source/physx/src/NpFactory.cpp @@ -244,7 +244,6 @@ NpArticulationLink* NpFactory::createNpArticulationLink(NpArticulationReducedCoo PxMutex::ScopedLock lock(mArticulationLinkPoolLock); npArticulationLink = mArticulationLinkPool.construct(pose, root, parent); } - OMNI_PVD_NOTIFY_ADD(npArticulationLink); return npArticulationLink; } @@ -267,7 +266,7 @@ PxArticulationLink* NpFactory::createArticulationLink(NpArticulationReducedCoord PxGetFoundation().error(PxErrorCode::eINTERNAL_ERROR, PX_FL, "Articulation link initialization failed: returned NULL."); return NULL; } - + OMNI_PVD_NOTIFY_ADD(npArticulationLink); PxArticulationJointReducedCoordinate* npArticulationJoint = 0; if (parent) { @@ -284,8 +283,7 @@ PxArticulationLink* NpFactory::createArticulationLink(NpArticulationReducedCoord } npArticulationLink->setInboundJoint(*npArticulationJoint); - } - + } return npArticulationLink; } diff --git a/physx/source/physx/src/NpParticleSystem.cpp b/physx/source/physx/src/NpParticleSystem.cpp index ee1ba047b..8293db1f4 100644 --- a/physx/source/physx/src/NpParticleSystem.cpp +++ b/physx/source/physx/src/NpParticleSystem.cpp @@ -670,6 +670,11 @@ namespace physx const PxU32 groupID = mNextPhaseGroupID++; core.mPhaseGroupToMaterialHandle.pushBack(materialHandle); + PxU16* foundHandle = core.mUniqueMaterialHandles.find(materialHandle); + if(foundHandle == core.mUniqueMaterialHandles.end()) + { + core.mUniqueMaterialHandles.pushBack(materialHandle); + } if (mCore.getSim()) mCore.getSim()->getLowLevelParticleSystem()->mFlag |= Dy::ParticleSystemFlag::eUPDATE_PHASE; @@ -701,6 +706,12 @@ namespace physx NpDestroyParticleSystem(this); } + PxU32 NpPBDParticleSystem::getParticleMaterials(PxParticleMaterial** userBuffer, PxU32 bufferSize, + PxU32 startIndex) const + { + return getParticleMaterialsInternal(userBuffer, bufferSize, startIndex); + } + void NpPBDParticleSystem::addParticleBuffer(PxParticleBuffer* clothBuffer) { NP_WRITE_CHECK(getNpScene()); @@ -781,6 +792,11 @@ namespace physx const PxU32 groupID = mNextPhaseGroupID++; core.mPhaseGroupToMaterialHandle.pushBack(materialHandle); + PxU16* foundHandle = core.mUniqueMaterialHandles.find(materialHandle); + if(foundHandle == core.mUniqueMaterialHandles.end()) + { + core.mUniqueMaterialHandles.pushBack(materialHandle); + } if (mCore.getSim()) mCore.getSim()->getLowLevelParticleSystem()->mFlag |= Dy::ParticleSystemFlag::eUPDATE_PHASE; @@ -849,6 +865,12 @@ namespace physx PX_CATCH_UNDEFINED_ENABLE_DEBUG_VISUALIZATION #endif + PxU32 NpFLIPParticleSystem::getParticleMaterials(PxParticleMaterial** userBuffer, PxU32 bufferSize, + PxU32 startIndex) const + { + return getParticleMaterialsInternal(userBuffer, bufferSize, startIndex); + } + void NpFLIPParticleSystem::addParticleBuffer(PxParticleBuffer* particleBuffer) { NP_WRITE_CHECK(getNpScene()); @@ -901,6 +923,11 @@ namespace physx const PxU32 groupID = mNextPhaseGroupID++; core.mPhaseGroupToMaterialHandle.pushBack(materialHandle); + PxU16* foundHandle = core.mUniqueMaterialHandles.find(materialHandle); + if(foundHandle == core.mUniqueMaterialHandles.end()) + { + core.mUniqueMaterialHandles.pushBack(materialHandle); + } if (mCore.getSim()) mCore.getSim()->getLowLevelParticleSystem()->mFlag |= Dy::ParticleSystemFlag::eUPDATE_PHASE; @@ -985,6 +1012,12 @@ namespace physx PX_CATCH_UNDEFINED_ENABLE_DEBUG_VISUALIZATION #endif + PxU32 NpMPMParticleSystem::getParticleMaterials(PxParticleMaterial** userBuffer, PxU32 bufferSize, + PxU32 startIndex) const + { + return getParticleMaterialsInternal(userBuffer, bufferSize, startIndex); + } + void NpMPMParticleSystem::addParticleBuffer(PxParticleBuffer* particleBuffer) { NP_WRITE_CHECK(getNpScene()); diff --git a/physx/source/physx/src/NpParticleSystem.h b/physx/source/physx/src/NpParticleSystem.h index 7d75c2e4b..377c541a5 100644 --- a/physx/source/physx/src/NpParticleSystem.h +++ b/physx/source/physx/src/NpParticleSystem.h @@ -54,6 +54,8 @@ #include "NpActor.h" #include "NpActorTemplate.h" #include "NpBase.h" +#include "NpMaterialManager.h" +#include "NpPhysics.h" #include "ScParticleSystemSim.h" @@ -213,13 +215,15 @@ namespace physx void setSolverType(const PxParticleSolverType::Enum solverType) { scSetSolverType(solverType); } virtual PxParticleSolverType::Enum getSolverType() const { return mCore.getSolverType(); } - - virtual PxU32 getNbParticleMaterials() const + virtual PxU32 getNbParticleMaterials() const { const Sc::ParticleSystemShapeCore& shapeCore = mCore.getShapeCore(); - return shapeCore.getNbMaterialIndices(); + const Dy::ParticleSystemCore& core = shapeCore.getLLCore(); + return core.mUniqueMaterialHandles.size(); } + virtual PxU32 getParticleMaterials(PxParticleMaterial** userBuffer, PxU32 bufferSize, PxU32 startIndex = 0) const = 0; + virtual void addParticleBuffer(PxParticleBuffer* userBuffer) = 0; virtual void removeParticleBuffer(PxParticleBuffer* userBuffer) = 0; @@ -390,6 +394,27 @@ namespace physx virtual void setGridSizeY(PxU32 gridSizeY) { scSetGridSizeY(gridSizeY); } virtual void setGridSizeZ(PxU32 gridSizeZ) { scSetGridSizeZ(gridSizeZ); } + template + PxU32 getParticleMaterialsInternal(PxParticleMaterial** userBuffer, PxU32 bufferSize, + PxU32 startIndex = 0) const + { + const Sc::ParticleSystemShapeCore& shapeCore = mCore.getShapeCore(); + const Dy::ParticleSystemCore& core = shapeCore.getLLCore(); + + NpMaterialManager& matManager = + NpMaterialAccessor::getMaterialManager(NpPhysics::getInstance()); + + PxU32 size = core.mUniqueMaterialHandles.size(); + const PxU32 remainder = PxU32(PxMax(PxI32(size - startIndex), 0)); + const PxU32 writeCount = PxMin(remainder, bufferSize); + for(PxU32 i = 0; i < writeCount; i++) + { + userBuffer[i] = matManager.getMaterial(core.mUniqueMaterialHandles[startIndex + i]); + } + return writeCount; + } + + protected: Sc::ParticleSystemCore mCore; PxCudaContextManager* mCudaContextManager; @@ -462,6 +487,8 @@ namespace physx //external API virtual PxActorType::Enum getType() const { return PxActorType::ePBD_PARTICLESYSTEM; } + virtual PxU32 getParticleMaterials(PxParticleMaterial** userBuffer, PxU32 bufferSize, PxU32 startIndex) const PX_OVERRIDE; + virtual void addParticleBuffer(PxParticleBuffer* particleBuffer); virtual void removeParticleBuffer(PxParticleBuffer* particleBuffer); @@ -505,8 +532,10 @@ namespace physx virtual void visualize(PxRenderOutput& out, NpScene& npScene) const; #else PX_CATCH_UNDEFINED_ENABLE_DEBUG_VISUALIZATION -#endif - +#endif + + virtual PxU32 getParticleMaterials(PxParticleMaterial** userBuffer, PxU32 bufferSize, PxU32 startIndex) const PX_OVERRIDE; + virtual void addParticleBuffer(PxParticleBuffer* particleBuffer); virtual void removeParticleBuffer(PxParticleBuffer* particleBuffer); @@ -558,6 +587,8 @@ namespace physx PX_CATCH_UNDEFINED_ENABLE_DEBUG_VISUALIZATION #endif + virtual PxU32 getParticleMaterials(PxParticleMaterial** userBuffer, PxU32 bufferSize, PxU32 startIndex) const PX_OVERRIDE; + virtual void addParticleBuffer(PxParticleBuffer* particleBuffer); virtual void removeParticleBuffer(PxParticleBuffer* particleBuffer); diff --git a/physx/source/physx/src/NpPhysics.cpp b/physx/source/physx/src/NpPhysics.cpp index 7cdc977b7..a6f09d222 100644 --- a/physx/source/physx/src/NpPhysics.cpp +++ b/physx/source/physx/src/NpPhysics.cpp @@ -158,7 +158,7 @@ NpPhysics::NpPhysics(const PxTolerancesScale& scale, const PxvOffsetTable& pxvOf NpOmniPvd* npOmniPvd = static_cast(mOmniPvd); NpOmniPvd::incRefCount(); npOmniPvd->mPhysXSampler = mOmniPvdSampler; // Dirty hack to do startSampling from PxOmniPvd - mOmniPvdSampler->setOmniPvdWriter(omniPvd->getWriter()); + mOmniPvdSampler->setOmniPvdInstance(npOmniPvd); } } #else diff --git a/physx/source/physx/src/NpScene.cpp b/physx/source/physx/src/NpScene.cpp index 5aad21bcd..0c422bb5e 100644 --- a/physx/source/physx/src/NpScene.cpp +++ b/physx/source/physx/src/NpScene.cpp @@ -1362,7 +1362,7 @@ bool NpScene::addArticulationInternal(PxArticulationReducedCoordinate& npa) //if all axis are locked, which means the user doesn't set the motion. In this case, we should change the joint type to be //fix to avoid crash in the solver #if PX_CHECKED - outputError(__LINE__, "PxScene::addArticulation(): The application need to set joint motion. defaulting joint type to eFix"); + outputError(__LINE__, "PxScene::addArticulation(): Encountered a joint with all motions fixed. Switching joint type to eFix"); #endif joint->scSetJointType(PxArticulationJointType::eFIX); child->setInboundJointDof(0); diff --git a/physx/source/physx/src/PvdMetaDataPvdBinding.cpp b/physx/source/physx/src/PvdMetaDataPvdBinding.cpp index bae896b68..b35d258f4 100644 --- a/physx/source/physx/src/PvdMetaDataPvdBinding.cpp +++ b/physx/source/physx/src/PvdMetaDataPvdBinding.cpp @@ -606,18 +606,13 @@ void PvdMetaDataBinding::sendAllProperties(PvdDataStream& inStream, const PxPhys inStream.setPropertyValue(&inPhysics, "Version.Minor", PxU32(PX_PHYSICS_VERSION_MINOR)); inStream.setPropertyValue(&inPhysics, "Version.Bugfix", PxU32(PX_PHYSICS_VERSION_BUGFIX)); -#if PX_CHECKED -#if defined(NDEBUG) - // This is a checked build - String buildType = "Checked"; -#elif defined(_DEBUG) - // This is a debug build +#if PX_DEBUG String buildType = "Debug"; -#endif +#elif PX_CHECKED + String buildType = "Checked"; #elif PX_PROFILE String buildType = "Profile"; -#elif defined(NDEBUG) - // This is a release build +#else String buildType = "Release"; #endif inStream.setPropertyValue(&inPhysics, "Version.Build", buildType); diff --git a/physx/source/physx/src/omnipvd/NpOmniPvd.cpp b/physx/source/physx/src/omnipvd/NpOmniPvd.cpp index 9680f1ba8..432be27c2 100644 --- a/physx/source/physx/src/omnipvd/NpOmniPvd.cpp +++ b/physx/source/physx/src/omnipvd/NpOmniPvd.cpp @@ -80,14 +80,6 @@ namespace physx PX_FREE(mInstance); mInstance = NULL; } - else - { - /* - mInstance->error(PxErrorCode::eINVALID_OPERATION, PX_FL, - "Foundation destruction failed due to pending module references. Close/release all depending " - "modules first."); - */ - } } // Called once by physx::PxOmniPvd* PxCreateOmniPvd(...) @@ -141,8 +133,14 @@ namespace physx } OmniPvdWriter* NpOmniPvd::getWriter() + { + return blockingWriterLoad(); + } + + OmniPvdWriter* NpOmniPvd::blockingWriterLoad() { #if PX_SUPPORT_OMNI_PVD + PxMutex::ScopedLock lock(mWriterLoadMutex); if (mWriter) { return mWriter; @@ -155,8 +153,26 @@ namespace physx return mWriter; #else return NULL; +#endif + } + + OmniPvdWriter* NpOmniPvd::acquireExclusiveWriterAccess() + { +#if PX_SUPPORT_OMNI_PVD + mMutex.lock(); + return blockingWriterLoad(); +#else + return NULL; #endif } + + void NpOmniPvd::releaseExclusiveWriterAccess() + { +#if PX_SUPPORT_OMNI_PVD + mMutex.unlock(); +#endif + } + OmniPvdFileWriteStream* NpOmniPvd::getFileWriteStream() { diff --git a/physx/source/physx/src/omnipvd/NpOmniPvd.h b/physx/source/physx/src/omnipvd/NpOmniPvd.h index d83405ccd..292121ad2 100644 --- a/physx/source/physx/src/omnipvd/NpOmniPvd.h +++ b/physx/source/physx/src/omnipvd/NpOmniPvd.h @@ -30,6 +30,7 @@ #define NP_OMNI_PVD_H #include "omnipvd/PxOmniPvd.h" +#include "foundation/PxMutex.h" class OmniPvdReader; class OmniPvdWriter; @@ -51,7 +52,14 @@ class NpOmniPvd : public PxOmniPvd void release(); bool initOmniPvd(); + OmniPvdWriter* getWriter(); + + OmniPvdWriter* blockingWriterLoad(); + + OmniPvdWriter* acquireExclusiveWriterAccess(); + void releaseExclusiveWriterAccess(); + OmniPvdFileWriteStream* getFileWriteStream(); bool startSampling(); @@ -61,6 +69,8 @@ class NpOmniPvd : public PxOmniPvd OmniPvdPxSampler* mPhysXSampler; static PxU32 mRefCount; static NpOmniPvd* mInstance; + PxMutex mMutex; + PxMutex mWriterLoadMutex; }; } diff --git a/physx/source/physx/src/omnipvd/NpOmniPvdSetData.h b/physx/source/physx/src/omnipvd/NpOmniPvdSetData.h index a2f61d605..9a43a6fe2 100644 --- a/physx/source/physx/src/omnipvd/NpOmniPvdSetData.h +++ b/physx/source/physx/src/omnipvd/NpOmniPvdSetData.h @@ -43,6 +43,7 @@ #include "NpOmniPvdRegistrationData.h" #include "OmniPvdPxSampler.h" +#include "NpOmniPvd.h" #define OMNI_PVD_ACTIVE (::OmniPvdPxSampler::getInstance() != NULL) @@ -53,7 +54,8 @@ // #undef OMNI_PVD_GET_WRITER #define OMNI_PVD_GET_WRITER(writer) \ -OmniPvdWriter* writer = NpOmniPvdGetWriter(); +physx::PxOmniPvd::ScopedExclusiveWriter writeLock(NpOmniPvdGetInstance()); \ +OmniPvdWriter* writer = writeLock.getWriter(); #undef OMNI_PVD_GET_REGISTRATION_DATA diff --git a/physx/source/physx/src/omnipvd/OmniPvdPxSampler.cpp b/physx/source/physx/src/omnipvd/OmniPvdPxSampler.cpp index 54969f9d7..181cfd370 100644 --- a/physx/source/physx/src/omnipvd/OmniPvdPxSampler.cpp +++ b/physx/source/physx/src/omnipvd/OmniPvdPxSampler.cpp @@ -34,6 +34,7 @@ #include "ScIterators.h" +#include "omnipvd/NpOmniPvd.h" #include "OmniPvdPxSampler.h" #include "OmniPvdWriteStream.h" #include "NpOmniPvdSetData.h" @@ -55,9 +56,9 @@ class OmniPvdStreamContainer ~OmniPvdStreamContainer(); bool initOmniPvd(); void registerClasses(); - void setOmniPvdWriter(OmniPvdWriter* omniPvdWriter); + void setOmniPvdInstance(NpOmniPvd* omniPvdInstance); - OmniPvdWriter* mWriter; + NpOmniPvd* mOmniPvdInstance; physx::PxMutex mMutex; OmniPvdPxCoreRegistrationData mRegistrationData; bool mClassesRegistered; @@ -88,7 +89,7 @@ class OmniPvdPxScene : public physx::PxUserAllocated void sampleScene() { mFrameId++; - samplerInternals->mPvdStream.mWriter->startFrame(OMNI_PVD_CONTEXT_HANDLE, mFrameId); + samplerInternals->mPvdStream.mOmniPvdInstance->getWriter()->startFrame(OMNI_PVD_CONTEXT_HANDLE, mFrameId); } physx::PxU64 mFrameId; @@ -97,17 +98,17 @@ class OmniPvdPxScene : public physx::PxUserAllocated OmniPvdStreamContainer::OmniPvdStreamContainer() { physx::PxMutex::ScopedLock myLock(mMutex); - mWriter = NULL; mClassesRegistered = false; + mOmniPvdInstance = NULL; } OmniPvdStreamContainer::~OmniPvdStreamContainer() { } -void OmniPvdStreamContainer::setOmniPvdWriter(OmniPvdWriter* omniPvdWriter) +void OmniPvdStreamContainer::setOmniPvdInstance(NpOmniPvd* omniPvdInstance) { - mWriter = omniPvdWriter; + mOmniPvdInstance = omniPvdInstance; } bool OmniPvdStreamContainer::initOmniPvd() @@ -130,11 +131,13 @@ bool OmniPvdStreamContainer::initOmniPvd() void OmniPvdStreamContainer::registerClasses() { if (mClassesRegistered) return; - if (mWriter) + OmniPvdWriter* writer = mOmniPvdInstance->acquireExclusiveWriterAccess(); + if (writer) { - mRegistrationData.registerData(*mWriter); + mRegistrationData.registerData(*writer); mClassesRegistered = true; } + mOmniPvdInstance->releaseExclusiveWriterAccess(); } @@ -387,11 +390,38 @@ void streamActorAttributes(const physx::PxActor& actor) void streamRigidActorAttributes(const PxRigidActor &ra) { OMNI_PVD_WRITE_SCOPE_BEGIN(pvdWriter, pvdRegData) - - PxTransform t = ra.getGlobalPose(); - OMNI_PVD_SET_EXPLICIT(pvdWriter, pvdRegData, OMNI_PVD_CONTEXT_HANDLE, PxRigidActor, translation, ra, t.p); - OMNI_PVD_SET_EXPLICIT(pvdWriter, pvdRegData, OMNI_PVD_CONTEXT_HANDLE, PxRigidActor, rotation, ra, t.q); + if (ra.is()) + { + const PxArticulationLink& link = static_cast(ra); + PxTransform TArtLinkLocal; + PxArticulationJointReducedCoordinate* joint = link.getInboundJoint(); + if (joint) + { + PxArticulationLink& parentLink = joint->getParentArticulationLink(); + // TGlobal = TFatherGlobal * TLocal + // Inv(TFatherGlobal)* TGlobal = Inv(TFatherGlobal)*TFatherGlobal * TLocal + // Inv(TFatherGlobal)* TGlobal = TLocal + // TLocal = Inv(TFatherGlobal) * TGlobal + //physx::PxTransform TParentGlobal = pxArticulationParentLink->getGlobalPose(); + PxTransform TParentGlobalInv = parentLink.getGlobalPose().getInverse(); + PxTransform TArtLinkGlobal = link.getGlobalPose(); + // PT:: tag: scalar transform*transform + TArtLinkLocal = TParentGlobalInv * TArtLinkGlobal; + } + else + { + TArtLinkLocal = link.getGlobalPose(); + } + OMNI_PVD_SET_EXPLICIT(pvdWriter, pvdRegData, OMNI_PVD_CONTEXT_HANDLE, PxRigidActor, translation, ra, TArtLinkLocal.p) + OMNI_PVD_SET_EXPLICIT(pvdWriter, pvdRegData, OMNI_PVD_CONTEXT_HANDLE, PxRigidActor, rotation, ra, TArtLinkLocal.q) + } + else + { + PxTransform t = ra.getGlobalPose(); + OMNI_PVD_SET_EXPLICIT(pvdWriter, pvdRegData, OMNI_PVD_CONTEXT_HANDLE, PxRigidActor, translation, ra, t.p); + OMNI_PVD_SET_EXPLICIT(pvdWriter, pvdRegData, OMNI_PVD_CONTEXT_HANDLE, PxRigidActor, rotation, ra, t.q); + } // Stream shapes too const int nbrShapes = ra.getNbShapes(); @@ -486,8 +516,6 @@ void streamRigidStatic(const physx::PxRigidStatic& rs) void streamArticulationJoint(const physx::PxArticulationJointReducedCoordinate& jointRef) { - OMNI_PVD_WRITE_SCOPE_BEGIN(pvdWriter, pvdRegData) - const PxU32 degreesOfFreedom = PxArticulationAxis::eCOUNT; // make sure size matches the size used in the PVD description @@ -538,6 +566,8 @@ void streamArticulationJoint(const physx::PxArticulationJointReducedCoordinate& for (PxU32 ax = 0; ax < degreesOfFreedom; ++ax) drivevelocitys[ax] = jointRef.getDriveVelocity(static_cast(ax)); + OMNI_PVD_WRITE_SCOPE_BEGIN(pvdWriter, pvdRegData) + OMNI_PVD_CREATE_EXPLICIT(pvdWriter, pvdRegData, OMNI_PVD_CONTEXT_HANDLE, PxArticulationJointReducedCoordinate, jointRef); OMNI_PVD_SET_EXPLICIT(pvdWriter, pvdRegData, OMNI_PVD_CONTEXT_HANDLE, PxArticulationJointReducedCoordinate, type, jointRef, jointType); OMNI_PVD_SET_EXPLICIT(pvdWriter, pvdRegData, OMNI_PVD_CONTEXT_HANDLE, PxArticulationJointReducedCoordinate, parentLink, jointRef, parentPxLinkPtr); @@ -575,6 +605,10 @@ void streamArticulationLink(const physx::PxArticulationLink& al) OMNI_PVD_SET_EXPLICIT(pvdWriter, pvdRegData, OMNI_PVD_CONTEXT_HANDLE, PxArticulationLink, inboundJointDOF, al, al.getInboundJointDof()); OMNI_PVD_WRITE_SCOPE_END + + streamActorAttributes(al); + streamRigidActorAttributes(al); + streamRigidBodyAttributes(al); } void streamArticulation(const physx::PxArticulationReducedCoordinate& art) @@ -979,9 +1013,9 @@ bool OmniPvdPxSampler::isSampling() return samplerInternals->mIsSampling; } -void OmniPvdPxSampler::setOmniPvdWriter(OmniPvdWriter* omniPvdWriter) +void OmniPvdPxSampler::setOmniPvdInstance(physx::NpOmniPvd* omniPvdInstance) { - samplerInternals->mPvdStream.setOmniPvdWriter(omniPvdWriter); + samplerInternals->mPvdStream.setOmniPvdInstance(omniPvdInstance); } void createGeometry(const physx::PxGeometry & pxGeom) @@ -1439,11 +1473,11 @@ const OmniPvdPxCoreRegistrationData* NpOmniPvdGetPxCoreRegistrationData() } } -OmniPvdWriter* NpOmniPvdGetWriter() +physx::NpOmniPvd* NpOmniPvdGetInstance() { if (samplerInternals) { - return samplerInternals->mPvdStream.mWriter; + return samplerInternals->mPvdStream.mOmniPvdInstance; } else { diff --git a/physx/source/physx/src/omnipvd/OmniPvdPxSampler.h b/physx/source/physx/src/omnipvd/OmniPvdPxSampler.h index ed9535339..5ba3b0f64 100644 --- a/physx/source/physx/src/omnipvd/OmniPvdPxSampler.h +++ b/physx/source/physx/src/omnipvd/OmniPvdPxSampler.h @@ -54,6 +54,8 @@ namespace physx class PxPBDMaterial; struct OmniPvdPxCoreRegistrationData; + + class NpOmniPvd; } void streamActorName(const physx::PxActor & a, const char* name); @@ -78,16 +80,15 @@ enum OmniPvdSharedMeshEnum { class OmniPvdWriter; class OmniPvdPxScene; + class OmniPvdPxSampler : public physx::PxUserAllocated { public: OmniPvdPxSampler(); ~OmniPvdPxSampler(); - //enables sampling: void startSampling(); bool isSampling(); - //sets destination: - void setOmniPvdWriter(OmniPvdWriter* omniPvdWriter); + void setOmniPvdInstance(physx::NpOmniPvd* omniPvdIntance); // writes all contacts to the stream void streamSceneContacts(physx::NpScene& scene); @@ -110,7 +111,7 @@ namespace physx { const OmniPvdPxCoreRegistrationData* NpOmniPvdGetPxCoreRegistrationData(); -OmniPvdWriter* NpOmniPvdGetWriter(); +NpOmniPvd* NpOmniPvdGetInstance(); } diff --git a/physx/source/physxcharacterkinematic/src/CctCharacterControllerManager.cpp b/physx/source/physxcharacterkinematic/src/CctCharacterControllerManager.cpp index 6e0638cc1..51536dc05 100644 --- a/physx/source/physxcharacterkinematic/src/CctCharacterControllerManager.cpp +++ b/physx/source/physxcharacterkinematic/src/CctCharacterControllerManager.cpp @@ -67,8 +67,22 @@ CharacterControllerManager::~CharacterControllerManager() PX_DELETE(mRenderBuffer); } +static PxArray* gControllerManagers = NULL; + void CharacterControllerManager::release() { + if(gControllerManagers) + { + const bool found = gControllerManagers->findAndReplaceWithLast(this); + PX_ASSERT(found); + PX_UNUSED(found); + + if(!gControllerManagers->size()) + { + PX_DELETE(gControllerManagers); + } + } + // PT: TODO: use non virtual calls & move to dtor while(getNbControllers()!= 0) releaseController(*getController(0)); @@ -84,6 +98,29 @@ void CharacterControllerManager::release() PxDecFoundationRefCount(); } +PX_C_EXPORT PxControllerManager* PX_CALL_CONV PxCreateControllerManager(PxScene& scene, bool lockingEnabled) +{ + if(gControllerManagers) + { + // PT: make sure we cannot create two controller managers for the same scene + const PxU32 nbManagers = gControllerManagers->size(); + for(PxU32 i=0;igetScene()) + return NULL; + } + } + + PxIncFoundationRefCount(); + CharacterControllerManager* controllerManager = PX_NEW(CharacterControllerManager)(scene, lockingEnabled); + + if(!gControllerManagers) + gControllerManagers = new PxArray; + gControllerManagers->pushBack(controllerManager); + + return controllerManager; +} + PxScene& CharacterControllerManager::getScene() const { return mScene; @@ -676,11 +713,3 @@ void CharacterControllerManager::computeInteractions(PxF32 elapsedTime, PxContro PX_FREE(boxes); } -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//Public factory methods - -PX_C_EXPORT PxControllerManager* PX_CALL_CONV PxCreateControllerManager(PxScene& scene, bool lockingEnabled) -{ - PxIncFoundationRefCount(); - return PX_NEW(CharacterControllerManager)(scene, lockingEnabled); -} diff --git a/physx/source/physxcharacterkinematic/src/CctCharacterControllerManager.h b/physx/source/physxcharacterkinematic/src/CctCharacterControllerManager.h index 6e469cca5..61c91c01b 100644 --- a/physx/source/physxcharacterkinematic/src/CctCharacterControllerManager.h +++ b/physx/source/physxcharacterkinematic/src/CctCharacterControllerManager.h @@ -67,7 +67,9 @@ namespace Cct { public: CharacterControllerManager(PxScene& scene, bool lockingEnabled = false); + private: virtual ~CharacterControllerManager(); + public: // PxControllerManager virtual void release() PX_OVERRIDE; diff --git a/physx/source/physxextensions/src/ExtCustomGeometryExt.cpp b/physx/source/physxextensions/src/ExtCustomGeometryExt.cpp index 20f319a29..9f6fee954 100644 --- a/physx/source/physxextensions/src/ExtCustomGeometryExt.cpp +++ b/physx/source/physxextensions/src/ExtCustomGeometryExt.cpp @@ -222,12 +222,9 @@ bool PxCustomGeometryExt::BaseConvexCallbacks::generateContacts(const PxGeometry if (PxGjkQueryExt::generateContacts(*this, geomSupport, pose0, pose1, contactDistance, toleranceLength, contactBuffer)) { PxGeometryHolder substituteGeom; PxTransform preTransform; - - PxBounds3 bounds; - PxGeometryQuery::computeGeomBounds(bounds, geom1, pose1, 0.0f, 1.01f); - - if (useSubstituteGeometry(substituteGeom, preTransform, contactBuffer.contacts[contactBuffer.count - 1], pose0, bounds.getCenter())) + if (useSubstituteGeometry(substituteGeom, preTransform, contactBuffer.contacts[contactBuffer.count - 1], pose0)) { + contactBuffer.count--; const PxGeometry* pGeom0 = &substituteGeom.any(); const PxGeometry* pGeom1 = &geom1; // PT:: tag: scalar transform*transform @@ -254,8 +251,9 @@ bool PxCustomGeometryExt::BaseConvexCallbacks::generateContacts(const PxGeometry contact.separation = dist; contactBuffer.contact(contact); PxGeometryHolder substituteGeom; PxTransform preTransform; - if (useSubstituteGeometry(substituteGeom, preTransform, contactBuffer.contacts[contactBuffer.count - 1], pose0, pose0.p)) + if (useSubstituteGeometry(substituteGeom, preTransform, contactBuffer.contacts[contactBuffer.count - 1], pose0)) { + contactBuffer.count--; const PxGeometry* pGeom0 = &substituteGeom.any(); const PxGeometry* pGeom1 = &geom1; // PT:: tag: scalar transform*transform @@ -269,9 +267,12 @@ bool PxCustomGeometryExt::BaseConvexCallbacks::generateContacts(const PxGeometry case PxGeometryType::eTRIANGLEMESH: case PxGeometryType::eHEIGHTFIELD: { + // As a triangle has no thickness, we need to choose some collision margin - the distance + // considered a touching contact. I set it as 1% of the custom shape minimum dimension. + PxReal meshMargin = getLocalBounds(geom0).getDimensions().minElement() * 0.01f; TrimeshContactFilter contactFilter; bool hasAdjacency = (geom1.getType() != PxGeometryType::eTRIANGLEMESH || (static_cast(geom1).triangleMesh->getTriangleMeshFlags() & PxTriangleMeshFlag::eADJACENCY_INFO)); - PxBoxGeometry boxGeom(getLocalBounds(geom0).getDimensions() * 0.5f + PxVec3(meshContactMargin)); + PxBoxGeometry boxGeom(getLocalBounds(geom0).getExtents() + PxVec3(contactDistance + meshMargin)); PxU32 triangles[MAX_TRIANGLES]; bool overflow = false; PxU32 triangleCount = (geom1.getType() == PxGeometryType::eTRIANGLEMESH) ? @@ -286,17 +287,18 @@ bool PxCustomGeometryExt::BaseConvexCallbacks::generateContacts(const PxGeometry PxMeshQuery::getTriangle(static_cast(geom1), pose1, triangles[i], tri, NULL, hasAdjacency ? adjacent : NULL); else PxMeshQuery::getTriangle(static_cast(geom1), pose1, triangles[i], tri, NULL, adjacent); - TriangleSupport triSupport(tri.verts[0], tri.verts[1], tri.verts[2], meshContactMargin); + TriangleSupport triSupport(tri.verts[0], tri.verts[1], tri.verts[2], meshMargin); if (PxGjkQueryExt::generateContacts(*this, triSupport, pose0, identityPose, contactDistance, toleranceLength, contactBuffer)) { contactBuffer.contacts[contactBuffer.count - 1].internalFaceIndex1 = triangles[i]; - PxGeometryHolder substituteGeom; PxTransform preTransform; PxVec3 pos1 = (tri.verts[0] + tri.verts[1] + tri.verts[2]) / 3.0f; - if (useSubstituteGeometry(substituteGeom, preTransform, contactBuffer.contacts[contactBuffer.count - 1], pose0, pos1)) + PxGeometryHolder substituteGeom; PxTransform preTransform; + if (useSubstituteGeometry(substituteGeom, preTransform, contactBuffer.contacts[contactBuffer.count - 1], pose0)) { + contactBuffer.count--; const PxGeometry& geom = substituteGeom.any(); // PT:: tag: scalar transform*transform PxTransform pose = pose0.transform(preTransform); - PxGeometryQuery::generateTriangleContacts(geom, pose, tri.verts, triangles[i], contactDistance, meshContactMargin, toleranceLength, contactBuffer); + PxGeometryQuery::generateTriangleContacts(geom, pose, tri.verts, triangles[i], contactDistance, meshMargin, toleranceLength, contactBuffer); } } if (hasAdjacency) @@ -319,12 +321,10 @@ bool PxCustomGeometryExt::BaseConvexCallbacks::generateContacts(const PxGeometry if (PxGjkQueryExt::generateContacts(*this, *custom1, pose0, pose1, contactDistance, toleranceLength, contactBuffer)) { PxGeometryHolder substituteGeom; PxTransform preTransform; - - PxBounds3 bounds; - PxGeometryQuery::computeGeomBounds(bounds, geom1, pose1, 0.0f, 1.01f); - - if (useSubstituteGeometry(substituteGeom, preTransform, contactBuffer.contacts[contactBuffer.count - 1], pose0, bounds.getCenter())) + if (useSubstituteGeometry(substituteGeom, preTransform, contactBuffer.contacts[contactBuffer.count - 1], pose0)) { + contactBuffer.count--; + PxU32 oldCount = contactBuffer.count; const PxGeometry* pGeom0 = &substituteGeom.any(); @@ -358,12 +358,18 @@ bool PxCustomGeometryExt::BaseConvexCallbacks::generateContacts(const PxGeometry return contactBuffer.count > 0; } -PxU32 PxCustomGeometryExt::BaseConvexCallbacks::raycast(const PxVec3& origin, const PxVec3& unitDir, const PxGeometry& /*geom*/, const PxTransform& pose, +PxU32 PxCustomGeometryExt::BaseConvexCallbacks::raycast(const PxVec3& origin, const PxVec3& unitDir, const PxGeometry& geom, const PxTransform& pose, PxReal maxDist, PxHitFlags /*hitFlags*/, PxU32 /*maxHits*/, PxGeomRaycastHit* rayHits, PxU32 /*stride*/, PxRaycastThreadContext*) const { + // When FLT_MAX is used as maxDist, it works bad with GJK algorithm. + // Here I compute the maximum needed distance (wiseDist) as the diagonal + // of the bounding box of both the geometry and the ray origin. + PxBounds3 bounds = PxBounds3::transformFast(pose, getLocalBounds(geom)); + bounds.include(origin); + PxReal wiseDist = PxMin(maxDist, bounds.getDimensions().magnitude()); PxReal t; PxVec3 n, p; - if (PxGjkQuery::raycast(*this, pose, origin, unitDir, maxDist, t, n, p)) + if (PxGjkQuery::raycast(*this, pose, origin, unitDir, wiseDist, t, n, p)) { PxGeomRaycastHit& hit = *rayHits; hit.distance = t; @@ -400,6 +406,8 @@ bool PxCustomGeometryExt::BaseConvexCallbacks::sweep(const PxVec3& unitDir, cons const PxGeometry& geom0, const PxTransform& pose0, const PxGeometry& geom1, const PxTransform& pose1, PxGeomSweepHit& sweepHit, PxHitFlags /*hitFlags*/, const PxReal inflation, PxSweepThreadContext*) const { + PxBounds3 bounds0 = PxBounds3::transformFast(pose0, getLocalBounds(geom0)); + switch (geom1.getType()) { case PxGeometryType::eSPHERE: @@ -407,10 +415,14 @@ bool PxCustomGeometryExt::BaseConvexCallbacks::sweep(const PxVec3& unitDir, cons case PxGeometryType::eBOX: case PxGeometryType::eCONVEXMESH: { + // See comment in BaseConvexCallbacks::raycast + PxBounds3 bounds; PxGeometryQuery::computeGeomBounds(bounds, geom1, pose1, 0, inflation); + bounds.include(bounds0); + PxReal wiseDist = PxMin(maxDist, bounds.getDimensions().magnitude()); PxGjkQueryExt::ConvexGeomSupport geomSupport(geom1, inflation); PxReal t; PxVec3 n, p; - if (PxGjkQuery::sweep(*this, geomSupport, pose0, pose1, unitDir, maxDist, t, n, p)) + if (PxGjkQuery::sweep(*this, geomSupport, pose0, pose1, unitDir, wiseDist, t, n, p)) { sweepHit.distance = t; sweepHit.position = p; @@ -424,15 +436,19 @@ bool PxCustomGeometryExt::BaseConvexCallbacks::sweep(const PxVec3& unitDir, cons case PxGeometryType::eTRIANGLEMESH: case PxGeometryType::eHEIGHTFIELD: { - PxReal radius = getLocalBounds(geom0).getDimensions().magnitude() * 0.5f; - PxCapsuleGeometry sweepGeom(radius + inflation, maxDist * 0.5f); - const PxVec3 defaultCapsuleAxis(1, 0, 0); - PxTransform sweepGeomPose(pose0.p - unitDir * maxDist * 0.5f, PxShortestRotation(defaultCapsuleAxis, unitDir)); + PxReal radius = getLocalBounds(geom0).getExtents().magnitude(); + PxGeometryHolder sweepGeom = PxSphereGeometry(radius + inflation); + PxTransform sweepGeomPose = pose0; + if (maxDist > FLT_EPSILON) + { + sweepGeom = PxCapsuleGeometry(radius + inflation, maxDist * 0.5f); + sweepGeomPose = PxTransform(pose0.p - unitDir * maxDist * 0.5f, PxShortestRotation(PxVec3(1, 0, 0), unitDir)); + } PxU32 triangles[MAX_TRIANGLES]; bool overflow = false; PxU32 triangleCount = (geom1.getType() == PxGeometryType::eTRIANGLEMESH) ? - PxMeshQuery::findOverlapTriangleMesh(sweepGeom, sweepGeomPose, static_cast(geom1), pose1, triangles, MAX_TRIANGLES, 0, overflow) : - PxMeshQuery::findOverlapHeightField(sweepGeom, sweepGeomPose, static_cast(geom1), pose1, triangles, MAX_TRIANGLES, 0, overflow); + PxMeshQuery::findOverlapTriangleMesh(sweepGeom.any(), sweepGeomPose, static_cast(geom1), pose1, triangles, MAX_TRIANGLES, 0, overflow) : + PxMeshQuery::findOverlapHeightField(sweepGeom.any(), sweepGeomPose, static_cast(geom1), pose1, triangles, MAX_TRIANGLES, 0, overflow); if(overflow) PxGetFoundation().error(PxErrorCode::eDEBUG_INFO, PX_FL, "PxCustomGeometryExt::BaseConvexCallbacks::sweep() Too many triangles.\n"); sweepHit.distance = PX_MAX_F32; @@ -445,9 +461,15 @@ bool PxCustomGeometryExt::BaseConvexCallbacks::sweep(const PxVec3& unitDir, cons else PxMeshQuery::getTriangle(static_cast(geom1), pose1, triangles[i], tri); TriangleSupport triSupport(tri.verts[0], tri.verts[1], tri.verts[2], inflation); + PxBounds3 bounds = bounds0; + for (PxU32 j = 0; j < 3; ++j) + bounds.include(tri.verts[j]); + bounds.fattenFast(inflation); + // See comment in BaseConvexCallbacks::raycast + PxReal wiseDist = PxMin(maxDist, bounds.getDimensions().magnitude()); PxReal t; PxVec3 n, p; - if (PxGjkQuery::sweep(*this, triSupport, pose0, identityPose, unitDir, maxDist, t, n, p)) + if (PxGjkQuery::sweep(*this, triSupport, pose0, identityPose, unitDir, wiseDist, t, n, p)) { if (sweepHit.distance > t) { @@ -470,8 +492,12 @@ bool PxCustomGeometryExt::BaseConvexCallbacks::sweep(const PxVec3& unitDir, cons return false; } -bool PxCustomGeometryExt::BaseConvexCallbacks::usePersistentContactManifold(const PxGeometry& /*geometry*/, PxReal& /*breakingThreshold*/) const +bool PxCustomGeometryExt::BaseConvexCallbacks::usePersistentContactManifold(const PxGeometry& /*geometry*/, PxReal& breakingThreshold) const { + // Even if we don't use persistent manifold, we still need to set proper breakingThreshold + // because the other geometry still can force the PCM usage. FLT_EPSILON ensures that + // the contacts will be discarded and recomputed every frame if actor moves. + breakingThreshold = FLT_EPSILON; return false; } @@ -643,19 +669,24 @@ void PxCustomGeometryExt::CylinderCallbacks::computeMassProperties(const PxGeome } } -bool PxCustomGeometryExt::CylinderCallbacks::useSubstituteGeometry(PxGeometryHolder& geom, PxTransform& preTransform, const PxContactPoint& p, const PxTransform& pose0, const PxVec3& pos1) const +bool PxCustomGeometryExt::CylinderCallbacks::useSubstituteGeometry(PxGeometryHolder& geom, PxTransform& preTransform, const PxContactPoint& p, const PxTransform& pose0) const { + // here I check if we contact with the cylender bases or the lateral surface + // where more than 1 contact point can be generated. PxVec3 locN = pose0.rotateInv(p.normal); float nAng = acosf(PxClamp(-locN[axis], -1.0f, 1.0f)); float epsAng = PxPi / 36.0f; // 5 degrees if (nAng < epsAng || nAng > PxPi - epsAng) { + // if we contact with the bases + // make the substitute geometry a box and rotate it so one of + // the corners matches the contact point PxVec3 halfSize; halfSize[axis] = height * 0.5f + margin; halfSize[(axis + 1) % 3] = halfSize[(axis + 2) % 3] = radius / sqrtf(2.0f); geom = PxBoxGeometry(halfSize); PxVec3 axisDir(PxZero); axisDir[axis] = 1.0f; - PxVec3 locP = pose0.transformInv(pos1); + PxVec3 locP = pose0.transformInv(p.point); float s1 = locP[(axis + 1) % 3], s2 = locP[(axis + 2) % 3]; float ang = ((s1 * s1) + (s2 * s2) > 1e-3f) ? atan2f(s2, s1) : 0; preTransform = PxTransform(PxQuat(ang + PxPi * 0.25f, axisDir)); @@ -663,6 +694,9 @@ bool PxCustomGeometryExt::CylinderCallbacks::useSubstituteGeometry(PxGeometryHol } else if (nAng > PxPiDivTwo - epsAng && nAng < PxPiDivTwo + epsAng) { + // if it's the lateral surface + // make the substitute geometry a capsule and rotate it so it aligns + // with the cylinder surface geom = PxCapsuleGeometry(radius + margin, height * 0.5f); switch (axis) { @@ -868,20 +902,25 @@ void PxCustomGeometryExt::ConeCallbacks::computeMassProperties(const PxGeometry& } } -bool PxCustomGeometryExt::ConeCallbacks::useSubstituteGeometry(PxGeometryHolder& geom, PxTransform& preTransform, const PxContactPoint& p, const PxTransform& pose0, const PxVec3& pos1) const +bool PxCustomGeometryExt::ConeCallbacks::useSubstituteGeometry(PxGeometryHolder& geom, PxTransform& preTransform, const PxContactPoint& p, const PxTransform& pose0) const { + // here I check if we contact with the cone base or the lateral surface + // where more than 1 contact point can be generated. PxVec3 locN = pose0.rotateInv(p.normal); float nAng = acosf(PxClamp(-locN[axis], -1.0f, 1.0f)); float epsAng = PxPi / 36.0f; // 5 degrees float coneAng = atan2f(radius, height); if (nAng > PxPi - epsAng) { + // if we contact with the base + // make the substitute geometry a box and rotate it so one of + // the corners matches the contact point PxVec3 halfSize; halfSize[axis] = height * 0.5f + margin; halfSize[(axis + 1) % 3] = halfSize[(axis + 2) % 3] = radius / sqrtf(2.0f); geom = PxBoxGeometry(halfSize); PxVec3 axisDir(PxZero); axisDir[axis] = 1.0f; - PxVec3 locP = pose0.transformInv(pos1); + PxVec3 locP = pose0.transformInv(p.point); float s1 = locP[(axis + 1) % 3], s2 = locP[(axis + 2) % 3]; float ang = ((s1 * s1) + (s2 * s2) > 1e-3f) ? atan2f(s2, s1) : 0; preTransform = PxTransform(PxQuat(ang + PxPi * 0.25f, axisDir)); @@ -889,6 +928,9 @@ bool PxCustomGeometryExt::ConeCallbacks::useSubstituteGeometry(PxGeometryHolder& } else if (nAng > PxPiDivTwo - coneAng - epsAng && nAng < PxPiDivTwo - coneAng + epsAng) { + // if it's the lateral surface + // make the substitute geometry a capsule and rotate it so it aligns + // with the cone surface geom = PxCapsuleGeometry(radius * 0.25f + margin, sqrtf(height * height + radius * radius) * 0.5f); switch (axis) { diff --git a/physx/source/physxextensions/src/ExtExtensions.cpp b/physx/source/physxextensions/src/ExtExtensions.cpp index 035edc625..e6a2589c7 100644 --- a/physx/source/physxextensions/src/ExtExtensions.cpp +++ b/physx/source/physxextensions/src/ExtExtensions.cpp @@ -120,7 +120,7 @@ bool PxInitExtensions(PxPhysics& physics, PxPvd* pvd) { if (OmniPvdPxExtensionsSampler::createInstance()) { - OmniPvdPxExtensionsSampler::getInstance()->setOmniPvdWriter(physics.getOmniPvd()->getWriter()); + OmniPvdPxExtensionsSampler::getInstance()->setOmniPvdInstance(physics.getOmniPvd()); OmniPvdPxExtensionsSampler::getInstance()->registerClasses(); } } diff --git a/physx/source/physxextensions/src/ExtGearJoint.cpp b/physx/source/physxextensions/src/ExtGearJoint.cpp index 95c6fca4b..4b9920137 100644 --- a/physx/source/physxextensions/src/ExtGearJoint.cpp +++ b/physx/source/physxextensions/src/ExtGearJoint.cpp @@ -55,35 +55,38 @@ bool GearJoint::setHinges(const PxBase* hinge0, const PxBase* hinge1) { GearJointData* data = static_cast(mData); - if(!hinge0 || !hinge1) - return outputError(__LINE__, "PxGearJoint::setHinges: cannot pass null pointers to this function."); - - const PxType type0 = hinge0->getConcreteType(); - if(type0 == PxConcreteType::eARTICULATION_JOINT_REDUCED_COORDINATE) + if(hinge0) { - const PxArticulationJointReducedCoordinate* joint0 = static_cast(hinge0); - const PxArticulationJointType::Enum artiJointType = joint0->getJointType(); - if(artiJointType != PxArticulationJointType::eREVOLUTE && artiJointType != PxArticulationJointType::eREVOLUTE_UNWRAPPED) - return outputError(__LINE__, "PxGearJoint::setHinges: passed joint must be either a revolute joint."); - } - else - { - if(type0 != PxJointConcreteType::eREVOLUTE && type0 != PxJointConcreteType::eD6) - return outputError(__LINE__, "PxGearJoint::setHinges: passed joint must be either a revolute joint or a D6 joint."); - } - - const PxType type1 = hinge1->getConcreteType(); - if(type1 == PxConcreteType::eARTICULATION_JOINT_REDUCED_COORDINATE) - { - const PxArticulationJointReducedCoordinate* joint1 = static_cast(hinge1); - const PxArticulationJointType::Enum artiJointType = joint1->getJointType(); - if(artiJointType != PxArticulationJointType::eREVOLUTE && artiJointType != PxArticulationJointType::eREVOLUTE_UNWRAPPED) - return outputError(__LINE__, "PxGearJoint::setHinges: passed joint must be either a revolute joint."); + const PxType type0 = hinge0->getConcreteType(); + if(type0 == PxConcreteType::eARTICULATION_JOINT_REDUCED_COORDINATE) + { + const PxArticulationJointReducedCoordinate* joint0 = static_cast(hinge0); + const PxArticulationJointType::Enum artiJointType = joint0->getJointType(); + if(artiJointType != PxArticulationJointType::eREVOLUTE && artiJointType != PxArticulationJointType::eREVOLUTE_UNWRAPPED) + return outputError(__LINE__, "PxGearJoint::setHinges: passed joint must be either a revolute joint."); + } + else + { + if(type0 != PxJointConcreteType::eREVOLUTE && type0 != PxJointConcreteType::eD6) + return outputError(__LINE__, "PxGearJoint::setHinges: passed joint must be either a revolute joint or a D6 joint."); + } } - else + + if(hinge1) { - if(type1 != PxJointConcreteType::eREVOLUTE && type1 != PxJointConcreteType::eD6) - return outputError(__LINE__, "PxGearJoint::setHinges: passed joint must be either a revolute joint or a D6 joint."); + const PxType type1 = hinge1->getConcreteType(); + if(type1 == PxConcreteType::eARTICULATION_JOINT_REDUCED_COORDINATE) + { + const PxArticulationJointReducedCoordinate* joint1 = static_cast(hinge1); + const PxArticulationJointType::Enum artiJointType = joint1->getJointType(); + if(artiJointType != PxArticulationJointType::eREVOLUTE && artiJointType != PxArticulationJointType::eREVOLUTE_UNWRAPPED) + return outputError(__LINE__, "PxGearJoint::setHinges: passed joint must be either a revolute joint."); + } + else + { + if(type1 != PxJointConcreteType::eREVOLUTE && type1 != PxJointConcreteType::eD6) + return outputError(__LINE__, "PxGearJoint::setHinges: passed joint must be either a revolute joint or a D6 joint."); + } } data->hingeJoint0 = hinge0; diff --git a/physx/source/physxextensions/src/ExtParticleExt.cpp b/physx/source/physxextensions/src/ExtParticleExt.cpp index f0f91118e..d2bb81972 100644 --- a/physx/source/physxextensions/src/ExtParticleExt.cpp +++ b/physx/source/physxextensions/src/ExtParticleExt.cpp @@ -42,6 +42,7 @@ namespace ExtGpu void PxDmaDataToDevice(PxCudaContextManager* cudaContextManager, PxParticleBuffer* particleBuffer, const PxParticleBufferDesc& desc) { +#if PX_SUPPORT_GPU_PHYSX cudaContextManager->acquireContext(); PxVec4* posInvMass = particleBuffer->getPositionInvMasses(); @@ -63,6 +64,11 @@ void PxDmaDataToDevice(PxCudaContextManager* cudaContextManager, PxParticleBuffe cudaContext->streamSynchronize(0); cudaContextManager->releaseContext(); +#else + PX_UNUSED(cudaContextManager); + PX_UNUSED(particleBuffer); + PX_UNUSED(desc); +#endif } PxParticleBuffer* PxCreateAndPopulateParticleBuffer(const PxParticleBufferDesc& desc, PxCudaContextManager* cudaContextManager) @@ -83,6 +89,7 @@ PxParticleAndDiffuseBuffer* PxCreateAndPopulateParticleAndDiffuseBuffer(const Px PxParticleClothBuffer* PxCreateAndPopulateParticleClothBuffer(const PxParticleBufferDesc& desc, const PxParticleClothDesc& clothDesc, PxPartitionedParticleCloth& output, PxCudaContextManager* cudaContextManager) { +#if PX_SUPPORT_GPU_PHYSX cudaContextManager->acquireContext(); PxParticleClothBuffer* clothBuffer = PxGetPhysics().createParticleClothBuffer(desc.maxParticles, desc.maxVolumes, clothDesc.nbCloths, clothDesc.nbTriangles, clothDesc.nbSprings, cudaContextManager); @@ -113,12 +120,19 @@ PxParticleClothBuffer* PxCreateAndPopulateParticleClothBuffer(const PxParticleBu cudaContextManager->releaseContext(); - return clothBuffer; +#else + PX_UNUSED(desc); + PX_UNUSED(clothDesc); + PX_UNUSED(output); + PX_UNUSED(cudaContextManager); + return NULL; +#endif } PxParticleRigidBuffer* PxCreateAndPopulateParticleRigidBuffer(const PxParticleBufferDesc& desc, const PxParticleRigidDesc& rigidDesc, PxCudaContextManager* cudaContextManager) { +#if PX_SUPPORT_GPU_PHYSX cudaContextManager->acquireContext(); PxParticleRigidBuffer* rigidBuffer = PxGetPhysics().createParticleRigidBuffer(desc.maxParticles, desc.maxVolumes, rigidDesc.maxRigids, cudaContextManager); @@ -158,7 +172,13 @@ PxParticleRigidBuffer* PxCreateAndPopulateParticleRigidBuffer(const PxParticleBu cudaContextManager->releaseContext(); -return rigidBuffer; + return rigidBuffer; +#else + PX_UNUSED(desc); + PX_UNUSED(rigidDesc); + PX_UNUSED(cudaContextManager); + return NULL; +#endif } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -171,6 +191,7 @@ PxParticleAttachmentBuffer::PxParticleAttachmentBuffer(PxParticleBuffer& particl PxParticleAttachmentBuffer::~PxParticleAttachmentBuffer() { +#if PX_SUPPORT_GPU_PHYSX mCudaContextManager->acquireContext(); PxCudaContext* cudaContext = mCudaContextManager->getCudaContext(); @@ -184,10 +205,12 @@ PxParticleAttachmentBuffer::~PxParticleAttachmentBuffer() mDeviceFilters = NULL; mCudaContextManager->releaseContext(); +#endif } void PxParticleAttachmentBuffer::copyToDevice(CUstream stream) { +#if PX_SUPPORT_GPU_PHYSX mCudaContextManager->acquireContext(); PxCudaContext* cudaContext = mCudaContextManager->getCudaContext(); @@ -236,6 +259,9 @@ void PxParticleAttachmentBuffer::copyToDevice(CUstream stream) mDestroyedRefrencedBodies.resize(0); mCudaContextManager->releaseContext(); +#else + PX_UNUSED(stream); +#endif } void PxParticleAttachmentBuffer::addRigidAttachment(PxRigidActor* rigidActor, const PxU32 particleID, const PxVec3& localPose, PxConeLimitedConstraint* coneLimit) @@ -438,27 +464,31 @@ struct ParticleClothBuffersImpl : public PxParticleClothBufferHelper, public PxU { mMaxParticles = maxParticles; mClothDesc.nbParticles = 0; - mClothDesc.restPositions = mCudaContextManager->allocPinnedHostBuffer(maxParticles); mMaxTriangles = maxTriangles; mClothDesc.nbTriangles = 0; - mClothDesc.triangles = mCudaContextManager->allocPinnedHostBuffer(maxTriangles * 3); mMaxSprings = maxSprings; mClothDesc.nbSprings = 0; - mClothDesc.springs = mCudaContextManager->allocPinnedHostBuffer(maxSprings); mMaxCloths = maxCloths; mClothDesc.nbCloths = 0; +#if PX_SUPPORT_GPU_PHYSX + mClothDesc.restPositions = mCudaContextManager->allocPinnedHostBuffer(maxParticles); + mClothDesc.triangles = mCudaContextManager->allocPinnedHostBuffer(maxTriangles * 3); + mClothDesc.springs = mCudaContextManager->allocPinnedHostBuffer(maxSprings); mClothDesc.cloths = mCudaContextManager->allocPinnedHostBuffer(maxCloths); +#endif } void release() { +#if PX_SUPPORT_GPU_PHYSX mCudaContextManager->freePinnedHostBuffer(mClothDesc.cloths); mCudaContextManager->freePinnedHostBuffer(mClothDesc.restPositions); mCudaContextManager->freePinnedHostBuffer(mClothDesc.triangles); mCudaContextManager->freePinnedHostBuffer(mClothDesc.springs); +#endif PX_DELETE_THIS; } @@ -567,13 +597,19 @@ struct ParticleVolumeBuffersImpl : public PxParticleVolumeBufferHelper, public P mParticleVolumeMeshes = reinterpret_cast(PX_ALLOC(sizeof(PxParticleVolumeMesh) * maxVolumes, "ParticleVolumeBuffersImpl::mParticleVolumeMeshes")); mTriangles = reinterpret_cast(PX_ALLOC(sizeof(PxU32) * maxTriangles * 3, "ParticleVolumeBuffersImpl::mTriangles")); +#if PX_SUPPORT_GPU_PHYSX mParticleVolumes = cudaContextManager->allocPinnedHostBuffer(maxVolumes); mCudaContextManager = cudaContextManager; +#else + PX_UNUSED(cudaContextManager); +#endif } void release() { +#if PX_SUPPORT_GPU_PHYSX mCudaContextManager->freePinnedHostBuffer(mParticleVolumes); +#endif PX_FREE(mParticleVolumeMeshes); PX_FREE(mTriangles); PX_DELETE_THIS; @@ -678,22 +714,26 @@ struct ParticleRigidBuffersImpl : public PxParticleRigidBufferHelper, public PxU mMaxParticles = maxParticles; mNumParticles = 0; +#if PX_SUPPORT_GPU_PHYSX mCudaContextManager->allocPinnedHostBuffer(mRigidDesc.rigidOffsets, maxRigids + 1); mCudaContextManager->allocPinnedHostBuffer(mRigidDesc.rigidCoefficients, maxRigids); mCudaContextManager->allocPinnedHostBuffer(mRigidDesc.rigidTranslations, maxRigids); mCudaContextManager->allocPinnedHostBuffer(mRigidDesc.rigidRotations, maxRigids); mCudaContextManager->allocPinnedHostBuffer(mRigidDesc.rigidLocalPositions, maxParticles); mCudaContextManager->allocPinnedHostBuffer(mRigidDesc.rigidLocalNormals, maxParticles); +#endif } void release() { +#if PX_SUPPORT_GPU_PHYSX mCudaContextManager->freePinnedHostBuffer(mRigidDesc.rigidOffsets); mCudaContextManager->freePinnedHostBuffer(mRigidDesc.rigidCoefficients); mCudaContextManager->freePinnedHostBuffer(mRigidDesc.rigidTranslations); mCudaContextManager->freePinnedHostBuffer(mRigidDesc.rigidRotations); mCudaContextManager->freePinnedHostBuffer(mRigidDesc.rigidLocalPositions); mCudaContextManager->freePinnedHostBuffer(mRigidDesc.rigidLocalNormals); +#endif PX_DELETE_THIS; } diff --git a/physx/source/physxextensions/src/ExtRackAndPinionJoint.cpp b/physx/source/physxextensions/src/ExtRackAndPinionJoint.cpp index bc78dd2ba..7ed635033 100644 --- a/physx/source/physxextensions/src/ExtRackAndPinionJoint.cpp +++ b/physx/source/physxextensions/src/ExtRackAndPinionJoint.cpp @@ -91,35 +91,38 @@ bool RackAndPinionJoint::setJoints(const PxBase* hinge, const PxBase* prismatic) { RackAndPinionJointData* data = static_cast(mData); - if(!hinge || !prismatic) - return outputError(__LINE__, "PxRackAndPinionJoint::setJoints: cannot pass null pointers to this function."); - - const PxType type0 = hinge->getConcreteType(); - if(type0 == PxConcreteType::eARTICULATION_JOINT_REDUCED_COORDINATE) - { - const PxArticulationJointReducedCoordinate* joint0 = static_cast(hinge); - const PxArticulationJointType::Enum artiJointType0 = joint0->getJointType(); - if(artiJointType0 != PxArticulationJointType::eREVOLUTE && artiJointType0 != PxArticulationJointType::eREVOLUTE_UNWRAPPED) - return outputError(__LINE__, "PxGearJoint::setJoints: passed joint must be a revolute joint."); - } - else + if(hinge) { - if(type0 != PxJointConcreteType::eREVOLUTE && type0 != PxJointConcreteType::eD6) - return outputError(__LINE__, "PxRackAndPinionJoint::setJoints: passed hinge joint must be either a revolute joint or a D6 joint."); + const PxType type0 = hinge->getConcreteType(); + if(type0 == PxConcreteType::eARTICULATION_JOINT_REDUCED_COORDINATE) + { + const PxArticulationJointReducedCoordinate* joint0 = static_cast(hinge); + const PxArticulationJointType::Enum artiJointType0 = joint0->getJointType(); + if(artiJointType0 != PxArticulationJointType::eREVOLUTE && artiJointType0 != PxArticulationJointType::eREVOLUTE_UNWRAPPED) + return outputError(__LINE__, "PxRackAndPinionJoint::setJoints: passed joint must be a revolute joint."); + } + else + { + if(type0 != PxJointConcreteType::eREVOLUTE && type0 != PxJointConcreteType::eD6) + return outputError(__LINE__, "PxRackAndPinionJoint::setJoints: passed hinge joint must be either a revolute joint or a D6 joint."); + } } - const PxType type1 = prismatic->getConcreteType(); - if(type1 == PxConcreteType::eARTICULATION_JOINT_REDUCED_COORDINATE) + if(prismatic) { - const PxArticulationJointReducedCoordinate* joint1 = static_cast(prismatic); - const PxArticulationJointType::Enum artiJointType1 = joint1->getJointType(); - if(artiJointType1 != PxArticulationJointType::ePRISMATIC) - return outputError(__LINE__, "PxGearJoint::setJoints: passed joint must be a prismatic joint."); - } - else - { - if(type1 != PxJointConcreteType::ePRISMATIC && type1 != PxJointConcreteType::eD6) - return outputError(__LINE__, "PxRackAndPinionJoint::setJoints: passed prismatic joint must be either a prismatic joint or a D6 joint."); + const PxType type1 = prismatic->getConcreteType(); + if(type1 == PxConcreteType::eARTICULATION_JOINT_REDUCED_COORDINATE) + { + const PxArticulationJointReducedCoordinate* joint1 = static_cast(prismatic); + const PxArticulationJointType::Enum artiJointType1 = joint1->getJointType(); + if(artiJointType1 != PxArticulationJointType::ePRISMATIC) + return outputError(__LINE__, "PxRackAndPinionJoint::setJoints: passed joint must be a prismatic joint."); + } + else + { + if(type1 != PxJointConcreteType::ePRISMATIC && type1 != PxJointConcreteType::eD6) + return outputError(__LINE__, "PxRackAndPinionJoint::setJoints: passed prismatic joint must be either a prismatic joint or a D6 joint."); + } } data->hingeJoint = hinge; diff --git a/physx/source/physxextensions/src/ExtRemeshingExt.cpp b/physx/source/physxextensions/src/ExtRemeshingExt.cpp index 3c20eab66..7c2d0e91f 100644 --- a/physx/source/physxextensions/src/ExtRemeshingExt.cpp +++ b/physx/source/physxextensions/src/ExtRemeshingExt.cpp @@ -148,6 +148,242 @@ namespace physx return -1; } + + struct Info + { + PxI32 StartIndex; + PxI32 Count; + + Info(PxI32 startIndex, PxI32 count) + { + StartIndex = startIndex; + Count = count; + } + }; + + void checkEdge(PxU32 a, PxU32 b, PxHashMap& edges, PxArray& points, PxReal maxEdgeLength) + { + if (a > b) + PxSwap(a, b); + + PxReal l = (points[a] - points[b]).magnitudeSquared(); + if (l < maxEdgeLength * maxEdgeLength) + return; + + l = PxSqrt(l); + + PxU32 numSubdivisions = (PxU32)(l / maxEdgeLength); + if (numSubdivisions <= 1) + return; + + PxU64 k = key(a, b); + if (edges.find(k)) + return; + + edges.insert(k, Info(points.size(), numSubdivisions - 1)); + for (PxU32 i = 1; i < numSubdivisions; ++i) + { + PxReal p = (PxReal)i / numSubdivisions; + points.pushBack((1 - p) * points[a] + p * points[b]); + } + } + + PX_FORCE_INLINE Info getEdge(PxU32 a, PxU32 b, PxHashMap& edges) + { + const PxPair* value = edges.find(key(a, b)); + if (value) + return value->second; + return Info(-1, -1); + } + + PX_FORCE_INLINE void addPoints(PxArray& polygon, const Info& ab, bool reverse) + { + if (reverse) + { + for (PxI32 i = ab.Count - 1; i >= 0; --i) + polygon.pushBack(ab.StartIndex + i); + } + else + { + for (PxI32 i = 0; i < ab.Count; ++i) + polygon.pushBack(ab.StartIndex + i); + } + } + + PX_FORCE_INLINE PxReal angle(const PxVec3& l, const PxVec3& r) + { + PxReal d = l.dot(r) / PxSqrt(l.magnitudeSquared() * r.magnitudeSquared()); + if (d <= -1) return PxPi; + if (d >= 1) return 0.0f; + return PxAcos(d); + } + + PX_FORCE_INLINE PxReal evaluateCost(const PxArray& vertices, PxU32 a, PxU32 b, PxU32 c) + { + const PxVec3& aa = vertices[a]; + const PxVec3& bb = vertices[b]; + const PxVec3& cc = vertices[c]; + + PxReal a1 = angle(bb - aa, cc - aa); + PxReal a2 = angle(aa - bb, cc - bb); + PxReal a3 = angle(aa - cc, bb - cc); + + return PxMax(a1, PxMax(a2, a3)); + + //return (aa - bb).magnitude() + (aa - cc).magnitude() + (bb - cc).magnitude(); + } + + void triangulateConvex(PxU32 originalTriangleIndexTimes3, PxArray& polygon, const PxArray& vertices, PxArray& triangles, PxArray& offsets) + { + offsets.forceSize_Unsafe(0); + offsets.reserve(polygon.size()); + for (PxU32 i = 0; i < polygon.size(); ++i) + offsets.pushBack(1); + + PxI32 start = 0; + PxU32 count = polygon.size(); + PxU32 triCounter = 0; + while (count > 2) + { + PxReal minCost = FLT_MAX; + PxI32 best = -1; + PxI32 i = start; + for (PxU32 j = 0; j < count; ++j) + { + PxU32 a = polygon[i]; + + PX_ASSERT(offsets[i] >= 0); + + PxI32 n = (i + offsets[i]) % polygon.size(); + + PX_ASSERT(offsets[n] >= 0); + + PxU32 b = polygon[n]; + PxU32 nn = (n + offsets[n]) % polygon.size(); + + PX_ASSERT(offsets[nn] >= 0); + + PxU32 c = polygon[nn]; + + PxReal cost = evaluateCost(vertices, a, b, c); + if (cost < minCost) + { + minCost = cost; + best = i; + } + i = n; + } + { + PxU32 a = polygon[best]; + PxI32 n = (best + offsets[best]) % polygon.size(); + PxU32 b = polygon[n]; + PxU32 nn = (n + offsets[n]) % polygon.size(); + PxU32 c = polygon[nn]; + + if (n == start) + start += offsets[n]; + + offsets[best] += offsets[n]; + offsets[n] = -1; + + PX_ASSERT(offsets[(best + offsets[best]) % polygon.size()] >= 0); + + if (triCounter == 0) + { + triangles[originalTriangleIndexTimes3 + 0] = a; + triangles[originalTriangleIndexTimes3 + 1] = b; + triangles[originalTriangleIndexTimes3 + 2] = c; + } + else + { + triangles.pushBack(a); + triangles.pushBack(b); + triangles.pushBack(c); + } + ++triCounter; + } + + --count; + } + } + + bool limitMaxEdgeLengthAdaptive(PxArray& triangles, PxArray& points, PxReal maxEdgeLength, PxArray* triangleMap = NULL) + { + PxHashMap edges; + bool split = false; + + //Analyze edges + for (PxU32 i = 0; i < triangles.size(); i += 3) + { + const PxU32* t = &triangles[i]; + checkEdge(t[0], t[1], edges, points, maxEdgeLength); + checkEdge(t[1], t[2], edges, points, maxEdgeLength); + checkEdge(t[0], t[2], edges, points, maxEdgeLength); + } + + PxArray offsets; + PxArray polygon; + + //Subdivide triangles if required + PxU32 size = triangles.size(); + for (PxU32 i = 0; i < size; i += 3) + { + const PxU32* t = &triangles[i]; + Info ab = getEdge(t[0], t[1], edges); + Info bc = getEdge(t[1], t[2], edges); + Info ac = getEdge(t[0], t[2], edges); + if (ab.StartIndex >= 0 || bc.StartIndex >= 0 || ac.StartIndex >= 0) + { + polygon.forceSize_Unsafe(0); + polygon.pushBack(t[0]); + addPoints(polygon, ab, t[0] > t[1]); + polygon.pushBack(t[1]); + addPoints(polygon, bc, t[1] > t[2]); + polygon.pushBack(t[2]); + addPoints(polygon, ac, t[2] > t[0]); + + PxU32 s = triangles.size(); + triangulateConvex(i, polygon, points, triangles, offsets); + split = true; + + if (triangleMap != NULL) + { + for (PxU32 j = s; j < triangles.size(); ++j) + triangleMap->pushBack((*triangleMap)[i]); + } + } + /*else + { + result.pushBack(t[0]); + result.pushBack(t[1]); + result.pushBack(t[2]); + if (triangleMap != NULL) + triangleMap->pushBack((*triangleMap)[i]); + }*/ + } + return split; + } + + bool PxRemeshingExt::reduceSliverTriangles(PxArray& triangles, PxArray& points, PxReal maxEdgeLength, PxU32 maxIterations, PxArray* triangleMap, PxU32 triangleCountThreshold) + { + bool split = limitMaxEdgeLengthAdaptive(triangles, points, maxEdgeLength, triangleMap); + if (!split) + return false; + + for (PxU32 i = 1; i < maxIterations; ++i) + { + split = limitMaxEdgeLengthAdaptive(triangles, points, maxEdgeLength, triangleMap); + + if (!split) + break; + + if (triangles.size() >= triangleCountThreshold) + break; + } + + return true; + } + bool PxRemeshingExt::limitMaxEdgeLength(PxArray& triangles, PxArray& points, PxReal maxEdgeLength, PxU32 maxIterations, PxArray* triangleMap, PxU32 triangleCountThreshold) { if (triangleMap) diff --git a/physx/source/physxextensions/src/ExtSimpleFactory.cpp b/physx/source/physxextensions/src/ExtSimpleFactory.cpp index c8748f780..7f4f0e61c 100644 --- a/physx/source/physxextensions/src/ExtSimpleFactory.cpp +++ b/physx/source/physxextensions/src/ExtSimpleFactory.cpp @@ -67,8 +67,16 @@ PxRigidDynamic* PxCreateDynamic(PxPhysics& sdk, PxRigidDynamic* actor = sdk.createRigidDynamic(transform); if(actor) { - actor->attachShape(shape); - PxRigidBodyExt::updateMassAndInertia(*actor, density); + if(!actor->attachShape(shape)) + { + actor->release(); + return NULL; + } + if(!PxRigidBodyExt::updateMassAndInertia(*actor, density)) + { + actor->release(); + return NULL; + } } return actor; } diff --git a/physx/source/physxextensions/src/ExtSoftBodyExt.cpp b/physx/source/physxextensions/src/ExtSoftBodyExt.cpp index 97dcfe571..b2c51edbc 100644 --- a/physx/source/physxextensions/src/ExtSoftBodyExt.cpp +++ b/physx/source/physxextensions/src/ExtSoftBodyExt.cpp @@ -298,14 +298,18 @@ void PxSoftBodyExt::copyToDevice(PxSoftBody& sb, PxSoftBodyDataFlags flags, PxVe if (flags & PxSoftBodyDataFlag::eSIM_VELOCITY && simVelocitiesPinned) ctx->memcpyHtoDAsync(reinterpret_cast(sb.getSimVelocityBufferD()), simVelocitiesPinned, sb.getSimulationMesh()->getNbVertices() * sizeof(PxVec4), stream); - sb.markDirty(flags); - // we need to synchronize if the stream is the default argument. if (stream == 0) { ctx->streamSynchronize(stream); } +#else + PX_UNUSED(restPositionsPinned); + PX_UNUSED(simVelocitiesPinned); + PX_UNUSED(stream); #endif + + sb.markDirty(flags); } PxSoftBodyMesh* PxSoftBodyExt::createSoftBodyMesh(const PxCookingParams& params, const PxSimpleTriangleMesh& surfaceMesh, PxU32 numVoxelsAlongLongestAABBAxis, PxInsertionCallback& insertionCallback, const bool validate) @@ -382,8 +386,8 @@ PxSoftBody* PxSoftBodyExt::createSoftBodyFromMesh(PxSoftBodyMesh* softBodyMesh, PxSoftBodyExt::updateMass(*softBody, density, maxInvMassRatio, simPositionInvMassPinned); PxSoftBodyExt::copyToDevice(*softBody, PxSoftBodyDataFlag::eALL, simPositionInvMassPinned, simVelocityPinned, collPositionInvMassPinned, restPositionPinned); - PxCudaContextManager* mgr = &cudaContextManager; #if PX_SUPPORT_GPU_PHYSX + PxCudaContextManager* mgr = &cudaContextManager; PX_PINNED_HOST_FREE(mgr, simPositionInvMassPinned); PX_PINNED_HOST_FREE(mgr, simVelocityPinned); PX_PINNED_HOST_FREE(mgr, collPositionInvMassPinned); @@ -459,6 +463,8 @@ void PxSoftBodyExt::allocateAndInitializeHostMirror(PxSoftBody& softBody, PxCuda simVelocityPinned = PX_PINNED_HOST_ALLOC_T(PxVec4, cudaContextManager, nbSimVerts); collPositionInvMassPinned = PX_PINNED_HOST_ALLOC_T(PxVec4, cudaContextManager, nbCollVerts); restPositionPinned = PX_PINNED_HOST_ALLOC_T(PxVec4, cudaContextManager, nbCollVerts); +#else + PX_UNUSED(cudaContextManager); #endif // write positionInvMass into CPU part. diff --git a/physx/source/physxextensions/src/omnipvd/ExtOmniPvdSetData.h b/physx/source/physxextensions/src/omnipvd/ExtOmniPvdSetData.h index 29243bdd7..2fb3afd02 100644 --- a/physx/source/physxextensions/src/omnipvd/ExtOmniPvdSetData.h +++ b/physx/source/physxextensions/src/omnipvd/ExtOmniPvdSetData.h @@ -42,13 +42,15 @@ #if PX_SUPPORT_OMNI_PVD #include "OmniPvdPxExtensionsSampler.h" +#include "omnipvd/PxOmniPvd.h" // // Define the macros needed in CmOmniPvdAutoGenSetData.h // #undef OMNI_PVD_GET_WRITER #define OMNI_PVD_GET_WRITER(writer) \ -OmniPvdWriter* writer = physx::Ext::OmniPvdGetWriter(); +physx::PxOmniPvd::ScopedExclusiveWriter writeLock(physx::Ext::OmniPvdGetInstance()); \ +OmniPvdWriter* writer = writeLock.getWriter(); #undef OMNI_PVD_GET_REGISTRATION_DATA diff --git a/physx/source/physxextensions/src/omnipvd/OmniPvdPxExtensionsSampler.cpp b/physx/source/physxextensions/src/omnipvd/OmniPvdPxExtensionsSampler.cpp index ed7badc9c..f198c8568 100644 --- a/physx/source/physxextensions/src/omnipvd/OmniPvdPxExtensionsSampler.cpp +++ b/physx/source/physxextensions/src/omnipvd/OmniPvdPxExtensionsSampler.cpp @@ -30,6 +30,7 @@ #if PX_SUPPORT_OMNI_PVD #include "OmniPvdPxExtensionsSampler.h" +#include "omnipvd/PxOmniPvd.h" using namespace physx; @@ -37,25 +38,33 @@ using namespace physx; void OmniPvdPxExtensionsSampler::registerClasses() { - if (mWriter) + PxOmniPvd::ScopedExclusiveWriter scope(mOmniPvdInstance); + OmniPvdWriter* writer = scope.getWriter(); + if (writer) { - mRegistrationData.registerData(*mWriter); + mRegistrationData.registerData(*mOmniPvdInstance->getWriter()); } } -OmniPvdPxExtensionsSampler::OmniPvdPxExtensionsSampler() : mWriter(NULL) +OmniPvdPxExtensionsSampler::OmniPvdPxExtensionsSampler() { + mOmniPvdInstance = NULL; } OmniPvdPxExtensionsSampler::~OmniPvdPxExtensionsSampler() { } -void OmniPvdPxExtensionsSampler::setOmniPvdWriter(OmniPvdWriter* omniPvdWriter) +void OmniPvdPxExtensionsSampler::setOmniPvdInstance(physx::PxOmniPvd* omniPvdInstance) { - mWriter = omniPvdWriter; + mOmniPvdInstance = omniPvdInstance; } +physx::PxOmniPvd* OmniPvdPxExtensionsSampler::getOmniPvdInstance() { + return mOmniPvdInstance; +} + + /////////////////////////////////////////////////////////////////////////////// static OmniPvdPxExtensionsSampler* gOmniPvdPxExtensionsSampler = NULL; @@ -95,12 +104,12 @@ const OmniPvdPxExtensionsRegistrationData* OmniPvdGetPxExtensionsRegistrationDat } } -OmniPvdWriter* OmniPvdGetWriter() +PxOmniPvd* OmniPvdGetInstance() { OmniPvdPxExtensionsSampler* sampler = OmniPvdPxExtensionsSampler::getInstance(); if (sampler) { - return sampler->getOmniPvdWriter(); + return sampler->getOmniPvdInstance(); } else { diff --git a/physx/source/physxextensions/src/omnipvd/OmniPvdPxExtensionsSampler.h b/physx/source/physxextensions/src/omnipvd/OmniPvdPxExtensionsSampler.h index 958c3a635..3eec61199 100644 --- a/physx/source/physxextensions/src/omnipvd/OmniPvdPxExtensionsSampler.h +++ b/physx/source/physxextensions/src/omnipvd/OmniPvdPxExtensionsSampler.h @@ -36,14 +36,19 @@ #include "ExtOmniPvdRegistrationData.h" +namespace physx +{ + class PxOmniPvd; +} + class OmniPvdPxExtensionsSampler : public physx::PxUserAllocated { public: OmniPvdPxExtensionsSampler(); ~OmniPvdPxExtensionsSampler(); - void setOmniPvdWriter(OmniPvdWriter* omniPvdWriter); - OmniPvdWriter* getOmniPvdWriter() const { return mWriter; } + void setOmniPvdInstance(physx::PxOmniPvd* omniPvdInstance); + physx::PxOmniPvd* getOmniPvdInstance(); void registerClasses(); const physx::Ext::OmniPvdPxExtensionsRegistrationData& getRegistrationData() const { return mRegistrationData; } @@ -54,7 +59,7 @@ class OmniPvdPxExtensionsSampler : public physx::PxUserAllocated static void destroyInstance(); private: - OmniPvdWriter* mWriter; + physx::PxOmniPvd* mOmniPvdInstance; physx::Ext::OmniPvdPxExtensionsRegistrationData mRegistrationData; }; @@ -65,8 +70,7 @@ namespace Ext { const OmniPvdPxExtensionsRegistrationData* OmniPvdGetPxExtensionsRegistrationData(); -OmniPvdWriter* OmniPvdGetWriter(); - +PxOmniPvd* OmniPvdGetInstance(); } } diff --git a/physx/source/physxextensions/src/tet/ExtDelaunayBoundaryInserter.cpp b/physx/source/physxextensions/src/tet/ExtDelaunayBoundaryInserter.cpp index 1be2936ba..04a8bc5d2 100644 --- a/physx/source/physxextensions/src/tet/ExtDelaunayBoundaryInserter.cpp +++ b/physx/source/physxextensions/src/tet/ExtDelaunayBoundaryInserter.cpp @@ -2316,6 +2316,15 @@ namespace Ext else t = triangles.at(i); + for (PxU32 j = 0; j < 3; ++j) + { + PxI32 id = t[j]; + if (id < 0 || id >= PxI32(points.count)) + { + return PxTriangleMeshAnalysisResult::eTRIANGLE_INDEX_OUT_OF_RANGE | PxTriangleMeshAnalysisResult::eMESH_IS_INVALID; + } + } + mappedTriangles.pushBack(t); } diff --git a/physx/source/simulationcontroller/src/ScBodySim.cpp b/physx/source/simulationcontroller/src/ScBodySim.cpp index 1091af4b6..cd98f323f 100644 --- a/physx/source/simulationcontroller/src/ScBodySim.cpp +++ b/physx/source/simulationcontroller/src/ScBodySim.cpp @@ -33,6 +33,7 @@ #include "PxsContext.h" #include "PxsSimpleIslandManager.h" #include "PxsSimulationController.h" +#include "ScSimStateData.h" using namespace physx; using namespace physx::Dy; @@ -138,6 +139,10 @@ BodySim::~BodySim() tearDownSimStateData(isKinematic()); PX_ASSERT(!mSimStateData); + // PX-4603. AD: assuming that the articulation code cleans up the dirty state in case this is an articulation link. + if (!isArticulationLink()) + scene.getVelocityModifyMap().boundedReset(mNodeIndex.index()); + PX_ASSERT(!readInternalFlag(BF_ON_DEATHROW)); // Before 3.0 it could happen that destroy could get called twice. Assert to make sure this is fixed. raiseInternalFlag(BF_ON_DEATHROW); diff --git a/physx/source/simulationcontroller/src/ScFiltering.cpp b/physx/source/simulationcontroller/src/ScFiltering.cpp index ac443a45d..598329749 100644 --- a/physx/source/simulationcontroller/src/ScFiltering.cpp +++ b/physx/source/simulationcontroller/src/ScFiltering.cpp @@ -481,6 +481,22 @@ static PX_FORCE_INLINE bool testElementSimPointers(const ElementSim* e0, const E return true; } +static PX_FORCE_INLINE bool testShapeSimCorePointers(const ShapeSimBase* s0, const ShapeSimBase* s1) +{ + bool isValid0 = s0->isPxsCoreValid(); + bool isValid1 = s1->isPxsCoreValid(); + PX_ASSERT(isValid0); + PX_ASSERT(isValid1); + + // GW: further defensive coding added for OM-111249 + // This is only a temporary / immediate solution to mitigate crashes + // Still need to root-cause what is causing null pointers here + if(!isValid0 || !isValid1) + return outputError(__LINE__, + "NPhaseCore::runOverlapFilters: found null PxsShapeCore pointers!"); + return true; +} + // PT: called from OverlapFilterTask void NPhaseCore::runOverlapFilters( PxU32 nbToProcess, const Bp::AABBOverlap* PX_RESTRICT pairs, FilterInfo* PX_RESTRICT filterInfo, PxU32& nbToKeep_, PxU32& nbToSuppress_, PxU32* PX_RESTRICT keepMap @@ -505,6 +521,10 @@ void NPhaseCore::runOverlapFilters( PxU32 nbToProcess, const Bp::AABBOverlap* PX const ShapeSimBase* s0 = static_cast(e0); const ShapeSimBase* s1 = static_cast(e1); + + if(!testShapeSimCorePointers(s0, s1)) + continue; + PX_ASSERT(&s0->getActor() != &s1->getActor()); // No actor internal interactions filterInfo[i].filterFlags = PxFilterFlags(0); diff --git a/physx/source/simulationcontroller/src/ScPipeline.cpp b/physx/source/simulationcontroller/src/ScPipeline.cpp index 96ecef684..2ee644619 100644 --- a/physx/source/simulationcontroller/src/ScPipeline.cpp +++ b/physx/source/simulationcontroller/src/ScPipeline.cpp @@ -310,8 +310,8 @@ void Sc::Scene::broadPhase(PxBaseTask* continuation) { PX_PROFILE_START_CROSSTHREAD("Basic.broadPhase", mContextId); - mProcessLostPatchesTask.setContinuation(&mPostNarrowPhase); - mProcessLostPatchesTask.removeReference(); + /*mProcessLostPatchesTask.setContinuation(&mPostNarrowPhase); + mProcessLostPatchesTask.removeReference();*/ #if PX_SUPPORT_GPU_PHYSX gpu_updateBounds(); @@ -1323,13 +1323,14 @@ void Sc::Scene::islandGen(PxBaseTask* continuation) //mLLContext->runModifiableContactManagers(); //KS - moved here so that we can get up-to-date touch found/lost events in IG - /*mProcessLostPatchesTask.setContinuation(&mUpdateDynamics); - mProcessLostPatchesTask.removeReference();*/ processNarrowPhaseTouchEvents(); // PT: could we merge processNarrowPhaseTouchEventsStage2 with processNarrowPhaseTouchEvents ? mProcessFoundPatchesTask.setContinuation(continuation); + mProcessLostPatchesTask.setContinuation(&mProcessFoundPatchesTask); + + mProcessLostPatchesTask.removeReference(); mProcessFoundPatchesTask.removeReference(); // extracting information for the contact callbacks must happen before the solver writes the post-solve diff --git a/physx/source/simulationcontroller/src/ScShapeInteraction.cpp b/physx/source/simulationcontroller/src/ScShapeInteraction.cpp index 9a9013841..b310712fd 100644 --- a/physx/source/simulationcontroller/src/ScShapeInteraction.cpp +++ b/physx/source/simulationcontroller/src/ScShapeInteraction.cpp @@ -547,49 +547,56 @@ PxU32 Sc::ShapeInteraction::getContactPointData(const void*& contactPatches, con const PxsCCDContactHeader* ccdContactStream = reinterpret_cast(workUnit.ccdContacts); PxU32 idx = 0; - if(output->nbContacts) + if(output) // preventive measure for omnicrash OM-109664 { - if(startOffset == 0) + if(output->nbContacts) { - contactPatches = output->contactPatches; - contactPoints = output->contactPoints; - contactDataSize = sizeof(PxContactPatch) * output->nbPatches + sizeof(PxContact) * output->nbContacts; - contactPointCount = output->nbContacts; - numPatches = output->nbPatches; - impulses = output->contactForces; + if(startOffset == 0) + { + contactPatches = output->contactPatches; + contactPoints = output->contactPoints; + contactDataSize = sizeof(PxContactPatch) * output->nbPatches + sizeof(PxContact) * output->nbContacts; + contactPointCount = output->nbContacts; + numPatches = output->nbPatches; + impulses = output->contactForces; + + if(!ccdContactStream) + return startOffset; + else + return (startOffset + 1); + } - if(!ccdContactStream) - return startOffset; - else - return (startOffset + 1); + idx++; } - idx++; - } - - while(ccdContactStream) - { - if(startOffset == idx) + while(ccdContactStream) { - const PxU8* stream = reinterpret_cast(ccdContactStream); - PxU16 streamSize = ccdContactStream->contactStreamSize; - contactPatches = stream + sizeof(PxsCCDContactHeader); - contactPoints = stream + sizeof(PxsCCDContactHeader) + sizeof(PxContactPatch); - contactDataSize = streamSize - sizeof(PxsCCDContactHeader); - contactPointCount = 1; - numPatches = 1; - impulses = reinterpret_cast(stream + ((streamSize + 0xf) & 0xfffffff0)); - - if(!ccdContactStream->nextStream) - return startOffset; - else - return (startOffset + 1); + if(startOffset == idx) + { + const PxU8* stream = reinterpret_cast(ccdContactStream); + PxU16 streamSize = ccdContactStream->contactStreamSize; + contactPatches = stream + sizeof(PxsCCDContactHeader); + contactPoints = stream + sizeof(PxsCCDContactHeader) + sizeof(PxContactPatch); + contactDataSize = streamSize - sizeof(PxsCCDContactHeader); + contactPointCount = 1; + numPatches = 1; + impulses = reinterpret_cast(stream + ((streamSize + 0xf) & 0xfffffff0)); + + if(!ccdContactStream->nextStream) + return startOffset; + else + return (startOffset + 1); + } + + idx++; + ccdContactStream = ccdContactStream->nextStream; } - - idx++; - ccdContactStream = ccdContactStream->nextStream; } } + else + { + PxGetFoundation().error(PxErrorCode::eINTERNAL_ERROR, PX_FL, "PxsContactManagerOutput output is null!\n"); + } contactPatches = NULL; contactPoints = NULL; diff --git a/physx/source/simulationcontroller/src/ScShapeSimBase.h b/physx/source/simulationcontroller/src/ScShapeSimBase.h index cabade534..9b9436211 100644 --- a/physx/source/simulationcontroller/src/ScShapeSimBase.h +++ b/physx/source/simulationcontroller/src/ScShapeSimBase.h @@ -63,6 +63,7 @@ namespace physx PX_FORCE_INLINE void setCore(const ShapeCore* core); PX_FORCE_INLINE const ShapeCore& getCore() const; + PX_FORCE_INLINE bool isPxsCoreValid() const { return mLLShape.mShapeCore != NULL; } PX_INLINE PxGeometryType::Enum getGeometryType() const { return getCore().getGeometryType(); } diff --git a/physx/version.txt b/physx/version.txt index cae073084..306cb9775 100644 --- a/physx/version.txt +++ b/physx/version.txt @@ -1 +1 @@ -5.3.0.33308187 \ No newline at end of file +5.3.1.e9cf8e18b \ No newline at end of file