webgl fishing simulator project
기본적으로 모든 drawtype은 Triangle로
hierarchyManager가 frameMatrix를 전파하여 사용
모든 매니저들은 rootManager에서 접근 가능함.
data의 prefabs/robotArm.js와 animators/robotArm.js를 보면 예시가 되어있는데, Animator의 animationData는 gemini한테
아래 코드는 내가 webgl로 만든 로봇팔이야
```
class RobotArm extends PrefabObject {
init() {
this.animator = new RobotArmAnimator(this);
const _box = new BoxPrimitive([
[-0.1, 0.5, 0.025],
[0.1, 0.5, 0.025],
[0.1, -0.5, 0.025],
[-0.1, -0.5, 0.025],
[-0.1, 0.5, -0.025],
[0.1, 0.5, -0.025],
[0.1, -0.5, -0.025],
[-0.1, -0.5, -0.025],
]);
const _arm = new HierarchyObject([_box], new Transform());
_arm.children = {
innerArm: new HierarchyObject(
[_box],
new Transform({
position: vec3(0, 1, 0),
rotation: vec3(0, 0, 30),
anchor: vec3(0, 0.5, 0),
})
),
};
_arm.children["innerArm"].children = {
innerArm: new HierarchyObject(
[_box],
new Transform({
position: vec3(0, 1, 0),
rotation: vec3(0, 0, 30),
anchor: vec3(0, 0.5, 0),
})
),
};
this.children = {
arm: _arm,
};
}
}
```
위 계층적 구조를 가지고 있는 로봇팔이 자연스럽게 좌우로 흔들리는 애니메이션을 만들 생각이거든?
살짝 bvh파일처럼 해석될 수 있는 json 형식을 아래와 같이 정의했어
```
여기에다가는
(new RobotArm()).getAnimationFrameFormat()
의 결과값을 넣으면 된다.
```
값을 초기상태로 60 프래임짜리 애니메이션을 6초 정도 만들고 싶은데 JS로 위와 같은 형식의 배열을 생성할 수 있는 코드를 짜줘
이때 딥카피를 하게되면 Transform이 제대로 초기화가 되지 않아서 하면 안돼
그리고 필요한 함수들은 전부 정의가 되어있어
처럼 물어보면 찍어준다. (2.5 pro에서 테스트해봄)
fishing.html의 main 부분이랑 objects/hierarchyObject.js, data/prefabs/robotArm.js 부분만 참고해서 보면 될 듯
밑에는 할 작업들인데 순서는 상관없고 매번 브랜치를 하나씩 파서 작업하면 좋을듯
rootManager.canvasManager.lightAmbient = vec4(0.2, 0.2, 0.2, 1.0)
rootManager.canvasManager.lightingSync()
처럼 하면 됨.
아니면 colorManager나 textureManager같은거 만들어도 되고
내생각엔 HierarchyObject 클래스에 color나 texture 필드를 추가해서 만들면 될 것 같음
fishing.html의 마지막에 mouse scirpt가 있는데 여기에 추가하면 될듯
handleMouseDown에 e.button === 1인 경우로 두고
적당히 primitives.js에 정리하면 될듯
이 프로젝트는 WebGL을 사용하여 계층 구조를 가진 3D 객체를 렌더링하는 방법을 보여줍니다. 부모-자식 관계를 가진 객체를 정의할 수 있으며, 부모 객체에 적용된 변환(이동, 회전, 크기 조절)은 자식 객체에도 동일하게 영향을 미칩니다. 렌더링에는 Blinn-Phong 조명 모델이 사용됩니다.
- 계층적 씬 그래프: 객체들을 중첩하여 계층 구조로 관리합니다.
- 변환 컴포넌트: 각 객체는 위치, 회전(앵커 포인트 지정 가능), 크기를 관리하는
Transform컴포넌트를 가집니다. 변환은 자식에게 자동으로 전파됩니다. - 기본 도형:
QuadPrimitive(사각형),BoxPrimitive(육면체)와 같은 기본 도형을 제공합니다. - 프리팹 시스템:
RobotArm과 같이 복잡한 객체를 재사용 가능한 프리팹으로 정의할 수 있습니다. - WebGL 렌더링: 커스텀 버텍스 및 프래그먼트 셰이더를 사용합니다.
- Blinn-Phong 조명: 버텍스 셰이더에서 기본적인 조명 계산을 수행합니다.
- 상호작용 컨트롤:
- 조명 위치 조절
- 카메라 제어 (eye, at, up 벡터) 및 프리셋 (정면, 측면, 상단) 제공
- 마우스 드래그를 통한 카메라 이동
main.html: 캔버스, UI 컨트롤, 셰이더 설정 및 WebGL 애플리케이션 초기화.src/components/:primitive.js: 기본 도형(PrimitiveBase,QuadPrimitive,BoxPrimitive) 정의.transform.js: 객체 변환 및 행렬 계산을 위한Transform클래스.
src/objects/:hierarchyObject.js: 씬 계층 내 객체의 핵심 클래스. 자식, 프리미티브, 변환 관리 및 재귀적 드로잉 처리.prefabObject.js: 프리팹 객체 생성을 위한 기본 클래스.
src/data/prefabs/robotArm.js:RobotArm프리팹 정의 (계층 구조 예시).src/managers/: (추정)RootManager,CanvasManager,CameraManager등 애플리케이션 관리 클래스.- 셰이더 (main.html 내): 버텍스 변환 및 조명 계산(버텍스 셰이더), 색상 적용(프래그먼트 셰이더).
- 씬 객체의 기본 단위.
- 자신의 지역 변환(
transform)과 부모로부터 전달받은 변환을 결합하여 최종 월드 변환을 계산. drawRecursively(부모_월드_행렬):- 자신의 최종 월드 행렬 계산:
부모_월드_행렬 * 자신의_로컬_변환_행렬. - 자신의 프리미티브(도형)를
draw()메소드를 통해 그림. - 각 자식 객체에 대해
drawRecursively()를 재귀적으로 호출하며, 자신의 최종 월드 행렬을부모_월드_행렬로 전달.
- 자신의 최종 월드 행렬 계산:
draw(부모_월드_행렬):- 자신의 최종 모델 행렬을 계산하여 셰이더에 전달.
- 자신의 정점 및 법선 데이터를 WebGL 버퍼에 업로드.
gl.drawArrays()호출하여 렌더링.
- 객체의 로컬 위치, 회전, 크기 및 회전 기준점(
anchor)을 관리. - 이 값들이 변경되면 자동으로 모델 행렬(
modelMat)을 갱신.
- 초기화: WebGL 컨텍스트, 셰이더, 버퍼 등을 설정하고,
RobotArm과 같은 프리팹 객체를 생성하여 씬 그래프에 추가. - 렌더 호출:
canvasManager.render()가 호출되면, 캔버스를 지우고 카메라/조명 등 전역 상태 설정 후, 루트 객체의drawRecursively()를 호출하며 렌더링 시작. - 재귀적 드로잉 (
HierarchyObject.drawRecursively()):- 각 객체는 부모로부터 받은 행렬과 자신의 로컬 변환 행렬을 곱해 현재 자신의 월드 행렬을 계산.
- 자신의 도형을 그리고, 계산된 월드 행렬을 자식 객체에게 전달하며 재귀적으로
drawRecursively()를 호출.
- 셰이더 실행: 각 객체의 정점 데이터는 버텍스 셰이더에서 변환 및 조명 계산 후, 프래그먼트 셰이더에서 최종 색상이 결정되어 화면에 그려짐.
- 로컬 웹 서버를 사용하여 파일들을 호스팅합니다. (브라우저 보안 정책)
main.html에 명시된 경로에 맞게 모든 JavaScript 파일(primitive.js,transform.js등) 및Common/디렉토리의 유틸리티 스크립트를 배치합니다.- 웹 서버를 통해
main.html파일을 엽니다.
graph TD
A[main.html / RootManager 초기화] --> B(WebGL 캔버스 및 셰이더 설정);
B --> C{RobotArm 프리팹 생성};
C -- RobotArm.init() --> D[팔 계층 구조 빌드: HierarchyObject 자식들 + BoxPrimitives 및 Transforms];
A --> E(카메라/조명 UI 이벤트 리스너 설정);
subgraph RenderLoop [최초 로드 또는 UI 변경 시 트리거]
F[CanvasManager.render()] --> G[전역 유니폼 설정: View, Projection, Light];
G --> H[rootObject.drawRecursively(단위 행렬)];
end
subgraph RecursiveDraw [HierarchyObject.drawRecursively(부모_행렬)]
I[현재_월드_행렬 = 부모_행렬 * 로컬_Transform.modelMat 계산] --> J[Self.draw(부모_행렬)];
J --> K[현재_월드_행렬을 uModelMat으로 셰이더에 전송];
K --> L[자신의 프리미티브 정점/법선 데이터 바인딩 및 버퍼링];
L --> M[gl.drawArrays()];
I --> N{각 자식 객체에 대해};
N -- Yes --> O[ChildObject.drawRecursively(현재_월드_행렬)];
N -- No --> P[현재 분기 종료];
O --> RecursiveDraw;
end
M --> Q[버텍스 셰이더: 정점 변환, 조명 계산];
Q --> R[프래그먼트 셰이더: 색상 적용];
R --> S[캔버스에 표시];
E -- 사용자 상호작용 --> F;
요약 안된 부분
This project demonstrates rendering hierarchical 3D objects using WebGL. It supports defining objects with parent-child relationships, where transformations (translation, rotation, scale) applied to a parent object also affect its children. The rendering includes Blinn-Phong lighting.
- Hierarchical Scene Graph: Objects can be nested within each other.
- Transformation Component: Each object has a
Transformcomponent managing its position, rotation (with optional anchor point), and scale. Transformations are automatically propagated to children. - Geometric Primitives: Includes
QuadPrimitiveandBoxPrimitiveas basic building blocks. - Prefab System: Allows defining complex objects like
RobotArmas reusable prefabs. - WebGL Rendering: Uses custom vertex and fragment shaders for rendering.
- Blinn-Phong Lighting: Implements basic lighting calculations in the vertex shader.
- Interactive Controls:
- Adjust light position.
- Control camera (eye, at, up vectors) with presets (front, side, top).
- Mouse-driven camera movement (click and drag on the canvas).
main.html: The main HTML file that sets up the canvas, UI controls, shaders, and initializes the WebGL application.src/components/primitive.js: Defines base classes for geometric primitives (PrimitiveBase,QuadPrimitive,BoxPrimitive).src/components/transform.js: Defines theTransformclass for handling object transformations and matrix calculations.src/objects/hierarchyObject.js: The core class for objects in the scene hierarchy. Manages children, primitives, and its own transform. Handles recursive drawing.src/objects/prefabObject.js: A base class for creating predefined complex objects, extendingHierarchyObject.src/data/prefabs/robotArm.js: Defines theRobotArmprefab, showcasing a hierarchical structure.src/managers/: (Assumed based onmain.htmland common practice)rootManager.js: Manages the overall application state and object hierarchy.canvasManager.js: Handles WebGL canvas setup, shader compilation, buffer management, and the main render loop.cameraManager.js: Manages camera properties and view matrix.animationManager.js: (Placeholder/Future) Intended for managing animations.
Common/: Contains utility scripts likewebgl-utils.js,initShaders.js, andMV.js(likely a matrix/vector library).- Vertex Shader (in
main.html): Handles vertex transformation and Blinn-Phong lighting calculations. - Fragment Shader (in
main.html): Applies the calculated color to fragments.
- Responsible for defining the raw geometry (vertices and normals) of a shape.
QuadPrimitive: Creates a 2D quad (composed of two triangles).BoxPrimitive: Creates a 3D box (composed of sixQuadPrimitives).
- Manages an object's local position, rotation (Euler angles), and scale.
- Includes an
anchorproperty for specifying a rotation pivot other than the object's origin. - Automatically computes and updates its
modelMat(local model matrix) when transform properties change. - The
rotateMathelper function is used to create rotation matrices, handling rotation around an arbitrary fixed point.
- The fundamental building block for scene objects.
parent: A reference to its parentHierarchyObject.children: A dictionary of named childHierarchyObjects.transform: An instance of theTransformclass for its local transformations._primitives: An array ofPrimitiveBaseinstances that make up this object's geometry._mergedVertices&_mergedNormals: Aggregated vertex and normal data from its_primitives.drawRecursively(parentsFrameMat):- Calculates its own world matrix by multiplying
parentsFrameMatwith its localtransform.modelMat. - Calls its
draw()method to render its own primitives. - Recursively calls
drawRecursively()on all its children, passing its calculated world matrix as the newparentsFrameMat.
- Calculates its own world matrix by multiplying
draw(parentsFrameMat):- Calculates the final model matrix (
frameMat) by multiplyingparentsFrameMatwith its localtransform.modelMat. - Sends this
frameMatto the vertex shader asuModelMat. - Binds and uploads its
_mergedVerticesand_mergedNormalsto WebGL buffers. - Calls
gl.drawArrays()to render its primitives.
- Calculates the final model matrix (
- Extends
HierarchyObjectto simplify the creation of complex, pre-defined objects. RobotArmuses itsinit()method to construct its internal hierarchy ofHierarchyObjects, each withBoxPrimitives and specificTransforms.
The rendering process is initiated and managed primarily by CanvasManager (via RootManager) and the HierarchyObject's recursive drawing mechanism.
-
Initialization (
main.html,RootManager):- WebGL context is obtained, shaders are compiled and linked.
- Buffer IDs for vertices and normals are created.
- The root
HierarchyObjectis established (managed byRootManager). - Prefab objects (like
RobotArm) are instantiated and added as children to the scene graph. Theirinit()methods build their internal structure.
-
Render Call (
canvasManager.render()):- This function typically clears the canvas.
- Sets up global rendering state (like view and projection matrices from
CameraManager, light properties). - Initiates the drawing process by calling
drawRecursively()on the rootHierarchyObjectof the scene, usually with an identity matrix as the initialparentsFrameMat.
-
Recursive Drawing (
HierarchyObject.drawRecursively()):- Calculate World Matrix: The current object computes its world transformation matrix (
frameMat) by premultiplying theparentsFrameMatwith its own localtransform.modelMat.frameMat = parentsFrameMat * this.transform.modelMat
- Draw Self: The object calls its own
draw(parentsFrameMat)method.- Inside
draw():- The final
frameMatis sent to the vertex shader (uModelMat). - Vertex and normal data for the current object's primitives are bound and uploaded to GPU buffers.
gl.drawArrays()is called to render the current object's geometry.
- The final
- Inside
- Draw Children: The object iterates through its
childrenand callsdrawRecursively()on each child, passing its own calculatedframeMatas theparentsFrameMatfor the child. This ensures transformations accumulate down the hierarchy.
- Calculate World Matrix: The current object computes its world transformation matrix (
-
Shader Execution (Vertex & Fragment Shaders):
- Vertex Shader:
- Receives vertex positions (
aVertexPosition) and normals (aVertexNormal). - Transforms vertices using
uProjectionMat * uViewMat * uModelMat * aVertexPosition. - Performs Blinn-Phong lighting calculations using transformed normals, light position, and material properties to determine
fColor.
- Receives vertex positions (
- Fragment Shader:
- Receives interpolated
fColorfrom the vertex shader. - Assigns
fColortogl_FragColor, determining the pixel's final color.
- Receives interpolated
- Vertex Shader:
graph TD
A[main.html / RootManager Initialization] --> B(Setup WebGL Canvas & Shaders);
B --> C{Create RobotArm Prefab};
C -- RobotArm.init() --> D[Builds Arm Hierarchy: HierarchyObject children with BoxPrimitives & Transforms];
A --> E(Setup UI Event Listeners for Camera/Light);
subgraph RenderLoop [Triggered by Initial Load or UI Change]
F[CanvasManager.render()] --> G[Set Global Uniforms: View, Projection, Light];
G --> H[rootObject.drawRecursively(IdentityMatrix)];
end
subgraph RecursiveDraw [HierarchyObject.drawRecursively(parentMatrix)]
I[Calculate currentWorldMatrix = parentMatrix * localTransform.modelMat] --> J[Self.draw(parentMatrix)];
J --> K[Send currentWorldMatrix to Shader as uModelMat];
K --> L[Bind & Buffer own Primitives' Vertices/Normals];
L --> M[gl.drawArrays()];
I --> N{For each ChildObject};
N -- Yes --> O[ChildObject.drawRecursively(currentWorldMatrix)];
N -- No --> P[End of this branch];
O --> RecursiveDraw;
end
M --> Q[Vertex Shader: Transform Vertices, Calculate Lighting];
Q --> R[Fragment Shader: Apply Color];
R --> S[Display on Canvas];
E -- User Interaction --> F;
- Ensure you have a local web server to serve the files (due to browser security restrictions with
file:///URLs for WebGL and shaders). - Place all provided JavaScript files (
primitive.js,transform.js,hierarchyObject.js,prefabObject.js,robotArm.js, and the assumed manager files) in the correctsrc/subdirectories as referenced inmain.html. - Place
webgl-utils.js,initShaders.js, andMV.jsinto aCommon/directory. - Open
main.htmlthrough your local web server.
- Animation System: Implement the
animationproperty inPrefabObjectand anAnimationManagerto allow for dynamic object movements. - Material System: Abstract material properties (ambient, diffuse, specular, shininess) into a separate component or class instead of being global.
- Texture Mapping: Add support for applying textures to objects.
- More Primitives: Introduce other basic shapes like spheres, cylinders, etc.
- Error Handling: More robust error checking, especially for WebGL calls and shader compilation.
- Optimizations: For very large scenes, consider techniques like frustum culling or instanced drawing.
- Input System: Refine mouse controls or add keyboard controls.
Explanation of the Mermaid Diagram:
- Initialization:
main.htmlandRootManagerset up the basics, including creating theRobotArmprefab which in turn builds its own internal hierarchy. UI listeners are also set up. - Render Loop: Triggered initially or by UI changes (like moving the camera/light).
CanvasManager.render()sets global shader uniforms and starts the recursive drawing from the root object. - RecursiveDraw (Subgraph): This is the core of the hierarchical rendering.
- A
HierarchyObjectreceives its parent's transformation matrix (parentMatrix). - It calculates its own
currentWorldMatrixby multiplying theparentMatrixwith its localtransform.modelMat. - It then calls its internal
draw()method (represented by steps J, K, L, M) to render its own geometry using thiscurrentWorldMatrix. - Crucially, it then iterates through its children and calls
drawRecursivelyon each child, passing down itscurrentWorldMatrixas theparentMatrixfor the child. This ensures transformations accumulate correctly.
- A
- Shader Processing: After
gl.drawArrays()is called for a set of primitives, the vertex shader processes each vertex (transforming it and calculating lighting), and then the fragment shader determines the final pixel color. - Display: The final image is shown on the canvas.
This README should give a good overview of your project's structure and functionality.