Game Development (Animation, Gameplay, Graphics, System), Game Design, Photograph, Boxing, Film, Guitar, I also have a cat!
Game
Game Projects
Floating Otter
3D narrative indie game
Party Planet
An online asymmetric party game
He Bala Me
A 2D local two-player party game
Tears of the West Lake
A projection art interactive game
Mr.Summer
A 2D side-scrolling stealth game
Lose Sight
A 3d narrative game
Floating Otter
3D narrative indie game
Intro
Floating Otter is a 3D casual single player game in which the player takes on the role of a sea otter as it goes about its daily activities of feeding, cleaning and sleeping in the water. The game reflects the sea otter’s cute habits through different interactions and actions.
As a baby sea otter, the player goes through a difficult journey to meet new animal friends and finally find his lost mother.
Party Planets is a four player online party game where players take on the roles of either Human or Reaper. Humans will need to hide from the Reapers and bring the planet back to life. The Reaper need to stop the humans from restoring the planet and capture all humans.
This is a 2D local two-player game where players can choose different characters and play with their friends in different maps. The characters have unique skills and backstories. In addition, each map has its own unique elements. (The game is very cheerful throughout and I hope players will enjoy it)
This is a 2D projection art interactive game about the story of Chinese folklore Madame White Snake, Player can interect with projection by swiping the tablet screen.
The little boy is transformed into a bubblegum superhero with a frog hood in his dream. The protagonist’s dodges monsters in various food disguises through bubblegum in his dreams…
This is a third-person single-player narrative game that tells the story of a blind man. The player takes on the role of the blind man to complete his daily life and the story of the family with the little girl.
Responsive Real-Time Grass Rendering for General 3D Scenes
Mini-Maya
Basic Maya Functions implementation
Flocking CUDA Simulation
Flocking simulation based on the Reynolds Boids algorithm
Mini-Minecraft
Implement Basic Minecraft with C++ and OpenGL
Player Physics
In this part, I implemented the player’s tick function, which include processInputs and computePhysics functions. For processInputs, I associate each input keys with accelerations on each direction, which is fairly easy using Qt’s input system. Then for computePhysics, I have fly version and non-fly version. Player’s velocity is computed using
I also implemented delete and create block function, which is done in the moveclick event.Everytime the mouse click, I do a raycast from the camera and check whether it hit something within 3 units. If it does, set that block’s type to Empty.
Efficient Terrain Rendering and Chunking
CHUNK:
A structure is created that stores vertex positions, and another that stores directions, offsets, and vertices that form a chunk neighbor’s face.
Make Chunk inherits from Drawable, implements the create() function which iterates over the x, y, z coordinates of the chunk and iterates over the coordinates of the 6 neighboring blocks to check if they are empty. The VBO data is added for each face of each empty neighboring block if the neighboring block is empty.
The loadVBO() function is implemented to receive the interleaved vertex data vector as well as the index data vector , and buffer them into VBOs.
TERRAIN:
Terrain is now generated from a 4x4 Chunk to generate a zone unit. The terrain expands as the player approaches 16 blocks from the edge of a Chunk that is not connected to an existing Chunk.
Changed the draw() function when the Chunk inherits from Drawable, so it draws each Chunk with the given ShaderProgram; sets the model matrix to the appropriate X and Z transformations.
SHADERPROGRAM:
Implemented a second drawing function drawInterleave() for the ShaderProgram class, to render a Drawable with an interleaved VBO set.
Texture and Texture Animation
I finished the texture pipeline, and also some simple texture animation on water and lava. I also implemented opaque and transparent rendering so that after enabling GL_BLEND all textures are rendered correctly.
Muti-Thread
I implemented a multi-threaded chunked rendering. First, I locate the player’s zone by the current player position, then I compare the player’s zone in the previous frame with the zone in this frame to find the chunks that do not need to be rendered, and destroy the vbo data of these chunks. After that, I decide if I need to create chunks for this zone by determining if the zone was created before, and then store these chunks in the newChunkMap if required. By iterating through the newChunkMap, I create a blockTypeWorker for each new chunk and create an additional thread to initialize the block data in the chunk. After initializing the chunk, store it in the blockTypeMap. Iterate through the blockTypeMap, creating a VBOWorker for each chunk and creating an extra thread to initialize the chunk’s VBO data. Finally, after loading the VBO data, the chunk binds the VBO data to the GPU uniformly. In addition, a thread mutex is needed for each Map operation.
Shadow Mapping
This is a very classic method to generating shadows in games. In this project I only implemented a very basic SM, but planning to add PCSS in the future.
Difficulty:
I found it a little difficult to find a correct bias and near/far plan number, so it takes me a long time to adjust in order to create better shadows.
Weahter, Procedurally placed assets, Water waves, Post-process Camera Overlay, Distance fog
Weahter:
I implemented two different weather systems: rain and snow (triggered by the K and L keys in the demo):
Water waves:
I change the position of the water wave vertex Y by the sin function:
Post-process Camera Overlay:
For Underwater, I change the color of original vertex to blue and applied the sine function to implement the visual effect. (The same as ShaderFun project)
For UnderLava, I change the color of orignial vertex to red and increase the color depth by time through. Additionally, I make the visual effect more realistic by Berlin noise function.
Water:
Lava:
Distance fog:
Pass in the current position of the player through the shaderprogram. Linear interpolation is performed between the original color of each pixel and the color of the fog, depending on the distance of the object from the player.
CUDA Path Tracer
CUDA-enabled GPU for rapid path tracing
Intro
This project harnesses the power of CUDA-enabled GPU for rapid path tracing, generating high-quality, globally-lit visuals. Path tracing works by sending out rays from the camera. These rays, when they meet reflective or refractive surfaces, keep traveling until they intersect with a light source. Leveraging parallel processing, this method accurately determines the overall light intensity at a specific spot on an object, resulting in a lifelike representation. Incorporating CUDA guarantees peak performance in Physically-based Rendering.
The diffuse BSDF provides a surface with a matte appearance. It uses cosine-weighted sampling at the points where rays intersect the surface to decide the direction of subsequent rays and then evaluates these rays as they emanate from the surface.
A perfectly specular surface reflects rays at the same angle as they arrive, imparting a mirror-like appearance to the surface. The function ‘glm::reflect’ is utilized to produce this perfectly reflected ray.
In path tracing, both perfect and imperfect specular surfaces are simulated using probability distributions from GPU Gems 3, Chapter 20. Imperfect surfaces blend perfect specular and diffuse reflections for a more natural metallic look.
The images utilize Schlick’s approximation to achieve refraction effects. The results incorporate the function glm::refract, based on Snell’s law, to determine the direction of the refracted ray.
In path tracing, Depth of Field is achieved by jittering rays within an aperture, mirroring the real-world function of a lens. This introduces noise to rays that strike objects at the focal length, resulting in a blurry effect. According to PBRT 6.2.3:
Utilizing the tinyObjLoader, it parses the .obj file’s data to assemble scene triangles using vertex, face, normal, and texture information. Before rendering the mesh through ray-triangle intersections, it first performs bounding volume intersection culling by examining rays against a volume encompassing the entire mesh.
In path tracing, accurately determining attributes like surface normal, and ray’s distance necessitates intersection with the scene’s geometry. While basic engines might test intersections with every scene primitive, this becomes inefficient with detailed meshes.
To enhance efficiency, the Bounding Volume Hierarchy (BVH) is used. This structure, formed of Axis Aligned Bounding Boxes (AABBs), simplifies ray-scene intersections. Rather than rays intersecting each triangle, they engage with BVH nodes. Only after a parent node registers a hit does its child node undergo evaluation. This reduces the costly triangle intersection tests to only when an AABB in a leaf node is hit.
GPU-based Motion Matching
GPU compute shader on Motion Matching search
Intro
Traditional Motion matching is CPU-based, and usually only runs on the main character. Our approach uses a GPU-based method to speed up the process and make it more suitable for multi-character motion-matching conditions.
Also, traditional Motionmatching is just to make the character animation look more fluent, but we think that pose match can be used to do personalized animation, that is, a character can choose different types of animation according to the current state, which can make the NPCs in our game more vivid and interesting.
The red box is the part we optimize with GPU compute shader, we put the database data and trajectory data into the buffer to the gpu, and compare the compute shader result in the cpu to get the best pose.
we put the database data and trajectory data into the buffer to the gpu, and compare the compute shader result in the cpu to get the best pose.
Further frame prediction
If we don’t wait for the cpu it will cause the gpu’s Output to lag behind the animation of the current frame, so it needs to be calculated from data sampled in the future to reduce the lag error.
Original Solution:
Current Solution:
5. Time dimension denoize
Also, to reduce dispatch stress, we distribute each dispatch into four buffer and apply prediction on each of them.
**Result for prediction denoize: **
As you can see, the character animation without predicting is inconsistent, and you can see that the character’s footsteps repeat and cross over. The right one with prediction implement works fine.
Database building support
Since we need to have different databases for our characters, a big problem shows up: we don’t have this much animation data. Additionally, most of the data we get can not fit our skeleton. Thus, we need to use MAYA human IK to retarget them. However, there are hundreds of animation data for each database, it is even impossible to manually retarget the animation. Thus, we wrote a Maya plugin to solve this large-scale retarget problem.
Unity-IKFK-Plugin
A dynamic library Unity plugin for FK/IK systems
Intro
A dynamic library Unity plugin leveraging C++ to provide advanced animation capabilities.Implemented robust FK/IK systems,bone and mesh binding, enhancing realistic bone movement in animations.
Feature
Robust FK/IK systems
Limb-based IK
CCD IK
Result
FK
Limb-based IK
CCD IK
Vulkan Grass Rendering
Responsive Real-Time Grass Rendering for General 3D Scenes
Intro
In this project, I developed a grass simulator and renderer using the Vulkan API, drawing inspiration from the paper Responsive Real-Time Grass Rendering for General 3D Scenes. The simulation represents each grass blade with three control points: v0, v1, and v2, facilitating efficient tessellation. The core components encompass a vertex shader for Bezier control point transformations, tessellation shaders for grass geometry generation, and a fragment shader for grass blade shading.
Using a specified gravity direction, D.xyz, and acceleration magnitude, D.w, the environmental gravity gE, is calculated as gE = normalize(D.xyz) * D.w. The front-facing gravity influence on the blade, termed “front gravity”, is gF = (1/4) * ||gE|| * f. The overall gravity acting on the grass blade is then g = gE + gF.
Recovery
The recovery force, bringing the grass blade back to equilibrium, is based on Hooke’s law. It compares the current position of v2 with its initial position, iv2, set at the simulation’s start. Initially, v1 and v2 are aligned at the blade height along the up vector. The recovery forces are then calculated as r = (iv2 - v2) * stiffness.
Wind
The wind’s direction in the simulation is dynamic, defined by windFunc (vec3(2.0, 4.0, 2.0) * sin(totalTime * 0.1)). Grass blades aligned with the wind direction experience a greater impact, represented by the windAlignment term. The cumulative wind force, w, is given by windDirection * windAlignment.
Result
Orientation
When the grass blade’s front face direction is perpendicular to the view vector, it can cause aliasing artifacts due to the blades having no width and appearing smaller than a pixel. To address this, blades are culled using a dot product test checking for perpendicularity between the view vector and the blade’s direction. The threshold for this culling is set at 0.9.
View-Frustum
Blades outside the view-frustum are culled since they won’t be visible in the frame. To ascertain a grass blade’s position in relation to the view-frustum, three points: v0, v2, and m = (1/4)v0 * (1/2)v1 * (1/4)v2) are assessed. If all these points lie outside the view-frustum, the blade is culled.
Distance
For grass blades at significant distances that appear smaller than a pixel, rendering can introduce artifacts. To counter this, blades are culled based on their distance from the camera, similar to orientation culling.
Result
Result
LOD Tessellation
To optimize performance, the tessellation level for a grass blade can be adjusted based on its distance from the camera. Blades farther away require less detail, reducing the need for high tessellation levels.
#if DYNAMIC_LOD
if (dist > 20.0)
LOD = 4;
else if (dist > 15.0)
LOD = 8;
else if (dist > 10.0)
LOD = 12;
else if (dist > 5.0)
LOD = 16;
#endif
Result
Mini-Maya
Basic Maya Functions implementation
Intro
In this project, I built a mirco Maya from scratch with C++ and OpenGL in QT Creator. The final version includes basic functions including:
Mesh manipulation
Catmull-Clark subdivision
Skeleton and skinning
Object loading
A final user interface based on QT GUI is shown below.
Flocking simulation based on the Reynolds Boids algorithm
Intro
In this project, I implemented a flocking simulation based on the Reynolds Boids algorithm, along with two levels of optimization: a uniform grid, and a uniform grid with semi-coherent memory access.
Average Frame Rate & 8 vs 27 Cells (Visualization-Off)
Research
Research Projects
VR Boxing
A HIIT-based VR Boxing Game, received from CHI-Play 2020
Effects of an Immersive Virtual Reality Exergame on University Students
JMIR Serious Games
Virus-Boxing
CHI-Play 2020
Abstract
Physical activity or exercise can improve people’s health and reduce their risk of developing several diseases; most importantly, regular activity can improve the quality of life. However, lack of time is one of the major barriers for people doing exercise. High-intensity interval training (HIIT) can reduce the time required for a healthy exercise regime but also bring similar benefits of regular exercise. We present a boxing-based VR exergame called VirusBoxing to promote physical activity for players. VirusBoxing provides players with a platform for HIIT and empowers them with additional abilities to jab a distant object without the need to aim at it precisely. In this paper, we discuss how we adapted the HIIT protocol and gameplay features to empower players in a VR exergame to give players an efficient, effective, and enjoyable exercise experience.
Effects of an Immersive Virtual Reality Exergame on University Students
JMIR Serious Games
Abstract
Background:
In recent years, there has been an increase in the number of students with depression, anxiety, and perceived stress. A solution that has been increasingly used for improving health and well-being is exergaming. The effects and acceptability of exergames have been studied widely but mostly with older adults. The feasibility and usability of exergames among university students, especially those of immersive virtual reality (iVR) exergames, remain unexplored.
Objective:
This study aimed to explore the feasibility of a 6-week iVR exergame–based intervention in reducing anxiety, depression, and perceived stress among university students and to examine the usability and acceptability of such games.
Methods:
A total of 31 university students were recruited to participate in a 6-week study in which they needed to play a boxing-style iVR exergame called FitXR (FitXR Limited) twice per week (30 minutes per session). Their anxiety (Beck Anxiety Inventory), depression (Beck Depression Inventory-II), and perceived stress (Perceived Stress Scale) levels were measured before and after intervention.
Results:
A total of 15 participants completed the 6-week study. Our results suggested that participants’ mean depression scores decreased significantly from 8.33 (SD 5.98) to 5.40 (SD 5.14) after the intervention (P=.01). In addition, most participants (14/15, 93%) believed that the iVR exergame has good usability. Furthermore, most participants (14/15, 93%) were satisfied with the iVR gameplay experience and would play the iVR exergame again in the future. Of the 15 participants, 11 (73%) would recommend the iVR exergame to their friends.
Conclusions:
The results gained from this study show that the iVR exergame has good usability, is highly acceptable, and has the potential to reduce depression levels among university students.
Join the X-Lab in my sophomore, responsible for HCI related demo development, experiment design, literature review, paper writing.
March 2021
Empathy Computing Lab
Join the ECL in my Junoir, responsible for VR demo development, experiment design.
July 2021
Seasun Game
Gameplay Programmer Intern: Responsible for the development of Gameplay and character animation performance using Unity/C# and Lua. Focused on refining the construction of animation behavior trees and developing robust, reusable behavior tree nodes.
May 2023
Netease Game
Gameplay Programmer Intern: Responsible for the development of Gameplay and animation-related content using Unreal Engine and C++, assisted in optimizing Motionmatching search, enhanced the quality of character interaction animations, and automated the marking process for the climbing system.
Jan 2024
Tencent Game
Animation Research Engineer Intern: Develop an animation system based on IK, role movement, interactive upper logic transformation