Heart

26 Dec 2014

利用 Computer Graphics 技术绘制的第一张渲染图:

1

实现使用了 GDI+ 的 bitmap 进行绘制,参照了 Milo 在知乎的回答

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Header.h

#pragma once

// Exclude rarely-used stuff from Windows headers
#define WIN32_LEAN_AND_MEAN  
// Windows Header Files:
#include <windows.h>

// C RunTime Header Files
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>

// Source.cpp
#include "Header.h"
#include <ObjIdl.h>
#include <gdiplus.h>
#include <math.h>

using namespace Gdiplus;
#pragma comment (lib, "Gdiplus.lib")

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

float f(float x, float y, float z) {
	float a = x * x + 9.0f / 4.0f * y * y + z * z - 1;
	return a * a * a - x * x * z * z * z - 9.0f / 80.0f * y * y * z * z * z;
}

float h(float x, float z) {
	for (float y = 1.0f; y >= 0.0f; y -= 0.001f)
		if (f(x, y, z) <= 0.0f)
			return y;
	return 0.0f;
}

VOID OnPaint(HDC hdc)
{
	Graphics graphics(hdc);
	Bitmap *bitmap = new Bitmap(512, 512);
	INT width = 512;
	INT height = 512;
	Color color;

	for (INT sy = 0; sy < height; ++sy)
	{
		float z = 1.5f - sy * 3.0f / height;
		for (INT sx = 0; sx < width; ++sx)
		{
			float x = sx * 3.0f / width - 1.5f;
			float v = f(x, 0.0f, z);
			int r = 0;
			if (v <= 0.0f) {
				float y0 = h(x, z);
				float ny = 0.001f;
				float nx = h(x + ny, z) - y0;
				float nz = h(x, z + ny) - y0;
				float nd = 1.0f / sqrtf(nx * nx + ny * ny + nz * nz);
				float d = (nx + ny - nz) / sqrtf(3) * nd * 0.5f + 0.5f;
				r = (int)(d * 255.0f);
			}
			color.SetValue(Color::MakeARGB(
				(BYTE)(255),
				(BYTE)(r),
				(BYTE)(0),
				(BYTE)(0)
				));
			bitmap->SetPixel(sx, sy, color);
		}
	}

	graphics.DrawImage(bitmap, 0, 0, 512, 512);

	delete bitmap;
}

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, INT iCmdShow)
{
	HWND hwnd;
	MSG msg;
	WNDCLASS wndClass;
	GdiplusStartupInput gdiInput;
	ULONG_PTR gdiToken;

	// Initial GDI+
	GdiplusStartup(&gdiToken, &gdiInput, NULL);

	wndClass.style = CS_HREDRAW | CS_VREDRAW;
	wndClass.lpfnWndProc = WndProc;
	wndClass.cbClsExtra = 0;
	wndClass.cbWndExtra = 0;
	wndClass.hInstance = hInstance;
	wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndClass.lpszMenuName = NULL;
	wndClass.lpszClassName = TEXT("Heart!");

	RegisterClass(&wndClass);

	hwnd = CreateWindow(
		TEXT("Heart!"),   // window class name
		TEXT("Heart!"),  // window caption
		WS_OVERLAPPEDWINDOW,      // window style
		CW_USEDEFAULT,            // initial x position
		CW_USEDEFAULT,            // initial y position
		//CW_USEDEFAULT,            // initial x size
		512,
		//CW_USEDEFAULT,            // initial y size
		512,
		NULL,                     // parent window handle
		NULL,                     // window menu handle
		hInstance,                // program instance handle
		NULL);                    // creation parameters

	ShowWindow(hwnd, iCmdShow);
	UpdateWindow(hwnd);

	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	GdiplusShutdown(gdiToken);
	return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
	HDC hdc;
	PAINTSTRUCT ps;

	switch (msg)
	{
	case WM_PAINT:
		hdc = BeginPaint(hwnd, &ps);
		OnPaint(hdc);
		EndPaint(hwnd, &ps);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;

	default:
		return DefWindowProc(hwnd, msg, wp, lp);
	}
}

图形学学得不多,做了一点小改进,利用了 FSAA(Full Screen Anti-Aliasing) 中的 SSAA(Super Sampling Anti-Aliasing)。

简单的做法就是,渲染更大分辨率(1024x1024)的图片,然后缩放,效果图如下 :

2

当然,这样的结果是运算时间多了4倍,很多时候这是不可接受的,所以需要 MSAA/CSAA/CFAA 等不同的抗锯齿方法。

下一步就是学习图形学理论,以及各种实际应用方法。

© 2014 plinx