본문 바로가기

C++ & etc

Maxscript / DirectX Shader for 3dsMax

나중을 대비해서 자주 쓰이는 내용들만 정리해 둠.

 

Maxscript

장면 내의 특정 유형 오브젝트들을 array로 받기

ObjectSets 라고 한다.

https://help.autodesk.com/view/MAXDEV/2024/ENU/?guid=GUID-77CB1890-C949-43AC-B1E9-B37F97B6712D

  • objects  --all the objects
  • geometry  --the standard 3ds Max categories... 
  • lights
  • cameras
  • helpers
  • shapes
  • systems
  • spacewarps
  • selection  --the current selection

어떤 내장 함수들은 clearSelection() 동작을 내포하고 있기 때문에, selection 으로 선택된 오브젝트들을 받아오기 전,

미리 현재 selectionset을 저장해 두어야 한다. 방법은 아래 두 가지이다.

  1. selection as array 로 현재 선택된 오브젝트 목록을 array에 저장해 둔다.
  2. getCurrentSelection() 함수를 사용한다.

https://help.autodesk.com/view/MAXDEV/2024/ENU/?guid=GUID-99A90A15-04D5-4D53-B9F1-CE5C7E1C4D7D

 

 

오브젝트의 클래스 검사하기

isKindOf, ClassOf, SuperClassOf 명령어로 오브젝트의 클래스, 상위 클래스를 판별할 수 있다.

예를 들어, 아래 스크립트는 오브젝트 o가 지오메트리 유형이며, hide 되지 않았을 때만 수행된다.

if (isKindOf o GeometryClass) and (o.ishidden == false) then ( ... )

https://help.autodesk.com/view/MAXDEV/2024/ENU/?guid=GUID-0AEEF510-1859-48B7-9A19-A6158B0310A7

 

 

배열 관련 기능들

array에 대해 아래 기능들을 사용할 수 있다.

  • collect, append : array 에 새 오브젝트를 추가한다.

예를 들어, 아래 스크립트는 sphere 중 radius가 5 이하인 것들만 little_spheres 배열에 저장한다.

   -- collect all spheres with radius less than 5
   little_spheres =
   	for i in $* collect
   	if classOf i == sphere and i.radius < 5 then i else dontCollect
  • appendIfUnique : array 내에 같은 요소가 없을 경우만 추가한다.
  • join : array와 array를 결합할 때 사용한다.
  • insertItem : array의 특정 인덱스에 값을 추가한다. value, array, integer 순으로 입력한다.
  • findItem : array 안에서 특정 값의 인덱스를 얻는다. 찾았을 경우 해당 인덱스가, 찾을 수 없을 경우 0이 반환된다.
  • deleteItem : 특정 인덱스의 값을 array로부터 지운다.
  • 기타 : in / by 키워드로 배열 내의 각 item들을 인자로 받거나, 특정 개수만큼 뛰어넘을 수 있다.

 

polyop 버텍스 관련 기능들

메시 내부의 버텍스 정보를 얻거나, 새로운 정보를 기록할 수 있다.

  • polyop.getNumVerts : 지오메트리 내부의 버텍스 갯수를 얻는다.

예를 들어, 아래 스크립트는 지오메트리 o 의 모든 버텍스에 대해 수행된다.

		for i = 1 to polyop.getNumVerts o do
		( ... )
  • polyop.getVert : 버텍스의 position을 얻는다. 오브젝트, 인덱스 순으로 입력한다.
  • polyop.setMapVert : 해당 버텍스의 map channel 데이터를 지정해 준다.

셋팅해 주기 전, polyop.setMapSupport 로 해당 채널을 활성화 해 주어야 한다.

(오브젝트, 채널 인덱스, true / false 순으로 입력한다.

예를 들어, 아래 스크립트는 오브젝트의 채널 0번 사용을성화 한다.

polyop.setMapSupport o 0 true

참고로, 3dsMax에서 맵 채널은 UV 채널 이외에도 버텍스 컬러에도 맵핑되어 있다. 내용은 아래와 같다.

  • Channel -2 : 버텍스 컬러 알파채널 값 (point3 유형)
  • Channel -1 : 버텍스 컬러 R, G, B 채널 값
  • Channel 1 ~ : 일반 UV 채널 값 (point 3 유형)

https://help.autodesk.com/view/MAXDEV/2024/ENU/?guid=mapping_channels

 

Direct X Shader (HLSL)

.fx 파일의 기본 구조

cbuffer CBufferPerObject
{
     float4x4 WorldViewProjection : WORLDVIEWPROJECTION;
}

RasterizerState DisableCulling
{
     CullMode = NONE;
};

struct VS_INPUT
{
     float4 ObjectPosition: POSITION;
};

struct VS_OUTPUT
{
     float4 Position: SV_Position;
};

VS_OUTPUT vertex_shader(VS_INPUT IN)
{
     VS_OUTPUT OUT = (VS_OUTPUT)0;
     OUT.Position = mul(IN.ObjectPosition, WorldViewProjection);
     return OUT;
}

float4 pixel_shader(VS_OUTPUT IN) : SV_Target
{
     return float4(1, 0, 0, 1);
}

technique11 main11
{
     pass p0
     {
     SetVertexShader( CompileShader(vs_4_0, vertex_shader()));
     SetGeometryShader( NULL);
     SetPixelShader( CompileShader(ps_4_0, pixel_shader()));
     SetRasterizerState(DisableCulling);
     }
}

아래 링크 (Real-Time 3D Rendering with DirectX® and HLSL)의 예제 코드를 참고하였다.

https://ptgmedia.pearsoncmg.com/images/9780321962720/samplepages/0321962729.pdf

 

 

버텍스 Map Channel 정보 버텍스 셰이더로 넘겨주기

버텍스 정보를 버텍스 셰이더로 넘겨주려면, 아래와 같이 맵 채널과 texcoord를 맵핑해 주어야 한다.

아래 코드는 맵채널 1번 (주로 텍스처 맵핑에 사용)과, 버텍스 구조체의 TEXCOORD0번을 연결해 준다.

int texcoord0 : Texcoord
<
	int Texcoord = 0;
	int MapChannel = 1;
	string UIWidget = "None";
> ;

TEXCOORD0 위치에 uv채널 1번 데이터가 들어간다.

.fx 파일 진입지점 알려주기

아래 코드는 셰이더 파일의 각 렌더링 파이프라인을 구성하는 부분이다.

하나의 fx 파일에서 여러 단계의 패스를 수행사도록 구성할 수도 있다.

technique11 myTechnique

{

  pass FirstPass

  {

      SetVertexShader(CompileShader(vs_5_0, mainVS()));

      SetPixelShader(CompileShader(ps_5_0, mainPS()));

      SetGeometryShader(NULL);

  }

}

추가적으로 BlendState, DepthStencilState, RasterizerState 등을 생성해서 지정해 줄 수도 있다.

아래는 투명한 셰이더에 대해 블렌딩을 활성화 할 수 있는 코드이다.

BlendState BlendStateTransparent
{
	BlendEnable[0] = TRUE;
	SrcBlend = SRC_ALPHA;
	DestBlend = INV_SRC_ALPHA;
};