Уроки, алгоритмы, программы, примеры

Вход на сайт

Материалы по разделам

Построения
на плоскости (2D)
Графика
в пространстве (3D)
Вычислительная
геометрия
Физическое
моделирование
Фрактальная
графика

Новые комментарии

Всем у кого не работает. файл wizard.script Ещё одно упоминание Glut32 в строке "if (!VerifyLibFile(dir_nomacro_lib, _T("glut32"), _T("GLUT's"))) return false;" меняем на "if (!VerifyLibFile(dir_nomacro_lib, _T("freeglut"), _T("GLUT's"))) return...
Не получается, емаё
огромное спасибо за подробное объяснение про 3д графику на питоне, в интернете очень мало подобной информации
dobryj den, popytalas otkryt prikreplionnyj fail ctoby posmotret kak rabotaet, no mne ego ne pokazyvaet vydajet osibku. Pochemu?
Очень интересно! ии сайт крутой жалко что умирает(

Счетчики и рейтинг

Рейтинг@Mail.ru Яндекс.Метрика
Скриншот к примеру
Среда программирования: 
Linux QT Creator
Статья по теме: 

Пример для шума перлина, кода довольно много, но он хорошо раскомментирован.
Весь шум перлина отделен в отдельный класс - можете использовать по своему усмотрению.

Запуск: выкидываете ехе-фаил в любое удобное место и кладете рядом SDL.dll, должно работать.

Интерфейс: Окно с сами шумом. Вводите 3 коэффициента через пробел и получаете отрисовку шума.

Управление: консоль

Код программы: 

Конструктор класса для шума

//PN.H BEGIN
#ifndef PN_H
#define PN_H
#include <vector>
class PN {
    // Вектор значений
    std::vector<int> p;
public:
    // Инициализируем значения вектора
    PN();
    // Генерирует новый вектор из зерна
    PN(unsigned int PSeed);
    // Получаем 2D шум, z может принимать любое значение
    double PNoise(double x, double y, double z);
private:
    double FadeOut(double t);
    double LinearInterpolation(double t, double a, double b);
    double Gradient(int hash, double x, double y, double z);
};
 
#endif 
// PN.H END

сам шум:

//PN.CPP BEGIN
#include "PN.h"
#include <algorithm>
#include <numeric>
#include <random>
 
PN::PN() {
 
    // Инициализируем вектор псевдослучайных чисел
    p = {
        151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,
        8,99,37,240,21,10,23,190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,
        35,11,32,57,177,33,88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,
        134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,
        55,46,245,40,244,102,143,54, 65,25,63,161,1,216,80,73,209,76,132,187,208, 89,
        18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,
        250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,
        189,28,42,223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167,
        43,172,9,129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,
        97,228,251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,
        107,49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
        138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 };
    p.insert(p.end(), p.begin(), p.end());
}
 
// Генерируем новый вектор из зерна (рандомное число = рандомный вектор)
PN::PN(unsigned int PSeed) {
    p.resize(256); //сжимаем вектор до 256 значений
 
    // Заполним р значениями от 0 до 255
    std::iota(p.begin(), p.end(), 0);
 
    // Инициализируем рандомные значения зерном
    std::default_random_engine engine(PSeed);
 
    // Перемешиваем значения вектора
    std::shuffle(p.begin(), p.end(), engine);
 
    // И вставим
    p.insert(p.end(), p.begin(), p.end());
}
 
double PN::PNoise(double x, double y, double z) {
    // Находим куб содержащий данную точку
    int X = (int) floor(x) & 255;
    int Y = (int) floor(y) & 255;
    int Z = (int) floor(z) & 255;
 
    // Находим значение x, y, z после запятой
    x -= floor(x);
    y -= floor(y);
    z -= floor(z);
 
    // Вычисляем кривую по значения переменных
    double u = FadeOut(x);
    double v = FadeOut(y);
    double w = FadeOut(z);
 
    // Получаем 8 векторов из углов куба
    int A = p[X] + Y;
    int AA = p[A] + Z;
    int AB = p[A + 1] + Z;
    int B = p[X + 1] + Y;
    int BA = p[B] + Z;
    int BB = p[B + 1] + Z;
    double res = LinearInterpolation(w, LinearInterpolation(v, LinearInterpolation(u, Gradient(p[AA], x, y, z), Gradient(p[BA], x-1, y, z)), LinearInterpolation(u, Gradient(p[AB], x, y-1, z), Gradient(p[BB], x-1, y-1, z))),	LinearInterpolation(v, LinearInterpolation(u, Gradient(p[AA+1], x, y, z-1), Gradient(p[BA+1], x-1, y, z-1)), LinearInterpolation(u, Gradient(p[AB+1], x, y-1, z-1),	Gradient(p[BB+1], x-1, y-1, z-1))));
    return (res + 1.0)/2.0;
}
 
double PN::FadeOut(double t) {
    return t * t * t * (t * (t * 6 - 15) + 10);
}
 
double PN::LinearInterpolation(double t, double a, double b) {
    return a + t * (b - a);
}
 
double PN::Gradient(int hash, double x, double y, double z) {
    int h = hash & 15;
    // Конвертирует 4 нижних значения векторов в 12 градиентных
    double u = h < 8 ? x : y,
           v = h < 4 ? y : h == 12 || h == 14 ? x : z;
    return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
}
// PN.CPP END

Графическая обертка (SDL2):
//main.cpp BEGIN
#include "PN.h"
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <random>
#include <SDL.h>
#undef main
 
#define TEST 400
 
using namespace std;
 
void SetPixel(SDL_Surface* surface, int x, int y, Uint32 pixel) //функция установки пикселя на поверхность, принимает название поверхности, координаты х и у, и цвет в формате uint32
{
    Uint32 *p = (Uint32 *) surface->pixels + y*surface->w+x;
    *p = pixel;
}
 
int main()
{
    unsigned int width=TEST, height=TEST; //размеры нашего окна
 
    SDL_Window *window= NULL; //пустое окно
    SDL_Renderer *renderer = NULL; //пустой рендерер
    SDL_Surface *image = NULL; //пустая поверхность
    SDL_Texture *imageTexture = NULL; //пустая текстура
 
    if(SDL_Init(SDL_INIT_VIDEO)<0)
	{ 
		//инициализируем видеодрайвер или выкидываем ошибку
        cout<<"Ошибка инициализации видео"<<endl;
        return 1;
    }
 
    window = SDL_CreateWindow("Perlin", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, 0); //создаем окно с ранее заданными размерами по центру или кидаем ошибку
    if(!window) 
	{
        cout<<"SDL не создало окно"<<endl;
        return 2;
    }
 
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE); //создаем рендерер для нашего окна или кидаем ошибку
    if(!renderer) 
	{
        cout<<"SDL не получила доступа к рендереру"<<endl;
        return 3;
    }
 
    Uint32 rmask, gmask, bmask, amask; //создаем пиксель с цветами в формате RGBA
    #if SDL_BYTEORDER == SDL_BIG_ENDIAN //здесь описывается маска пикселей для разных архитектур
        rmask = 0xff000000;
        gmask = 0x00ff0000;
        bmask = 0x0000ff00;
        amask = 0x000000ff;
    #else
        rmask = 0x000000ff;
        gmask = 0x0000ff00;
        bmask = 0x00ff0000;
        amask = 0xff000000;
    #endif
 
    image = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32, rmask, gmask, bmask,amask); //создаем поверхность под наши пиксели
    if(!image) 
	{
        cout << "Все плохо с поверхностью :(" <<endl;
        return 4;
    }
    unsigned int PSeed=0; //зернышко для рандома
 
    Uint8 colourByte; //упрощаем пиксель до uint (у нас же ЧБ изображение)
    bool quit = false; //бул для выхода
    SDL_Event event; //событие для обработки нажатий
 
    PN pn(PSeed); //создаем объект шума Перлина по зерну
    int ax=0, ay=0, e=0; //начальные значения для формулы шума
	while (!quit)
	{ //пока не ESC или не закрыли окно
 
		for (unsigned int i = 0; i < height; ++i) //циклом высчитываем шум и заполняем поверхность
			for (unsigned int j = 0; j < width; ++j)
			{
				double x = (double)j / ((double)width);
				double y = (double)i / ((double)height);
				double n = pn.PNoise(ax*x, ay*y, e);
				colourByte = Uint8(n * 0xff);
				SetPixel(image, j, i, SDL_MapRGB(image->format, colourByte, colourByte, colourByte));
			}
		SDL_RenderClear(renderer); //очищаем буфер рендерера и пихаем в него новую текстуру
		imageTexture = SDL_CreateTextureFromSurface(renderer, image); //создаем изображение (которое пойдет на экран)
		SDL_RenderCopy(renderer, imageTexture, NULL, NULL);
		SDL_RenderPresent(renderer); //проверяем все ли хорошо
 
		if (!imageTexture)
		{
			cout << "Не создалась поверхность из текстуры" << endl;
			return 5;
		}
 
		cout << " ax: " << ax << " ay: " << ay << " e: " << e << endl; //выводим в консоль текущие коэффициенты
		cout << "New ax, ay, e (spaced): ";
		cin >> ax >> ay >> e;
 
		//этот участок кода скорее всего не понадобится,
		//поскольку выход можно выполнить просто закрыв консоль
		//да и окно отвечать не будет, но пусть
		while (SDL_PollEvent(&event)) { //ждем дальнейших указаний:
			switch (event.type)
			{
			case SDL_QUIT: //закрыли окно -> выход
				quit = true;
				break;
			}
		}
	}
	//выход:
    SDL_FreeSurface(image); //очищаем поверхность
    SDL_DestroyTexture(imageTexture); //уничтожаем текстуру
    SDL_DestroyRenderer(renderer); //и рендерер
    SDL_DestroyWindow(window); // и окно
    SDL_Quit(); //выключаем библиотеку SDL
    return 0; //выход из программы
}
//main.cpp END

Прикрепленный файлРазмер
Perlin_noise.zip692.48 кб