2026年7月28日星期二
Common Art - Summer- Final Sprint
2026年7月14日星期二
Common Art - Summer- Sprint #5
Introduction
This sprint was slightly affected by illness. Fortunately, most of my assigned work had already been completed, so the overall impact was manageable. I also coordinated the integration with Rag and Jules, and the water effect has now been refined to a good state. The next step will likely be to sync with the lighting artist, as the scene currently appears somewhat too dark.
During this sprint, I also fixed a bug in the procedural sparkle effect: the sparkles were moving in an overly uniform and predictable pattern. This has now been corrected, and it turned out to be a minor issue.
Water
2026年6月30日星期二
Common Art - Summer- Sprint #4
Introduction
Since I was not assigned a new task for this sprint, this round focused on refining the result from the previous sprint and adding more detail. My current goal is to keep polishing the overall effect.
Water
Caustics
Compared with the last update, I found one issue in the water caustics: during certain moments, the effect would become noticeably brighter because of the opposing UV flow. I adjusted several parameters to prevent that brightness spike, and after the refinement the caustics now feel much smoother.
Waterfall
Splash
Before the last class, my main focus was researching VFX in Niagara. Since I have relatively little experience creating VFX, I spent some time studying the workflow. I have now created a splashing-water effect and added a simple mist layer. The current result already looks quite good, but I did not have time to build the scaling logic yet. I will decide whether to add that feature in the next sprint based on what the effect needs.
P4V
2026年6月17日星期三
Common Art - Summer- Sprint #3
General
Since I will soon return to China for an internship, this sprint also included many tasks that were originally planned for later sprints, so the overall team schedule would not be affected.
Building on the previous sprint, I fully completed the water material and waterfall effects.
Water
Caustics
The main idea was to use a fake caustics texture, which I created in Substance Designer.
I then sampled the texture using the XY coordinates of the world-space position reconstructed from depth. Since the water itself does not write to depth, I used the reconstructed world position from the scene depth to sample the caustics texture. By adding opposing UV flows, I was able to create a convincing underwater caustics effect.
The most difficult part was finding a reliable way to reconstruct world-space position from depth in UE5. Unreal and Unity handle this differently, so I spent quite a bit of time working through the problem.
Magic Spark
To better match the overall scene, I also added a subtle fake particle effect to the water. Our scene already has a fairly dense particle atmosphere, so this helped the water sit more naturally in the environment. The effect is made with two Perlin Noise textures flowing in opposite directions, followed by a Step operation.
Matcap
Although it may be hard to see clearly in the screenshots, I wanted the water to retain some ambient lighting in darker environments. UE's default physically based ambient lighting was too dark for this stylized water style, so I added a Matcap texture to provide a bit of extra environmental light.
Waterfall
Before starting the material work, I first quickly modeled a waterfall mesh plane in Blender. To keep the edges transparent, I painted vertex colors and used them as a simple mask for edge transparency.
The main body of the waterfall was built with a different approach from the water material. I did not use the Single Layer Water shading model here. A waterfall usually behaves more like a thin sheet, and it generally does not have enough depth variation to drive shallow-to-deep color changes in the same way as a water surface. Using Transparent Lit made the result more direct and easier to control.
The most important part of the waterfall is the foam. The core approach is UV flow, UV distortion, and applying Step operations to noise textures to create the flowing stripe patterns I wanted. The foam system mainly includes Main Foam, Detail Foam, Waterline, and Edge Foam. Edge Foam is generated around objects intersecting with the waterfall, and its logic is similar to shoreline waves: it is calculated based on the distance to the nearest surface.
I also added some Magic Spark to the waterfall, but with a different implementation. In this case, I baked the sparkle pattern into a texture and animated it with UV flow.
There is also a Waterfall Wave effect, which is a fake effect for the pool below the waterfall: a wave spreading outward from the impact area. The idea is quite similar to the other effects, using UV flow and UV distortion to manipulate noise and produce the final result.
The most time-consuming parts were parameter tuning and creating a large number of noise textures.
Final
P4V
2026年6月14日星期日
Tech Art - Summer- Initial Overview of VFX Lecture Content
The topic of this lecture is stylized face shadow, with a focus on one practical application of SDF, or Signed Distance Field, in stylized rendering. The goal is not to create fully physically accurate lighting. Instead, I want the shadow on the character's face to respond to the light direction while still staying clean, stable, and readable. Realistic lighting usually follows geometry, material, and light behavior, but stylized face lighting cares more about a designed shadow shape. In other words, the shadow should feel closer to an illustration, instead of being completely controlled by small details on the model surface.
In the first part, I will briefly review basic Toon Shading and explain why it often fails on the face. Hard Threshold and Soft Threshold methods can create a clear light and shadow separation, but the face has many complex forms. Areas like the nose, eye socket, and cheek can easily create broken or unstable shadow shapes. For anime-style or illustration-style characters, this result is often not controllable enough and not very artist-friendly.
After that, I will compare several possible approaches, including Proxy Mesh Normals, Edited Topology and Normals, and a more direct Edited Normals workflow. These methods can all improve face lighting to some degree, but they have different costs in terms of control, maintenance, and visual stability. The main focus of the lecture will then move to SDF Shadow, because it allows us to separate the shadow shape from pure geometry-based lighting and let artists define a cleaner shadow boundary through texture.
The core idea of SDF is that each pixel stores more than a black or white mask value. It stores the distance to the nearest boundary, and also which side of the boundary the pixel is on. With this, a simple binary mask can become a continuous threshold map. Once this map is used in the shader, we can sample the Face SDF Shadow Threshold Map based on the light direction, so the shadow can transition between different directions while keeping the overall shape readable.
The final part of the lecture will explain how this texture is generated. The workflow starts by drawing binary masks for different shadow states, converting them into SDF maps, calculating intermediate transition textures, and then combining those transitions into the final threshold map used by the shader. This section is closer to the actual production workflow, and it also explains why the texture can record how the shadow shape changes over time or direction.
If time allows, I will also briefly introduce several ways to calculate SDF maps, including the most direct but slow Brute Force method, the more practical CPU-based 8SSEDT method, and JFA, which is more suitable for parallel processing on the GPU. Overall, this lecture starts from a visual target and follows the process through solution choice, shader usage, and texture generation, showing the Tech Art workflow behind a stylized rendering effect.
2026年6月3日星期三
Common Art - Summer- Sprint #2
General
At the beginning of this sprint, we finalized the task distribution for the team.
My main responsibility on this cinematic project is to develop the water and waterfall systems.
I am also supporting Gabe S. by using Substance Designer to create several textures.
For this sprint, my primary focus is still the water work.
Since I was sick last week, I have been working hard this week to catch up with the schedule. At this point, I have completed the first version of the water shader/system.
Meetings and Documentation
At the beginning of this week, all of the Tech Art and 3D Art team members had a longer meeting to define the overall art style for the project. As a technical artist, one of my responsibilities was to help gather environment-related artist references.
Water
Since I am responsible for the water, I looked for several useful tutorials and breakdowns before starting development.
The most interesting reference I found was this one:
Stylized Water in UE5 Breakdown
This artist shared several techniques on X for creating stylized water in Unreal Engine.
His breakdown was very helpful for me.
He mentioned that he learned a lot from the following video, and I did as well:
How scrolling textures gave Super Mario Galaxy 2 its charm
This video explains many old-school water techniques used in Super Mario Galaxy. Even though these techniques are older, they are still valuable references today.
I recreated some of these ideas in Unreal. The current implementation is still simple, but after further refinement, some of these techniques should be useful for version 2 of my water system.
Because of the limited time for this version, my main goal was to establish the foundation and complete the basic rendering result.
The features and textures currently completed are:
Refraction and reflection effects
Adjustable shallow/deep water control
WPO waves + recalculated normals
Stylized shoreline wave effect
Water normal texture creation
Foam noise texture creation
The current water effect is partially compatible with Unreal's Water plugin. However, since the final environment will be built around an island, Unreal's official Water plugin may not always be the most convenient solution for our needs. Because of that, I implemented the wave motion using World Position Offset.
For the Gerstner wave implementation, I referenced this article.
Although the article is written for Unity, the logic can still be adapted to Unreal as long as the coordinate system differences are handled correctly. Unreal and Unity are both left-handed coordinate systems, but Unreal is Z-up while Unity is Y-up.
In the next version, I plan to start exploring:
Caustics effect
Sparkle/highlight effect
More stylized parameter controls
The goal is to push the water further toward a more stylized and cartoony look.
P4V
2026年5月17日星期日
Common Art - Summer- Sprint #1
VFX
There were not many tasks assigned to the Technical Artists during this sprint. My first task was to make sure the VFX created last semester could run reliably in our project. I organized and moved the VFX into the project, simplified the exposed parameters, and improved the adjustment workflow so that all artists can quickly use the effect.
Master Materials
In addition, Raghavendra and I were responsible for creating the Master Materials. The basic Master Materials have now all been integrated into the project.
Emissive Breathing
After finishing the basic setup, I also worked on a special technical art experiment. I created a GPU-based timer that does not rely on CPU control, which makes it very performance-friendly, and integrated it into the emissive material. This allows artists to freely adjust the emissive breathing effect, including customizing the glow duration and the interval between glow cycles.
2026年2月26日星期四
Common Art - Spring - Lighting Workshop Module 3
Final
Ref
Analysis + Creative process
My creative intent for this piece is actually not to make a heavily stylized environment. Instead, I want to create a natural, fresh atmosphere with a subtle sense of Chinese philosophy. For this “Lost Temple” scene, I’m aiming for an early-morning sunrise in a mountain ruin, when the mist hasn’t fully lifted yet. The fog won’t be exaggerated or overly stylized—I just want to convey a calm, everyday morning in a forgotten temple.
In the first image, I placed the entrance of the lost temple. Its worn-down, decayed state suggests that it’s an ancient place with no people around. The overall environment is relatively dark, but the brightness at the entrance is meant to draw the viewer’s attention—my goal is to guide the audience into the world of the scene through this inviting focal point.
In the second image, you can see a strong backlit setup. This is meant to communicate the time of day and the overall lighting condition of the environment. The third image reinforces what the first two are establishing: the ruined atmosphere and the sunrise timing.
The fourth image is the core shot. You can see that I didn’t add an overly dramatic top light to “glorify” the Buddha, because this is a damaged, weathered statue. I also don’t want the scene to feel overly artistic or theatrical. What I want to express is a sense of quiet plainness—despite the decay, the Buddha returns to simplicity and blends into the everyday world.
That said, I still tried to suggest a sense of sacredness, even if it’s subtle (because I don’t want it to be too exaggerated). I added a warmer rim light on the Buddha, and compositionally I framed the statue from the right looking toward the left. So in the lighting, I made a small deliberate choice: cooler light on the left side and warmer light on the right side, to hint at a gentle, warm radiance.
You can also see that I added fog to the environment. Unreal’s built-in fog effects couldn’t achieve the kind of sunrise atmosphere I wanted—where the mist hasn’t fully lifted yet—so I implemented my own volumetric fog to create that mood.
2026年2月5日星期四
Tech Art - Spring - HW4 - Matrix Rendering Transformations
Assignment contents:
For this assignment, although my previous homework provided a solid foundation, I still refactored my Matrix4x4 / Vector4 math system to make it cleaner and more complete for this mini-renderer. This includes matrix multiplication, matrix–vector multiplication, transpose, and the w-component convention to distinguish points vs. directions. On top of that, I built the full pipeline for TRS, View, Projection, and the mapping from Clip/NDC space to pixel coordinates. To validate the implementation, I created two tests (Test and Test_Advanced) and then visualized the final result.
Test (Direct verification using the assignment parameters)
In the first test, I strictly used the parameters provided by the assignment to construct and print:-
World (TRS): W = T * R * S, with rotation composed as R = Rz * Ry * Rx
-
View: V = R^T * T(-C) (the inverse of the camera’s world transform)
-
Projection: both the Orthographic and Perspective projection matrices
-
Final: MVP = P * V * W
Then, for the 8 vertices of the unit cube, I applied the full chain:
clip = MVP * local_point
ndc = clip / w
screen/pixel mapping
and printed each vertex’s local / clip / ndc / pixel values for inspection.
Test_Advanced (A more standard approach with a Camera class)
After the first test worked, I implemented an additional Camera class to better match a standard graphics pipeline structure. This class encapsulates camera parameters and generates the corresponding matrices (especially V and P, along with resolution/frustum-related setup). In Test_Advanced, I regenerated V and P through the Camera class and combined them with the same W to form:MVP = P * V * W
I then repeated the same vertex transformation and pixel mapping process to ensure both approaches produced consistent results.
Visualization (matplotlib is only used for drawing)
To present the final result, I used matplotlib to draw the points and edges after they were projected into pixel space (scatter/plot for points and line segments, plus axis limits and grid display). Matplotlib is only used for rendering the lines/points— all computations (matrix construction, vertex transforms, perspective divide, and NDC-to-pixel mapping) are performed entirely by my own code. Matplotlib does not participate in any of the math; it simply visualizes the pixel coordinates I computed.P4V:
I wrote the code in PyCharm. In the PyCharm project, I set up a virtual environment and installed the required libraries.
2026年2月2日星期一
Tech Art - Spring - HW3 - Matrix Calculator 2
Assignment contents:
Analysis:
This week’s tasks were fairly straightforward. The first part was to implement the matrix transformation that moves a model’s vertices from model space to world space. The second part was to build the interface for last week’s matrix calculator.
For Task 1, Nitin already explained the concept very clearly in class, so I won’t repeat it here. For Task 2, I tried to stay as faithful as possible to my previous UI design, but for practicality I also added an extra button under the Result section. It lets you copy the result matrix back into Matrix A, which makes chaining multiple operations much more convenient.
P4V:
2026年1月26日星期一
Tech Art - Spring - HW2 - Matrix Calculator

Assignment contents:
Analysis:
The code portion of this assignment is relatively straightforward—it's essentially an implementation of basic matrix calculations. My overall approach and structure are roughly as follows:
Core data structure: The matrix is stored as a 4×4 two-dimensional list in row-major order, which makes row/column access and arithmetic operations straightforward.
Construction & creation: There are two ways to create a matrix: if no data is provided, it defaults to a zero matrix; if a 4×4 set of rows is provided, the input is validated first and then all values are converted to floats to keep computations consistent. The class also provides static helpers like Zero, Identity, and FromRows to quickly generate common matrices.
Input validation: During construction, the code checks that the input is truly 4×4 and that every element is numeric, so errors are caught early and later operations don’t fail in confusing ways.
Display output: A formatted output function prints the matrix with a fixed number of decimal places and aligns columns by computing each column’s width, making the result easier to read.
Math features: The class implements essential matrix operations: addition, subtraction, scalar multiplication, matrix multiplication (using the standard row-by-column dot product rule), and transpose (swapping rows and columns). It supports both explicit method calls and operator-based usage for convenience.
Testing & verification: A simple test routine at the bottom of the file constructs example matrices and runs each feature in sequence to confirm the outputs and results behave as expected.
UI Design:
P4V:
2026年1月14日星期三
Tech Art - Spring - HW1 - Vector Calculator
Result:
Assignment contents:
Analysis:
The only detail that needs special attention is that the vectors use homogeneous coordinates: w = 0 represents a direction vector, and w = 1 represents a point. As long as you handle the arithmetic rules between points and direction vectors correctly, everything will be fine. That mainly means you should separate cases and apply the correct semantics for each operation.
For example:
-
Addition
-
Point + Direction = Point
(translate a point by a direction) -
Direction + Direction = Direction
(vector addition) -
Point + Point = Undefined / Not Allowed
(adding two positions usually has no geometric meaning)
-
-
Subtraction
-
Point − Point = Direction
(direction from the second point to the first point) -
Point − Direction = Point
(move the point backward along the direction) -
Direction − Direction = Direction
(vector difference) -
Direction − Point = Undefined / Not Allowed
(subtracting a position from a direction is not meaningful)
-
-
Scalar multiplication
-
Direction × Scalar = Direction
(scale direction magnitude) -
Point × Scalar = Typically Not Allowed
(scaling a point is not a standard affine operation unless you explicitly define an origin-based scaling rule; most pipelines treat this as undefined)
-
-
Dot product
-
Only defined for Direction · Direction → float
-
If a point is involved, you should either reject it or explicitly interpret it as a direction from the origin (but that changes meaning, so rejecting is usually cleaner for assignments).
-
-
Cross product
-
Only defined for Direction × Direction → Direction
-
Point involvement should be rejected.
-
-
Unitize (~)
-
Only defined for Direction → Direction
-
Unitizing a point should be rejected.
-
-
Angle between
-
Only defined for Direction vs Direction → float (degrees)
-
If either is zero-length, no valid solution.
P4V:
2025年12月2日星期二
Tech Art Fall Project
Comfy Houdini
I really like Houdini as a tool. It’s extremely reusable, and I once saw someone doing something similar on Bilibili, but I felt it wasn’t convenient enough. So I wanted to build my own version to speed up the workflows I already use. PCG workflows actually match ComfyUI’s workflow style very well. If we can run some AI nodes directly inside Houdini and combine them with Houdini’s native nodes, it clearly can boost our efficiency and let us create many different workflows. Especially with Houdini 21.0, the new COP is very powerful — in some cases it can even replace Substance Designer for generating certain procedural textures.
AI is really good at accelerating traditional pipelines, especially for concept design, where it can quickly generate a lot of ideas and help open up your thinking. For 3D, AI is already completely usable for distant background assets, and some of the models generated by Hunyuan 3.0 are almost good enough for mid-ground use. The speed of progress is really fast. As a tool, AI is honestly great. I’m really looking forward to Tencent releasing 3.0 so I can deploy it locally and play with it (still wishing for it).
At the same time, because ComfyUI’s official API examples are already based on sending data over the network, I combined it with Tailscale to set up easy remote calls. Having my own little AI render farm feels really nice — I didn’t expect the knowledge I learned from game streaming remote setups to be useful here too.
2025年12月1日星期一
Common Art - Week 15 - Final - 'A' Stage
Terrain Texture V2
| Substance Designer GrassV2 |
Based on the feedback from Stage B, I reworked both the grass and sand materials.
For the sand, I mainly lowered the saturation and brightness so it wouldn’t look so yellow.
For the grass, I pushed the style further and basically rebuilt the material from scratch, which took quite a bit more time.
Combined with the new grass billboard setup I made later, the updated grass material now gives a very nice overall grass look.
The Modified Parts
| Trees |
| Terrain Blending |
Now each tree no longer points along the landscape normal, but instead points straight up.
Also following the last round of suggestions, I researched how to achieve terrain blending in Unreal.
This setup mainly uses Virtual Textures. To make the terrain blend, I use two textures:
-
One texture stores the landscape height.
-
One texture stores the landscape material.
Once I have these two pieces of information, in the trunk material I compare the world-space vertex Z value with the landscape height, then use triplanar mapping to sample the landscape texture.
This gives me the terrain–trunk blending effect.
Grass V2
| The Reference "Sky" |
Again, based on the Stage B feedback, I decided to rebuild our grass and switch to another approach.
This time I collected references from Sky (a game made by the same team as Journey) and recreated a similar grass look.
I implemented billboard grass (always facing the camera) together with a wind system, and they work well.
The wind effect feels very soft and pleasant: each clump of grass sways gently in a regular rhythm.
Since I also have access to the landscape color information, I added that into the grass as well.
For each grass pivot in world space, I sample the landscape color and use it to tint the blades, so every grass clump matches the color of the terrain under it.
| Grass V2 Test |
Apple Tree & Bushes
| Bushes |
Finally, I also created an apple tree and some cute stylized bushes.
The apples on the tree use the same wind system as the leaves, so they also have a slight secondary motion and sway gently with the foliage.
The bushes are made almost the same way as the tree leaves, so I won’t repeat the process here.
P4V
2025年11月30日星期日
Tech Art - Week15 - PyQt
Result
Task Review
Before doing any analysis, I first restated the assignment requirements.
In short, based on the NameGenerator we implemented in HW12, we now need to build a GUI on top of it to make it much easier to use.
| Requirements Overview |
Analysis
Because this homework involves PyQt GUI development, the natural tool to think of is Qt Designer.
However, since the goal of this assignment is to get used to writing PyQt code by hand, I only used Qt Designer at the beginning as a layout sketching tool to clarify the UI structure. I did not use its auto-generated UI code.
| Qt Designer Interface |
In HW12 we already finished almost all of the core naming logic.
For better UI support, I only added a small helper function to check whether a category has a Default rule.
So the main focus of this homework is how to design and implement the GUI. PyQt itself is already quite straightforward to use, so instead of explaining every low-level detail, I will just briefly summarize my GUI design.
Overall, I divided the window into three main vertical regions (left / center / right), plus a menu bar and a status bar, so that each part of the workflow is clearly separated:
-
Left: Rules & Settings Panel
-
Shows the path of the currently loaded JSON rules file
-
Provides a “Load Rules…” button
-
Provides a Verbose checkbox and a status label, used to switch between simple history and verbose history display modes
-
-
Center: Input Panel
-
A Category combo box for choosing the main asset category
-
An Asset Type combo box for choosing a specific subtype, or selecting
[Default]to use the category’s default rule -
A Base Name line edit for entering the base asset name
-
A “Generate Name” button which calls
NameGenerator.generate_name()to generate the final asset name
-
-
Right: Result & History Panel
-
At the top, a read-only field that displays the last generated name, making it easy to copy
-
In the middle, a history list. Depending on whether Verbose is checked, it shows either the simple history list or the verbose version (with full details)
-
At the bottom, a Quit button. Clicking it triggers the close event and pops up a confirmation dialog before exiting
-
-
Menu Bar & Status Bar
-
The menu bar provides basic entries such as File (load rules / exit) and Help (About)
-
The status bar is used to give real-time feedback: for example, whether the rules file was loaded successfully or failed, and whether a name was generated successfully
-
The overall idea is: reuse all the naming logic from HW12’s NameGenerator, and only add a clean GUI layer on top.
The GUI breaks the pipeline “load rules → choose type → enter base name → show result/history” into clear visual sections, so that users can complete the same workflow without writing any code.
I also implemented a simple light-gray theme.
There is no complex visual design here—since this is a small tool, I think a clean and minimal look is the best choice.
Video Demo
P4V
| P4V |