显示标签为“TechArt”的博文。显示所有博文
显示标签为“TechArt”的博文。显示所有博文

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年2月5日星期四

Tech Art - Spring - HW4 - Matrix Rendering Transformations

 


Assignment contents: 


Implementation Logic:

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:

This assignment does not require a large amount of analysis. From the provided example file, it is already very clear what we are expected to build. In essence, it is just implementing a set of math operations and visualizing the results, so the overall complexity is not high.

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年11月30日星期日

Tech Art - Week15 - PyQt

 

Result

Screen Shot

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:

  1. 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

  2. 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

  3. 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

  4. 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

2025年11月22日星期六

Tech Art - Week14 - Simple Tool Design & Implementation

 

Result


Assignment Review

As always, before doing any implementation, I first restated the assignment clearly.
In short, we need to read a GeoJSON file, convert it into geometry in Houdini, and assign a different color to each region.


Approach

From reading through the task description, the difficult part of this assignment is not the procedural modeling itself.
The handout even provides example code that shows how to use a Python SOP to create geometry from point data.


The real challenge is how to extract the information we need from the GeoJSON file.
By checking online references and opening the GeoJSON in a text editor, I clarified the overall data structure: each entry contains information such as Feature, Properties, and Geometry, and the geometry can be either a single Polygon or a MultiPolygon.
The most important field is coordinates, which stores the vertex positions of every region.

One thing to pay attention to: in GeoJSON, coordinates are 2D (longitude, latitude), while in Houdini we work in 3D space, so we need to convert them.

Json-Info-Extraction


Once all the necessary information has been read from the GeoJSON file, the rest becomes relatively straightforward.
This assignment is purely about data visualization, and doesn’t involve object interactions or complex behaviors.
As long as the data-processing flow is clean and well structured, it’s easy to keep the overall logic clear.
Based on the assignment prompt and the way we extracted data from the JSON file, I split the whole assignment into four major functional parts to implement.


For the procedural modeling part using a Python SOP, polygons that contain holes require special handling.
We cannot directly create holes using only the Python SOP polygon, so we need to combine it with a Boolean node to fully support all these cases.

Taking “Kyrgyzstan” as an example, this region is of type Polygon and contains a hole in the middle that needs to be cut out.

Polygon-Kyrgyzstan-Hole-Example

Taking “Armenia” as another example, this region is of type MultiPolygon and also has inner areas that must be subtracted as holes.

MultiPolygon-Armenia-Hole-Example

Final Result & Demo



P4V


2025年11月14日星期五

Tech Art - Week13 - Final Project Description

Part I - Exceptions and JSON Input



This assignment is fairly straightforward. First, I need to map out the overall workflow (as shown in the figure), and then derive an accurate naming-format JSON from the UE5 Style Guide on GitHub. Since AI is a great tool, I just gave the link to GPT and had it compile the JSON file for me—let the AI handle the tedious grunt work to maximize efficiency. And also, to the custom rules, 
 It really should write back to the original JSON file, but for convenience during testing I wrote it to a new file insteadAlso, since this assignment doesn't actually involve Houdini's API—it's all just Python—I wrote it directly in a PyCharm project (so the JSON file path is in the same directory as the code; I didn’t use an absolute path).

Json File






Part II. - Final Project Description


Project "What"

Integrate my self-hosted ComfyUI + Hunyuan3D into Houdini 19.5 to build a fast asset iteration pipeline: one-click generation → auto import → auto material hookup. In Houdini, a PySide2 panel lets me enter prompts or drop a reference image to remotely trigger a ComfyUI workflow that outputs GLB models and PNG textures, then automatically builds the network, creates materials, wires textures, and places the asset in the scene for concept and greybox stages. Remote invocation is supported: ComfyUI runs on a home workstation; the client pulls results over the network and adapts them in Houdini.

Project "Why"

  • Faster ideation: compress idea to visual placeholder into minutes for greyboxing, previs, and style exploration.

  • Less repetitive work: auto naming, auto materials, auto folder layout; no manual import or texture wiring.

  • Reuse remote compute: heavy models run on a powerful home PC while the local machine handles interaction and import.

  • Scalable: can extend to half-body → Z-remesh, batch placeholder props, or temporary bridges to Unreal.

Project "How"

Implement Plan

  1. System Flow (high level)

  1. Prepare img2img, txt2img, and text-to-3D workflows on the ComfyUI side (Hunyuan3D 2.x).

  2. Submit jobs from the Houdini panel; ComfyUI queues and executes them.

  3. When complete, the client downloads GLB/OBJ and textures.

  4. Houdini automates: import model, create materials, wire textures, and place into the scene.

  5. Save assets to the project folder.

  1. Remote Networking

  • Preferred: ZeroTier or Tailscale (private networking without router port-forwarding).

  1. Technical Details and Challenges

  • GLB texture embedding: if ComfyUI’s SaveGLB does not embed textures, either output OBJ/FBX with separate textures and rebuild materials in Houdini, or post-process glTF to reference textures.

  • Scale and coordinate system: normalize units (meters/centimeters) and adjust the Up Axis during import.

  • Stability: timeouts, aborted jobs, and JSON parse errors should surface in the UI with retry options.

  • Version differences: support both Houdini 19.5 (PySide2 / Python 3.9) and Houdini 20.5 (PySide2 / Python 3.11).


Reference :
https://zhuanlan.zhihu.com/p/270427440
https://www.youtube.com/watch?v=va8Jkc7o9d4&t=11s
https://github.com/comfyanonymous/ComfyUI/tree/master/script_examples
https://github.com/Tencent-Hunyuan/Hunyuan3D-2.1
https://www.youtube.com/watch?v=MpVsQG6-FM0&t=568s
https://www.bilibili.com/video/BV1Ew411776J/?spm_id_from=333.1387.homepage.video_card.click&vd_source=6375d819a70068bc1dc42d8b1361e0ac

2025年11月7日星期五

Tech Art - Week12 - Class Hierarchy



Analysis

As usual, let’s start with a quick review of the assignment.


This week’s task is fairly straightforward with no major logical hurdles. The main thing to watch out for is the class hierarchy. I sketched the minimal layout as follows: the CSG class goes in CSGModule.py, while the Box and Tube classes go in ShapeModule.py.


One important detail: we use variables t, r, s, and c to store Position, Rotation, Scale, and Color respectively. When you actually modify them, make sure you are updating the node’s internal parameters. This is where __setattr__ helps a lot and greatly simplifies the code. Since __setattr__ is invoked whenever an attribute is set, we just detect changes to t, r, s, and c and then forward those changes to the node’s parameters.


Because this week’s assignment asks you to split classes across different files and call them from a main file, you can simply place those modules into Houdini’s Python library so they can be imported directly.

Example (Houdini 20.5.613)

  1. Find Houdini’s Start Menu folder:

C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Side Effects Software\Houdini 20.5.613
  1. Go to the Python libs directory:

C:\Program Files\Side Effects Software\Houdini 20.5.613\houdini\python3.11libs
  1. Put the files there:

CSGModule.py ShapeModule.py
  1. In your Houdini Python script, import the classes:

from ShapeModule import *

Note: I didn’t import CSGModule.py explicitly here because it is already imported inside ShapeModule.py, so there’s no need to import it again.

2025年11月1日星期六

Tech Art - Week11 - CSG Object Calculator

Confirm the Assignment

Before diving into the analysis, it’s essential to review the full assignment requirements.

Analysis

After analyzing the prompt, we can outline the overall framework for the CSG Object Calculator.

Items Outside Core Logic

We can note there are two requirements that sit outside the core logic, and they’re not difficult to implement.

__str__ is primarily used to override what gets printed when you print an object, typically turning it into something human-readable. For example, you can override it so printing becomes CSG<Label> for easy reading.

__setattr__ is invoked when creating or modifying member attributes in a class. Since the prompt asks us to force all spheres to be polygonal, we only need to check that the created object is indeed a sphere and then switch its type to polygon.

Final Result


2025年10月25日星期六

Tech Art - Week10 - Army of Darkness


Anlysis

Before explaining the approach, let’s first confirm our assignment requirements.

Assignment Requirements

The assignment brief is already quite clear. In the previous assignment, we essentially resolved the common hurdles when using the basic Houdini Python API, and this time we hardly need any new APIs. Therefore, this post will mainly explain the implementation approach.

Because we ultimately want the soldiers’ formation to be neat—and preferably a square—we should analyze the problem first. The formula can be split into two parts: compute the Unit first, then compute the Soldiers Number. Our implementation follows the same idea.

Decompose The Formula

Step 1: Generate the Unit. Its geometric meaning is straightforward: a formation with Base rows by Base columns of soldiers.

Step 2: Since we want the final result to be organized as an array of Units with M rows by N columns, we need a way to determine how many Units are required to assemble the final square formation. The answer is intuitive:


Once we obtain the value of Total Units, we naturally have M × N = Total Units. We want the final array to be as close to a square as possible (for better aesthetics), so M and N should be as close as they can be, and both will be near √(Total Units). Ideally, Total Units has an integer square root.

Since we already know Unit = Base², we can conclude that Total Units can indeed yield an integer square root.


At this point, the basic algorithmic idea is clear: implement it according to the assignment requirements and generate the result. 


PS: I also used a Match Size node to ensure that all the objects I create sit above the plane where Y = 0




Tips: When implementing this in Houdini, I like to treat both “Soldier” and “Unit” as discrete entities. In my implementation, one “Geo” serves as a “Unit,” and each “Shape” inside that “Geo” is treated as a “Soldier.” This hierarchy makes the overall implementation clearer.