장면에 광선 추가 - 법선 정의 및 BasicEffect 사용

8472 단어
문제.
정확한 빛이 비치지 않으면 장면은 진실감이 부족할 것이다.일부 경우 조명이 제대로 비치지 않으면 3D 효과가 완전히 사라집니다.
예를 들어 불투명한 색깔의 공이 빛이 비치지 않으면 공의 모든 픽셀은 같은 색깔로 화면에서 평면의 접시처럼 보일 것이다.빛이 올바르게 비추면 구 위의 빛이 비치는 부분이 다른 부분의 색보다 더 밝아서 구가 실제 3D 객체로 보입니다.
솔루션
컴퓨터 그래픽스에서 모든 3D 객체는 삼각형으로 구성됩니다.너는 삼각형이 입사광에 맞게 정확하게 밝게 비추기를 원한다.그림6-1은 왼쪽에서 오른쪽으로 향하는 일방적인 빛을 보여 주는데 한 직사각형의 6개의 다른 위치에 영향을 주고 각 직사각형은 두 개의 삼각형으로 구성되어 있다.
그림6-1 입사광의 삼각형 조명 상황에 따라
라이트의 위치와 객체의 위치를 간단하게 정의하면 그래픽이 객체에 올바른 조명을 추가할 수 없습니다.3D 객체의 모든 삼각형에 대해 정보를 추가해야 합니다. 그래픽카드는 표면을 비추는 빛의 강도를 계산할 수 있습니다.
이렇게 하면 각 교점의 법선 벡터를 지정하여 그림6-1에서 삼각형 교점의 선분으로 법선을 표시할 수 있습니다.각 정점에 정확한 법선이 정의되면 BasicEffect는 정확한 조명으로 대상을 그릴 수 있습니다.
작업 원리
그림6-1에서 입사광의 강도를 나타내는 사각형을 그렸다.직사각형이 입사광 방향에 수직일수록 더 많은 빛을 받아들인다.마지막 사각형은 광선 방향에 수직으로 완전히 비친다.첫 번째 사각형은 빛에 평행하기 때문에 빛을 받지 않는다.
법선 정의
그렇다면 카드는 어떻게 관련 정보를 알 수 있을까?삼각형의 각 정점에서 삼각형에 수직으로 있는 방향을 정의할 것이다.이 방향을 법선이라고 한다.수직 방향은 그림 6-1에서 삼각형 교점을 확장하는 선분으로 표시됩니다.평면에 수직인 방향은 고유하므로 사각형의 모든 교점은 같은 법선 방향을 가집니다.
법선 방향은 카드로 하여금 삼각형에서 얻은 빛을 계산할 수 있게 한다.교정6-5에서 말한 바와 같이 법선을 빛 방향에 투영할 수 있다. 그림6-2와 같다.빛의 방향은 그림 밑에 있는 긴 화살표로 왼쪽에서 오른쪽을 가리킨다.그림 6-2에서 회전하는 검은색 막대는 그림 6-1의 사각형을 나타냅니다.법선의 광선 방향 투영은 광선 화살표의 굵은 검은색 블록으로 검은색 블록이 클수록 삼각형이 더 많은 빛을 얻는다는 것을 나타낸다.
그림 6-2 수직을 광선 방향으로 투영합니다.
그림에서 왼쪽의 삼각형의 법선은 빛 방향에 수직이기 때문에 투영은 0이고 삼각형은 빛을 받지 않는다.오른쪽 삼각형의 법선은 빛의 방향에 평행하고 투영이 가장 크며 완전히 밝아진다.
광선과 법선을 주어 카드는 투영 길이를 쉽게 계산할 수 있다.이것이 바로 카드가 빛을 정확하게 계산하는 방법이다.
장면에 광선 적용
비디오 카드는 각 정점의 빛의 강도를 계산한 다음 이 값에 픽셀의 초기 색을 곱합니다.
정점에 법선 데이터 추가
앞의 단락에서는 3D 위치와 색상 외에 각 교점마다 법선 방향을 저장해야 한다고 설명합니다.
XNA는 각 정점에 법선을 저장할 수 있는 미리 정의된 정점 형식을 가지고 있습니다: VertexPositionNormalTexture 구조.이 형식은 각 정점에 3D 위치, 법선 방향과 무늬 좌표를 저장할 수 있게 한다.강좌 5-2에서 무늬가 있는 삼각형을 배울 수 있고, 강좌 5-12에서 정점 형식을 어떻게 사용자 정의하는지 배울 수 있다.
다음 방법은 6개의 정점을 가진 그룹을 만들고 두 삼각형이 하나의 직사각형을 형성하는 것을 정의한다.이 직사각형은 바닥에 평평하게 누워 있기 때문에 모든 Y 좌표는 0이다.따라서 수직선의 방향은 직사각형에 수직인 방향(0,1,0) Up 방향입니다.정점 형식에는 무늬 좌표가 있어야 카드가 이미지에서 색깔을 어떻게 샘플링하는지 알 수 있다(교정5-2 참조).
private void InitVertices() 
{
    vertices = new VertexPositionNormalTexture[6]; 
    int i = 0; 
    vertices[i++] = new VertexPositionNormalTexture(new Vector3(-1, 0, 1), new Vector3(0, 1, 0), new Vector2(1,1)); 
    vertices[i++] = new VertexPositionNormalTexture(new Vector3(-1, 0, -1), new Vector3(0, 1, 0), new Vector2(0,1)); 
    vertices[i++] = new VertexPositionNormalTexture(new Vector3(1, 0, -1), new Vector3(0, 1, 0), new Vector2(0,0));
    vertices[i++] = new VertexPositionNormalTexture(new Vector3(1, 0, -1), new Vector3(0, 1, 0), new Vector2(0,0)); 
    vertices[i++] = new VertexPositionNormalTexture(new Vector3(1, 0, 1), new Vector3(0, 1, 0), new Vector2(1,0));
    vertices[i++] = new VertexPositionNormalTexture(new Vector3(-1, 0, 1), new Vector3(0, 1, 0), new Vector2(1,1)); 
    
    myVertexDeclaration = new VertexDeclaration(device, VertexPositionNormalTexture.VertexElements); 
} 

마지막 줄 코드는 VertexDeclaration (튜토리얼 5-1 참조) 을 한 번만 만들 수 있도록 합니다. 변경할 필요가 없기 때문입니다.
기교: 삼각형이 바닥에 평평하게 깔려 있으면 법선을 계산하기 쉽다.복잡한 대상을 위한 자동 계산 법선을 배울 수 있는 강좌 5-7에 참가할 수 있다.
정법선과 음법선
하나의 삼각형은 사실 두 개의 수직 방향이 있다.만약 앞의 코드 삼각형이 땅 위에 있다면, 위나 아래를 가리키는 법선을 정의할 수 있다.그럼 어떤 걸 써야 돼요?잘못된 방향을 선택하면 잘못된 빛이 생기기 때문에 보통 빛을 받지 않기 때문이다.
원칙은 대상 외부를 가리키는 법선을 선택해야 한다는 것이다.
일반적으로 삼각형의 한 면은 3D 물체의'안쪽'으로 볼 수 있고 다른 한 면은'바깥쪽'으로 볼 수 있다.이런 상황에서 물체 외부를 가리키는 법선을 선택하고 싶다.
BasicEffect 매개 변수 설정
정점을 정의한 후 삼각형을 그릴 수 있다.이 장의 두 번째 부분에서는 HLSL effects를 어떻게 작성하는지 설명하지만, 첫 번째 강좌는 BasicEffect만 사용합니다.BasicEffect는 기본 조명 효과를 사용하는 물체를 그릴 수 있도록 미리 정의된 effect입니다.프레임마다 새 BasicEffect 대상을 만드는 데 자원을 너무 많이 소모하기 때문에 BasicEffect 변수를 확보하십시오.클래스 상단에 이 변수를 추가하려면 다음과 같이 하십시오.
BasicEffect BasicEffect basicEffect; 

LoadContent 메서드에서 basicEffect를 인스턴스화합니다.
basicEffect = new BasicEffect(device, null);

다음 설정은 태양과 같은 단방향 광원에서 3D 장면의 빛을 그립니다.
basicEffect.World = Matrix.Identity;
basicEffect.View = fpsCam.ViewMatrix; 
basicEffect.Projection = fpsCam.ProjectionMatrix; 
basicEffect.Texture = myTexture; 
basicEffect.TextureEnabled = true; 

basicEffect.LightingEnabled = true; 
basicEffect.AmbientLightColor = new Vector3(0.1f, 0.1f, 0.1f); 
basicEffect.PreferPerPixelLighting = true;
 
basicEffect.DirectionalLight0.Direction = new Vector3(1, -1, 0); 
basicEffect.DirectionalLight0.DiffuseColor = Color.White.ToVector3(); 
basicEffect.DirectionalLight0.Enabled = true; 
basicEffect.DirectionalLight1.Enabled = false; 
basicEffect.DirectionalLight2.Enabled = false; 

코드의 첫 번째 부분은 World, View와 Projection 행렬을 설정하여 3D 장면을 2D 화면으로 전환하는데 구체적인 지식은 교과서 2-1과 4-2를 참조할 수 있다.각 정점에 무늬 좌표를 저장하기 때문에 한 장의 무늬를 카드에 전달하고 열어야 한다. 무늬에 대한 지식은 교과서 5-2를 참조한다.
이어서 조명을 설치한다.먼저 빛을 켜고 환경 빛의 색을 정의합니다. 이 색은 대상이 빛의 방향에 상관없이 항상 받는 색입니다.빛이 없어도 물체가 은은하게 보일 수 있도록 어두운 회색을 정의했다.
만약 비디오 카드가 픽셀마다 비치는 빛을 처리할 수 있다면, 너는 그것을 켜서 튜토리얼 6-3에 참가할 수 있다.
마지막으로 라이트를 정의합니다.BasicEffect를 사용할 때 한 번에 세 개의 광원을 사용할 수 있습니다.너는 광원의 방향과 색깔을 설정하고 광원을 켜야 한다.이 예에서는 하나의 광원만 사용합니다.
BasicEffect를 설정하면 BasicEffect를 사용하여 삼각형을 그릴 수 있습니다.
basicEffect.Begin(); 
foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes) 
{
    pass.Begin(); 
    device.VertexDeclaration = myVertexDeclaration; 
    DrawUserPrimitives (PrimitiveType.TriangleList, vertices, 0, 2); 
    pass.End(); 
}
basicEffect.End(); 

주의: 만약 당신이basicEffect를 통과한다면.LightingEnabled 를 false 로 설정하면 라이트가 꺼지고 장면이 전체 빛의 강도로 그려집니다.앞에서 설명한 대로 그래픽 카드는 각 픽셀의 초기 색상에 조명 강도를 곱합니다.조명을 끄면 그래픽 카드는 각 픽셀의 초기 색상을 간단하게 그립니다.실제로lighting factor가 1인 경우엔 모든 빛이 강하다는 뜻이다.
세계 매트릭스 사용
삼각형을 그리기 전에 effect의 세계 행렬을 설정할 수 있습니다.이렇게 하면 삼각형을 다른 위치로 이동하거나 축소해서 회전시킬 수 있다. (교과서 4-2 참조)좋은 effects (예: BasicEffect) 를 구축하여 이 변환을 정점의 법선 데이터에 적용합니다.예를 들어 앞 코드의 직사각형이 회전하면 법선도 함께 회전한다.
아래의 코드는 이러한 예를 보여 준다.
귀일화 법선
주의: 이 절을 읽을 때normal(법선)과normalize(귀일화)의 차이를 알아야 합니다.법선은 삼각형에 수직인 방향이다.귀일화는 벡터의 길이를 단위로 하는 길이를 의미하며, 귀일화는 벡터의 길이를 1로 줄이는 것을 의미한다.
빛의 강도는 빛과 법선 사이의 협각에 의해 결정되어야 한다.그러나 그래픽 카드의 계산 결과는 두 가지 길이에 달려 있다.따라서 법선 방향과 광선 방향의 길이가 모두 1인 것을 확보해야 한다. 이것은 귀일화를 통해 실현될 수 있다.
둘 다 단위 길이일 때, 빛의 강도는 둘 사이의 협각에만 달려 있다. 이것이 바로 네가 원하는 결과이다.
코드
먼저 각 정점에 대한 법선 데이터를 제공해야 합니다.
private void InitVertices() 
{
    vertices = new VertexPositionNormalTexture[6]; 
    
    int i = 0; 
    vertices[i++] = new VertexPositionNormalTexture(new Vector3(-1, 0, 1), new Vector3(0, 1, 0), new Vector2(1,1));
    vertices[i++] = new VertexPositionNormalTexture(new Vector3(-1, 0, -1), new Vector3(0, 1, 0), new Vector2(0,1));
    vertices[i++] = new VertexPositionNormalTexture(new Vector3(1, 0, -1), new Vector3(0, 1, 0), new Vector2(0,0)); 
    vertices[i++] = new VertexPositionNormalTexture(new Vector3(1, 0, -1), new Vector3(0, 1, 0), new Vector2(0,0)); 
    vertices[i++] = new VertexPositionNormalTexture(new Vector3(1, 0, 1), new Vector3(0, 1, 0), new Vector2(1,0));
    vertices[i++] = new VertexPositionNormalTexture(new Vector3(-1, 0, 1), new Vector3(0, 1, 0), new Vector2(1,1));
    
    myVertexDeclaration = new VertexDeclaration(device, VertexPositionNormalTexture.VertexElements);
} 

BasicEffect를 사용하여 삼각형을 그리기 전에 매개변수를 설정하여 조명 환경을 정의해야 합니다.
basicEffect.View = fpsCam.ViewMatrix; 
basicEffect.Projection = fpsCam.ProjectionMatrix; 
basicEffect.Texture = myTexture; 
basicEffect.TextureEnabled = true;
 
basicEffect.LightingEnabled = true; 
basicEffect.DirectionalLight0.Direction = new Vector3(1, 0, 0); 
basicEffect.DirectionalLight0.DiffuseColor = Color.White.ToVector3(); 
basicEffect.DirectionalLight0.Enabled = true;

마지막으로 삼각형을 그립니다.다음 코드는 같은 삼각형 두 개를 아홉 번 그렸고 매번 다른 세계 행렬을 사용했다.세계 행렬은 먼저 삼각형을 선택한 다음에 그것을 x축을 따라 네 단위로 이동시킨다. (교과서 5-2 학습 행렬 곱셈의 순서 참조)
for (int i = 0; i < 9; i++)
{
    basicEffect.World = Matrix.CreateTranslation(4, 0, 0) * Matrix.CreateRotationZ((float)i * MathHelper.PiOver2 / 8.0f); 
    
    basicEffect.Begin(); 
    foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes) 
    {
        pass.Begin(); 
        device.VertexDeclaration = myVertexDeclaration; 
        device.DrawUserPrimitives (PrimitiveType.TriangleList, vertices, 0, 2); 
        pass.End(); 
    }
    basicEffect.End(); 
} 

강좌 5-1을 참고하여 삼각형을 어떻게 그리는지 배울 수 있다.
전재 대상:https://www.cnblogs.com/AlexCheng/archive/2011/02/14/2120102.html

좋은 웹페이지 즐겨찾기